Crossplaneで自らが動作するGKE Clusterを作成・運用する方法
内容
本記事では、Crossplaneが動作するGKEクラスターを作成します。
また、そのGKEクラスター自身もGKEクラスター上で動作するCrossplaneで運用し、 Crossplaneが動作するKubernetesクラスターをそのCrossplane自身で管理する構成
を作成していきます。
詳細
CrossplaneはKubernetes上で動作するアプリケーションのため、GKEクラスターを作成するためには、そもそもCrossplaneが動作するKubernetesクラスターが必要です。しかし、そのKubernetesクラスターを作成するためにはCrossplaneが必要です。この 卵が先か鶏が先か問題
を解決するために、以下のフローでCrossplaneが動作するGKEクラスターを作成します。
- kindを使って、Crossplaneが動作するローカルkubernetesクラスターを作成する
- そのローカルクラスターから、CrossplaneでGKEを作成する
- そのGKEに対して再度Crossplaneをinstallし、ローカルクラスターに適用したmanifestファイルをGKEにも適用する
- kindクラスターを削除する
- CrossplaneのdeletionPolicyにOrphanを指定しておくことで、kindクラスターで作成したGKEクラスターを削除せずkindクラスターのみを削除し、GKEクラスターで動作するCrossplaneに自分自身が動くGKEクラスターの管理を委譲することが出来ます
ローカル環境構築
まずはkindを使って、ローカル環境でKubernetesクラスターを作成し、Crossplaneを動作させます。(minikube等でも大丈夫です。)
Kindを使ってローカルkubernetesクラスターを作成する
$ kind create cluster --name crossplane-local
Creating cluster "crossplane-local" ...
✓ Ensuring node image (kindest/node:v1.25.3) 🖼
✓ Preparing nodes 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
Set kubectl context to "kind-crossplane-local"
You can now use your cluster with:
kubectl cluster-info --context kind-crossplane-local
Have a nice day! 👋
install Crossplane
helmを使って、Crossplaneをinstallします。
$ kubectl create namespace crossplane-system
$ helm repo add crossplane-stable https://charts.crossplane.io/stable
$ helm repo update
$ helm install crossplane --namespace crossplane-system crossplane-stable/crossplane
install CLI
crossplane CLIがローカルにinstallされていない場合は、installします。
$ curl -sL https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh | sh
これで、ローカルKubernetesクラスターでCrossplaneを動作させる準備が整いました。
GCP Providerをセットアップする
まずは、ローカルのKubernetesクラスターでCrossplaneからGCPのリソースを操作できるようにするために、GCP ProviderをCrossplaneに導入します。
Service Accountを作成する
Crossplane用のGCP Service Accountを作成します。
GCPの管理画面から、
- Compute Network Admin
- Kubernetes Engine Admin
- Service Account User
の権限をもったServiceAccountを作成してください。
Service AccountのKeyをKubernetesのSecretに登録します。
先ほど作成したServiceAccountのkeyを発行し、base64加工してKubernetes Secretに登録します。
$ gcloud iam service-accounts keys create credentials.json --iam-account="${SERVICE_ACCOUNT}@${PROJECT_ID}.iam.gserviceaccount.com" --project $PROJECT_ID
$ GCP_CREDS=$(base64 credentials.json | tr -d "\n")
secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: gcp-credential
namespace: crossplane-system
type: Opaque
data:
creds: $GCP_CREDS
※githubで管理する場合は、Sealed Secret等を使ってください
$ kubectl apply -f secret.yaml
...
$ kubectl get secret -n crossplane-system
NAME TYPE DATA AGE
gcp-credential Opaque 1 19h
sh.helm.release.v1.crossplane.v1 helm.sh/release.v1 1 19h
GCP ProviderをKubernetesにapplyする
最後に、GCP ProviderをKubernetesにapplyします。
gcp-provider.yaml
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-gcp
spec:
package: crossplane/provider-gcp:v0.21.0
---
apiVersion: gcp.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
projectID: <PROJECT_ID>
credentials:
source: Secret
secretRef:
name: gcp-credential
namespace: crossplane-system
key: creds
$ kubectl apply -f gcp-provider.yaml
Providerを確認する
正常にGCP Providerがapplyされたかどうかを確認します。
$ kubectl get provider
NAME PROJECT-ID AGE
providerconfig.gcp.crossplane.io/default <PROJECT-ID> 74s
ローカルKubernetsクラスターからGKEを作成する
次に、ローカルKubernetesクラスターからGKEを作成します。
※もし、GCPのprojectで以下のAPIが有効になっていない場合は、あらかじめ有効化をお願いします。
- Kubernetes Engine API
- Compute Engine API
network作成
GKEを作成するネットワークをCrossplaneで作成します。
network.yaml
apiVersion: compute.gcp.crossplane.io/v1beta1
kind: Network
metadata:
name: main-network
spec:
deletionPolicy: "Orphan"
forProvider:
autoCreateSubnetworks: false
description: 'Main Network created by Crossplane'
routingConfig:
routingMode: 'REGIONAL'
---
apiVersion: compute.gcp.crossplane.io/v1beta1
kind: Subnetwork
metadata:
name: subnet-1
spec:
deletionPolicy: "Orphan"
forProvider:
ipCidrRange: '10.0.0.0/20'
networkRef:
name: main-network
region: asia-northeast1
上記のような形で、サブネット等を作成し、GKEが動作するnetworkを作成します(CIDR等は自由に変更してください)
$ kubectl apply -f network.yaml
以下のコマンドで正常に作成されたかを確認できます。
$ kubectl get managed
NAME READY SYNCED
subnetwork.compute.gcp.crossplane.io/subnet-1 True True
NAME READY SYNCED
network.compute.gcp.crossplane.io/main-network True True
deletionPolicyを忘れない
先ほど作成したVPCとSubnetのmanaged resourceには deletionPolicy: "Orphan"
を付与しています。 このstatusはCrossplane上から対象のresourceを削除してもGCP上からは削除しないという設定のために必要で、この設定がないとローカルKubernetesクラスターからGKEクラスターにCrossplaneを移行する際に削除処理が走ってしまいます。
GKEクラスターを作成する
gke.yaml
---
apiVersion: container.gcp.crossplane.io/v1beta2
kind: Cluster
metadata:
name: crossplane-cluster
spec:
deletionPolicy: "Orphan"
forProvider:
initialClusterVersion: latest
network: "projects/<PROJECT_ID>/global/networks/main-network"
subnetwork: "projects/<PROJECT_ID>/regions/asia-northeast1/subnetworks/subnet-1"
ipAllocationPolicy:
useIpAliases: true
defaultMaxPodsConstraint:
maxPodsPerNode: 100
addonsConfig:
gcePersistentDiskCsiDriverConfig:
enabled: true
location: asia-northeast1
monitoringService: monitoring.googleapis.com/kubernetes
loggingService: logging.googleapis.com/kubernetes
writeConnectionSecretToRef:
name: crossplane-cluster
namespace: default
---
apiVersion: container.gcp.crossplane.io/v1beta1
kind: NodePool
metadata:
name: crossplane-nodepool
spec:
deletionPolicy: "Orphan"
forProvider:
autoscaling:
autoprovisioned: false
enabled: true
minNodeCount: 1
maxNodeCount: 2
cluster: projects/<PROJECT_ID>/locations/asia-northeast1/clusters/crossplane-cluster
config:
serviceAccount: crossplane-sa@<PROJECT_ID>.iam.gserviceaccount.com
diskSizeGb: 30
diskType: pd-ssd
imageType: cos_containerd
labels:
created_by: crossplane
machineType: e2-medium
oauthScopes:
- "https://www.googleapis.com/auth/devstorage.read_only"
- "https://www.googleapis.com/auth/logging.write"
- "https://www.googleapis.com/auth/monitoring"
- "https://www.googleapis.com/auth/servicecontrol"
- "https://www.googleapis.com/auth/service.management.readonly"
- "https://www.googleapis.com/auth/trace.append"
- "https://www.googleapis.com/auth/compute"
initialNodeCount: 1
locations:
- asia-northeast1-a
- asia-northeast1-b
- asia-northeast1-c
diskSizeやlocations等は自由に変更してください。また、GKE用のServiceAccountも作成し、serviceAccountの項目で紐づけてください。
$ kubectl apply -f gke.yaml
以下のコマンドで正常稼働しているか確認します。
$ kubectl get managed
NAME READY SYNCED
subnetwork.compute.gcp.crossplane.io/subnet-1 True True
NAME READY SYNCED
network.compute.gcp.crossplane.io/main-network True True
NAME READY SYNCED STATE ENDPOINT LOCATION AGE
cluster.container.gcp.crossplane.io/crossplane-cluster True True RUNNING 34.146.81.14 asia-northeast1 12m
NAME READY SYNCED STATE CLUSTER-REF AGE
nodepool.container.gcp.crossplane.io/crossplane-nodepool True True RUNNING 12m
先ほど作ったネットワーク群だけでなく、GKEに関するクラスターとノードプールも正常に作成されていることがわかります。
これで、ローカルKubernetesクラスターで動作するCrossplaneでGKEを作成・管理することができました。
GKEにCrossplaneをInstallする
GKEクラスターの作成が完了したため、次は、作成したGKEクラスターにCrossplaneをinstallします。
GKEクラスターのcredentialを取得
$ gcloud container clusters get-credentials crossplane-cluster --region asia-northeast1 --project $PROJECT_ID
これでGKEクラスターに対して、kubectlコマンドを実行できるようになりました。
GKEにCrossplaneをInstallする
先ほど、kindクラスターに実行したのと同じようにHelmを利用して、GKEにもCrossplaneをinstallします。
$ kubectl create namespace crossplane-system
$ helm repo add crossplane-stable https://charts.crossplane.io/stable
$ helm repo update
$ helm install crossplane --namespace crossplane-system crossplane-stable/crossplane
GKEにもkindと同じmanifestファイルをapplyする
GKEにもkindに適用したmanifestファイルを適用します。
$ kubectl apply -f secret.yaml
$ kubectl apply -f gcp-provider.yaml
$ kubectl apply -f network.yaml
$ kubectl apply -f gke.yaml
すべてのリソースが正常に連携されているかを確認する
kindクラスターから作成されたリソースとGKE上のCrossplaneのmanaged resourcesが紐づけられていることを確認します。
$ kubectl get managed
NAME READY SYNCED
subnetwork.compute.gcp.crossplane.io/subnet-1 True True
NAME READY SYNCED
network.compute.gcp.crossplane.io/main-network True True
NAME READY SYNCED STATE ENDPOINT LOCATION AGE
cluster.container.gcp.crossplane.io/crossplane-cluster True True RUNNING 34.146.81.14 asia-northeast1 31s
NAME READY SYNCED STATE CLUSTER-REF AGE
nodepool.container.gcp.crossplane.io/crossplane-nodepool True True RUNNING 31s
ローカルKubernetes(kind)クラスターを削除する
いままでの操作で、
- ローカルKubernetes(kind)クラスターで動作するCrossplaneからGKEを作成する
-
作成されたGKE上で動作するCrossplane
とkindクラスター上のCrossplaneが作成したリソース
を紐づける
ことが完了しました。
そのため、現時点で、kindクラスターとGKEクラスターで同一のGCPリソースを管理していることになります。
この状態でkindクラスターだけを削除すると、GKEクラスター上で動作しているCrossplaneが自分自身が動作するGKEリソースを管理する状態が完成します。
kindクラスターを削除
$ kind delete cluster --name crossplane-local
GKEクラスターにリソースを追加してみる
最後に試しにGKEクラスターに対して、リソースを追加してみます。(VPCにサブネットをもう一つ追加)
network.yaml
apiVersion: compute.gcp.crossplane.io/v1beta1
kind: Network
metadata:
name: main-network
spec:
deletionPolicy: "Orphan"
forProvider:
autoCreateSubnetworks: false
description: 'Main Network created by Crossplane'
routingConfig:
routingMode: 'REGIONAL'
---
apiVersion: compute.gcp.crossplane.io/v1beta1
kind: Subnetwork
metadata:
name: subnet-1
spec:
deletionPolicy: "Orphan"
forProvider:
ipCidrRange: '10.0.0.0/20'
networkRef:
name: main-network
region: asia-northeast1
---
apiVersion: compute.gcp.crossplane.io/v1beta1
kind: Subnetwork
metadata:
name: subnet-2
spec:
deletionPolicy: "Orphan"
forProvider:
ipCidrRange: '10.0.16.0/20'
networkRef:
name: main-network
region: asia-northeast1
※subnet-2を追加
$ kubectl apply -f network.yaml
正常にSubentworkが作成されたかを確認
$ kubectl get managed
NAME READY SYNCED
network.compute.gcp.crossplane.io/main-network True True
NAME READY SYNCED
subnetwork.compute.gcp.crossplane.io/subnet-1 True True
subnetwork.compute.gcp.crossplane.io/subnet-2 True True
NAME READY SYNCED STATE ENDPOINT LOCATION AGE
cluster.container.gcp.crossplane.io/crossplane-cluster True True RUNNING 34.146.81.14 asia-northeast1 15h
NAME READY SYNCED STATE CLUSTER-REF AGE
nodepool.container.gcp.crossplane.io/crossplane-nodepool True True RUNNING 15h
正常にSubentworkが作成されています🎉
まとめ
CrossplaneはKubernetes上で動作するコントロールプレーンです。そのため、Crossplane自身が動作するKubernetesクラスターもCrossplaneでIaCとして管理しようとすると、今回紹介したようなフローが必要になります。是非、参考にしてみてください!
note
勉強法やキャリア構築法など、エンジニアに役立つ記事をnoteで配信しています。
Discussion