hidemium's blog

日々学んだことをアウトプットする。

Cluster APIを使ってvSphereにKubernetesクラスタを作成する

今まではKubesprayを使ってKubernetesのインストールを行ってきました。今回は、Cluster APIを使ったKubernetesクラスタを作成を試してみました。

hidemium.hatenablog.com

構成

  • vCenter 7.0 U3
  • ESXi 7.0 Update 3
  • Kubespray
  • kubernetes v1.25.5
  • Cluster API v1.3.2
    • clusterctl v1.3.2
    • cluster-api-provider-vsphere v1.5.1
    • ubuntu-2004-kube-v1.25.5.ova

Cluster APIについて

Cluster APIは、Kubernetesの宣言型の機能を利用し、Kubernetesクラスタの作成や構成、管理をするプロジェクトになります。Kubesprayでは、masterノートやworkerノードの展開はgovcなど自身で行ってきましたが、Cluster APIではその作業も任せることができます。Cluster APIパブリッククラウドなど様々なプラットフォームに対応しており、vSphereにも対応しており、vSphereの実装として、Cluster API Provider vSphere(CAPV)があります。CAPVはTanzu Kubernetes Grid(TKG)の中でも利用されているようです。

Cluster APIを利用すると、Kubernetesクラスタを管理するmanagement clusterと、management clusterで管理されたワークロードを実行するworkload clusterが作成されます。

workload cluster用のネットワークの準備

workload clusterはDHCPIPアドレスを取得するため、workload clusterが接続するポートグループにDHCPIPアドレスを取得できるようにしておきます。homelabでは、EdgeRouterのDHCP機能でIPアドレスを払い出ししています。

マシンイメージの展開

CAPV用のマシンイメージが配布されており、 ubuntu-2004-kube-v1.25.5.ova をダウンロードし、vCenter上にデプロイします。

homelabでの利用なので、マシンイメージをそのまま利用しますが、production環境では独自ビルドが推奨なようです。

マシンイメージのビルド用のpackerテンプレートはこちらで管理されていました。

image-builder/images/capi/packer/ova at master · kubernetes-sigs/image-builder · GitHub

Cluster APIでマシンイメージを展開する際に、デフォルトだとlinked cloneが利用されるため、以下のようにlinked cloneを利用するためにスナップショットをとってから、テンプレート化しておきます。

$ govc snapshot.create -vm ubuntu-2004-kube-v1.25.5 root
$ govc vm.markastemplate ubuntu-2004-kube-v1.25.5

haproxyのマシンイメージについては、kube-vipを使うように変更となったため、非推奨となってようなので、利用はしていません。

management clusterのインストール

通常の手順ですと、kindを利用して、docker上にKubernetesをインストールして、bootstrap clusterを作成し、そこにclusterctlを使ってmanagement clusterをインストールします。

今回は、KubesprayですでにKubernetesクラスタがあるため、Kubesprayで作成したKubernetesクラスタにmanagement clusterをインストールしていきます。

clusterctlをインストールします。

$ curl -L https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.3.2/clusterctl-linux-amd64 -o clusterctl
$ sudo install -o root -g root -m 0755 clusterctl /usr/local/bin/clusterctl
$ clusterctl version

clusterctlを実行するために、以下のように ~/.cluster-api/clusterctl.yaml に定義ファイルを用意します。

$ vi ~/.cluster-api/clusterctl.yaml
## -- Controller settings -- ##
VSPHERE_USERNAME: "vCenterのログインユーザ"
VSPHERE_PASSWORD: "パスワード"

## -- Required workload cluster default settings -- ##
VSPHERE_SERVER: "vCenterのFQDN"
VSPHERE_DATACENTER: "データセンター名"
VSPHERE_DATASTORE: "データストア名"
VSPHERE_NETWORK: "DHCPが利用可能なポートグループ名"
VSPHERE_RESOURCE_POOL: "<クラスタ名 or リソースプール名>/Resources"
VSPHERE_FOLDER: "vm"
VSPHERE_TEMPLATE: "ubuntu-2004-kube-v1.25.5"
CONTROL_PLANE_ENDPOINT_IP: "workload clusterのkubectlで接続するコントロールプレーンのIPアドレス"
VIP_NETWORK_INTERFACE: "eth0"
VSPHERE_TLS_THUMBPRINT: "vCenterのthumbprint"
EXP_CLUSTER_RESOURCE_SET: "true"
VSPHERE_SSH_AUTHORIZED_KEY: "sshのための公開鍵"
VSPHERE_STORAGE_POLICY: ""

vCenterのthumbprintは、vCenterにsshでログインし、以下のコマンドで取得します。

# openssl x509 -in /etc/vmware-vpx/ssl/rui.crt -fingerprint -sha1 -noout

vCenterのログイン情報や、workload clusterを作成するために必要なリソースプールやデータストア名などを入力します。

上記の設定で困ったことは、 CONTROL_PLANE_ENDPOINT_IPVIP_NETWORK_INTERFACE の設定になります。

CONTROL_PLANE_ENDPOINT_IP はkube-vipで利用するworkload clusterのコントロールプレーンのIPアドレスになり、DHCPのIP帯以外のstaticなIPアドレスを指定する必要があります。ここのIPアドレスの指定を間違えると、コントロールプレーンにアクセスできないとエラーが出て、workload clusterの作成に失敗します。

$ kubectl logs capi-kubeadm-control-plane-controller-manager-785c94c5d4-sh9fg -n capi-kubeadm-control-plane-system -f
"Failed to update KubeadmControlPlane Status" err="failed to create remote cluster client: failed to create cluster accessor: error creating dynamic rest mapper for remote cluster \"default/vsphere-quickstart\": Get \"https://10.0.50
.30:6443/api?timeout=10s\": x509: certificate signed by unknown authority (possibly because of \"crypto/rsa: verification error\" while trying to verify candidate authority certificate \"kubernetes\")" controller="kubeadmcontrolplane" controllerGroup="controlplane.cluster.x-k8s.io"
 controllerKind="KubeadmControlPlane" KubeadmControlPlane="default/vsphere-quickstart" namespace="default" name="vsphere-quickstart" reconcileID=fa7159b4-97ff-45cd-b1ba-29a4d5f11548 Cluster="default/vsphere-quickstart"

VIP_NETWORK_INTERFACE は、コントロールプレーンのkube-vipで利用するインターフェイスの設定となりますが、公式のマシンイメージでは、インターフェイスにeth0を利用しており、サンプルではens192だったため、コントロールプレーンにアクセスできず、workload clusterの作成に失敗します。

~/.cluster-api/clusterctl.yaml が出来たところで、以下のコマンドで、management clusterのインストールを行います。

$ clusterctl init --infrastructure vsphere
Fetching providers
Installing cert-manager Version="v1.10.1"
Waiting for cert-manager to be available...
Installing Provider="cluster-api" Version="v1.3.2" TargetNamespace="capi-system"
Installing Provider="bootstrap-kubeadm" Version="v1.3.2" TargetNamespace="capi-kubeadm-bootstrap-system"
Installing Provider="control-plane-kubeadm" Version="v1.3.2" TargetNamespace="capi-kubeadm-control-plane-system"
Installing Provider="infrastructure-vsphere" Version="v1.5.1" TargetNamespace="capv-system"

Your management cluster has been initialized successfully!

You can now create your first workload cluster by running the following:

  clusterctl generate cluster [name] --kubernetes-version [version] | kubectl apply -f -

以下のような、podが起動してきます。

$ kubectl get pod -A
NAMESPACE                           NAME                                                             READY   STATUS    RESTARTS       AGE
capi-kubeadm-bootstrap-system       capi-kubeadm-bootstrap-controller-manager-78c76cd689-flgtb       1/1     Running   0              3d
capi-kubeadm-control-plane-system   capi-kubeadm-control-plane-controller-manager-785c94c5d4-sh9fg   1/1     Running   0              3d
capi-system                         capi-controller-manager-8665f47486-thlh4                         1/1     Running   0              3d
capv-system                         capv-controller-manager-dfb77fcc6-tz7t8                          1/1     Running   0              2d19h
cert-manager                        cert-manager-74d949c895-v4g52                                    1/1     Running   0              3d
cert-manager                        cert-manager-cainjector-d9bc5979d-ktwrz                          1/1     Running   0              3d
cert-manager                        cert-manager-webhook-84b7ddd796-fdj8l                            1/1     Running   0              3d

workload clusterのインストール

次に、workload clusterのインストールをしていきます。

workload clusterのKubernetsのバージョンや、コントロールプレーンのVM数、wokerノードのVM数を指定して、cluster.yamlを生成します。

$ clusterctl generate cluster vsphere-quickstart \
    --infrastructure vsphere \
    --kubernetes-version v1.25.5 \
    --control-plane-machine-count 1 \
    --worker-machine-count 3 > cluster.yaml

必要に応じて、cluster.yamlを編集します。

以下のコマンドで、workload clusterのインストールを行います。

$ kubectl apply -f cluster.yaml

以下のコマンドで、workload clusterが起動してきかたを確認できます。10分ぐらいで立ち上がってくるように見えています。

$ kubectl get machines
NAME                                       CLUSTER              NODENAME                                   PROVIDERID                                       PHASE     AGE     VERSION
vsphere-quickstart-md-0-5c5849c5b9-5wbv8   vsphere-quickstart   vsphere-quickstart-md-0-5c5849c5b9-5wbv8   vsphere://42080fa2-7dab-7285-444a-7b0ecc66a35e   Running   7m15s   v1.25.5
vsphere-quickstart-md-0-5c5849c5b9-95595   vsphere-quickstart   vsphere-quickstart-md-0-5c5849c5b9-95595   vsphere://4208d8b7-8297-c452-26f9-e7061d023e8a   Running   7m15s   v1.25.5
vsphere-quickstart-md-0-5c5849c5b9-s4rz9   vsphere-quickstart   vsphere-quickstart-md-0-5c5849c5b9-s4rz9   vsphere://4208246c-a347-1f39-51c3-3907b502f884   Running   7m15s   v1.25.5
vsphere-quickstart-sxfqt                   vsphere-quickstart   vsphere-quickstart-sxfqt                   vsphere://4208aad8-d2e7-42bf-00ac-70511419ff77   Running   7m14s   v1.25.5

workload clusterにアクセスするためのconfigファイルを以下のように生成します。

$ kubectl get secret/vsphere-quickstart-kubeconfig -o json \
  | jq -r .data.value \
  | base64 --decode \
  > ./vsphere-quickstart.kubeconfig

workload clusterのノードを確認すると、NotReadyとなっています。こちらはCNIがインストールされていないため、利用ができない状態となっています。

$ KUBECONFIG=vsphere-quickstart.kubeconfig kubectl get node
NAME                                       STATUS     ROLES           AGE   VERSION
vsphere-quickstart-md-0-5c5849c5b9-5wbv8   NotReady   <none>          10m   v1.25.5
vsphere-quickstart-md-0-5c5849c5b9-95595   NotReady   <none>          10m   v1.25.5
vsphere-quickstart-md-0-5c5849c5b9-s4rz9   NotReady   <none>          10m   v1.25.5
vsphere-quickstart-sxfqt                   NotReady   control-plane   11m   v1.25.5

以下のようにcalicoをインストールします。

$ KUBECONFIG=vsphere-quickstart.kubeconfig kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.0/manifests/calico.yaml

Readyになったことを確認し、workload clusterのインストールは完了になります。

$ KUBECONFIG=vsphere-quickstart.kubeconfig kubectl get node
NAME                                       STATUS   ROLES           AGE   VERSION
vsphere-quickstart-md-0-5c5849c5b9-5wbv8   Ready    <none>          28h   v1.25.5
vsphere-quickstart-md-0-5c5849c5b9-95595   Ready    <none>          28h   v1.25.5
vsphere-quickstart-md-0-5c5849c5b9-s4rz9   Ready    <none>          28h   v1.25.5
vsphere-quickstart-sxfqt                   Ready    control-plane   28h   v1.25.5

calicoのインストールが完了すると、podの状態はこのようになっていました。vsphere-csi-controller が CrashLoopBackOff となっている原因について別途書いてみようと思います。

$ KUBECONFIG=vsphere-quickstart.kubeconfig kubectl get pod -A
NAMESPACE     NAME                                               READY   STATUS             RESTARTS      AGE
kube-system   calico-kube-controllers-74677b4c5f-m77w8           1/1     Running            0             16m
kube-system   calico-node-7bcpz                                  1/1     Running            0             16m
kube-system   calico-node-w7fs9                                  1/1     Running            0             16m
kube-system   calico-node-wckhz                                  1/1     Running            0             16m
kube-system   calico-node-zlc5b                                  1/1     Running            0             16m
kube-system   coredns-565d847f94-chn5z                           1/1     Running            0             21m
kube-system   coredns-565d847f94-dn4zq                           1/1     Running            0             21m
kube-system   etcd-vsphere-quickstart-d7r7k                      1/1     Running            0             21m
kube-system   kube-apiserver-vsphere-quickstart-d7r7k            1/1     Running            0             21m
kube-system   kube-controller-manager-vsphere-quickstart-d7r7k   1/1     Running            0             21m
kube-system   kube-proxy-br9fn                                   1/1     Running            0             20m
kube-system   kube-proxy-cvfzq                                   1/1     Running            0             20m
kube-system   kube-proxy-qxlj2                                   1/1     Running            0             20m
kube-system   kube-proxy-rmzww                                   1/1     Running            0             21m
kube-system   kube-scheduler-vsphere-quickstart-d7r7k            1/1     Running            0             21m
kube-system   kube-vip-vsphere-quickstart-d7r7k                  1/1     Running            0             21m
kube-system   vsphere-cloud-controller-manager-ctkr7             1/1     Running            0             20m
kube-system   vsphere-cloud-controller-manager-hl5w2             1/1     Running            0             20m
kube-system   vsphere-cloud-controller-manager-r9dhk             1/1     Running            0             20m
kube-system   vsphere-csi-controller-5d6484644d-nqwlh            4/5     CrashLoopBackOff   8 (37s ago)   21m
kube-system   vsphere-csi-node-h9p2x                             3/3     Running            0             21m
kube-system   vsphere-csi-node-hbgsl                             3/3     Running            0             20m
kube-system   vsphere-csi-node-tr99v                             3/3     Running            0             20m
kube-system   vsphere-csi-node-xk2jq                             3/3     Running            0             20m

スモークテスト

動作確認を行います。

テスト用のpodを2台作成し、pod間で疎通が取れるか確認します。

$ KUBECONFIG=vsphere-quickstart.kubeconfig kubectl run myshell1 -it --rm --image busybox -- sh
/ # hostname -i
192.168.136.2
/ # ping 192.168.82.67
PING 192.168.82.67 (192.168.82.67): 56 data bytes
64 bytes from 192.168.82.67: seq=0 ttl=62 time=0.615 ms
64 bytes from 192.168.82.67: seq=1 ttl=62 time=3.218 ms
^C
--- 192.168.82.67 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.615/1.916/3.218 ms
$ KUBECONFIG=vsphere-quickstart.kubeconfig kubectl run myshell2 -it --rm --image busybox -- sh
/ # hostname -i
192.168.82.67
/ # ping 192.168.136.2
PING 192.168.136.2 (192.168.136.2): 56 data bytes
64 bytes from 192.168.136.2: seq=0 ttl=62 time=0.918 ms
64 bytes from 192.168.136.2: seq=1 ttl=62 time=0.316 ms
^C
--- 192.168.136.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.316/0.617/0.918 ms

podの状態は以下の通りです。

$ KUBECONFIG=vsphere-quickstart.kubeconfig kubectl get pod -o wide
NAME       READY   STATUS    RESTARTS   AGE   IP                NODE                                       NOMINATED NODE   READINESS GATES
myshell1   1/1     Running   0          50s   192.168.136.2     vsphere-quickstart-md-0-5c5849c5b9-5wbv8   <none>           <none>
myshell2   1/1     Running   0          28s   192.168.82.67   vsphere-quickstart-md-0-5c5849c5b9-95595   <none>           <none>

おわりに

KubesprayだとKubernetesクラスタのインストールに30分ぐらいかかりましたが、Cluster APIだと10分程度で利用ができるので、効率がよさそうでした。ただ、Kubesprayだとクラスタの初期設定(CNIやMetalLB)もある程度対応できたり、マシンイメージのビルドが楽だったり、構築中の動作やどのような設定を行っているかが分かりやすいということもあり、homelabだとKubesprayのほうが使いやすそうには見えています。用途によって使い分けるのがよさそうに見えました。

参考