5分でわかる!Kubernetes/CloudNative Topics

入門Cluster API BYOH ~物理ホストやVMを用いてクラスタの構築を自動化する

こんにちは。CyberAgentの川部です。

「5分でわかる!Kubernetes/CloudNative」連載の第2回は、Cluster API Bring Your Own Host(BYOH)というOSSについて紹介します。Cluster APIの概要、用語やリソース、実際のBYOHの動作を説明していきます。

Cluster API の概要

Cluster APIはKubernetesのCluster Lifecycle SIGsで開発されているOSSです。

端的にいってしまうとKubernetes上で別のKubernetesクラスタの構築や更新、削除といった一連の操作を実現するためのソフトウェアとなっています。

なぜ、わざわざKubernetesクラスタでKubernetesクラスタを管理するのでしょうか? 筆者の考えるメリットとしては、クラスタの構成をマニフェストとして定義することでKubernetesクラスタの構築や更新、削除の自動化が可能という点です。

Cluster APIの実態は複数のCRDやカスタムコントローラから構成されます。

図1 Cluster APIの概要 (参照:Concepts - The Cluster API Book
図1

Cluster APIはClusterやControlPlane、MachineDeployment、Machineといったカスタムリソースを提供しています。これらのリソースを管理Kubernetesクラスタに作成することで、別のKubernetesの作成を行います。

また、利用するインフラストラクチャに応じてプロバイダを個別に実装するアーキテクチャになっています。既存のプロバイダを利用すればAWSやGCP、OpenStackなど様々なインフラストラクチャ上にKubernetesクラスタを構築できます。

InfrastructureClusterやInfrastructureMachineといったリソースはプロバイダごとに定義されることを想定したリソースです。AWSのプロバイダを例に挙げると、AWSClusterとAWSMachineがそのリソースにあたります。

AWSClusterリソースではSecurityGroupやVPC、Gatewayに関する設定ができ、作成するとKubernetesクラスタが動作するネットワーク構成の構築が自動的に行われます。

Kubernetesノードが動作するVMや物理マシンを抽象化したMachineリソースのプロバイダ実装であるAWSMachineでは、作成するとKubernetesのコンポーネントがインストールされた状態のEC2のVMが立ち上がります。

今回紹介するCluster API BYOHにおいても、独自のリソースとCluster APIが提供するリソースの関係が重要となってくるので後ほど紹介します。

図2 Cluster APIとプロバイダの関係
図2

Cluster APIではプロバイダ実装をサポートするために、公式ドキュメントで実装すべき項目や想定する実装内容が説明されています。詳しくはそちらをご覧ください。

今回紹介するCluster API BYOHはCluster APIプロバイダ実装の一種で、既存のLinuxマシンを物理、VM問わずKubernetesノードとして利用できます。

Cluster API Bring Your Own Hostとは?

先ほども述べた通り、Cluster API BYOH(以降 BYOH)を利用すれば既存のLinuxマシンをKubernetesノードとして利用できます。

BYOHはCluster APIプロバイダの中でも異色なプロバイダです。

BYOHではMachineリソースを作成しても、新規にLinuxマシンを作成したりLinuxマシンが動作するネットワーク構成を新規作成、更新することはありません。

他のプロバイダでは基本的にMachineリソースを定義し、それに応じてインフラストラクチャが提供するAPIなどを操作してVMの作成やネットワークの構成管理を行う形でした。しかしBYOHでは既存のLinuxマシンをKubernetesノードに組み込むという仕様上、これらのアプローチとは異なる形でプロバイダが実装されています。

BYOHの面白い点はこのプロバイダの実装にあるのですが、使う側は特にその内容を意識することなく、他のプロバイダと同様にKubernetesクラスタの構築やバージョンアップを自動化できます。つまり、既存のLinuxマシンの資源を再利用できるというメリットに変わりはありません。

BYOHによるKubernetesクラスタの構築

それでは実際にBYOHでのKubernetesクラスタの構築について説明します。

なお、ここからはKubernetesクラスタが複数出てきてややこしいので、Linuxマシンを利用して作成したいKubernetesクラスタをWorkloadクラスタ、それを管理するクラスタをManegementクラスタと呼ぶことにします。

まずCluster APIの多くのプロバイダでは、プロバイダが提供するコントローラがManagementクラスタ上でのみ動作し、MachineやClusterといったリソースに応じてインフラストラクチャのリソースを操作します。

図3 Cluster API AWS Providerの概略
図3

しかし、BYOHはこのパターンに当てはまらない実装となっており、agentと呼ばれるカスタムコントローラとManagementクラスタで動作するカスタムコントローラの二つが必要となります。またagentは既存のLinuxマシン上で動作しますので、利用したいLinuxマシンの数だけインストールする必要があります。

図4はBYOHにおけるagentとカスタムコントローラの関係を表したものです。

図4 BYOHの概略
図4

agentはLinuxマシンのIPアドレスやMACアドレスといったホスト固有の情報を、ManagementクラスタにByoHostというカスタムリソースとして登録することが第一の役割です。

その後はClusterAPIがAWSのEC2インスタンスを作成するのと同じように、BYO Hostの情報を参照し、BYOHMachineを作りながらcloud-initスクリプトで実際にノードの初期化を行います。

他のプロバイダではBYO Hostのようなリソースは登場しませんが、BYOHではBYO HostでLinuxマシンの情報を抽象化することによって、別のKubernetesクラスタのノードとして再利用できます。

初期化処理の実態はcloud-initのスクリプトです。

* Applying /etc/sysctl.conf ...
net.ipv4.tcp_max_tw_buckets = 65536
net.core.somaxconn = 16384
net.core.netdev_max_backlog = 2048
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_tw_reuse = 1

(中略)

+ for pkg in cri-tools kubernetes-cni kubectl kubelet kubeadm
+ dpkg --install /var/lib/byoh/bundles/projects.registry.vmware.com/cluster_api_provider_bringyourownhost/byoh-bundle-ubuntu_20.04.1_x86-64_k8s:v1.23.5/kubelet.deb
Selecting previously unselected package kubelet.
(Reading database ... 64597 files and directories currently installed.)
Preparing to unpack .../kubelet.deb ...
Unpacking kubelet (1.23.5-00) ...
Setting up kubelet (1.23.5-00) ...
Created symlink /etc/systemd/system/multi-user.target.wants/kubelet.service → /lib/systemd/system/kubelet.service.
+ apt-mark hold kubelet
kubelet set on hold.
+ for pkg in cri-tools kubernetes-cni kubectl kubelet kubeadm
+ dpkg --install /var/lib/byoh/bundles/projects.registry.vmware.com/cluster_api_provider_bringyourownhost/byoh-bundle-ubuntu_20.04.1_x86-64_k8s:v1.23.5/kubeadm.deb

上記のように必要なKubernetesのコンポーネントのインストールやカーネルパラメータチューニングなどを行っています。

コントロールプレーンとワーカーの分離

さて、ここまで読まれて「BYO Hostリソースに登録したはいいけどどうやってコントロールプレーンとワーカーに分けるんだろう?」という疑問を持つ人もいるかと思います。この項ではCluster API BYOHによるコントロールプレーンとワーカーの指定の仕方について取り上げます。

その前に、Cluster APIとCluster API BYOHのカスタムリソースとその関係性を改めて整理してみましょう。

図5 Cluster API BYOHのリソース関係
図5

図5における語句の説明は次のとおりです。

  • KubeadmControlPlane:コントロールプレーン専用のMachineSetを管理します。Deployment的な立ち位置です。
  • MachineDeployment:ワーカーノード用のMachineSetを管理します。こちらも同様にDeploymentと似たような振る舞いをします。
  • KubeadmConfigTemplate:Machine作成時に起動するcloud-initスクリプトの定義を行います。MachineDeploymentとKubeadmControlPlaneから参照されます。
  • MachineSet:ReplicaSetと似たようにMachineの台数を管理します。
  • Machine:Kubernetesの1ノードに対応します。InfrastructureMachineへの参照を持っています。
  • Cluster:Kubernetesのクラスタが使用するバージョンやKubeadmControlPlane、InfrastructureClusterへの参照を持ちます。
  • ByoHost:LinuxマシンのIPアドレスやMACアドレスを保持します。
  • ByoMachineTemplate:どのLinuxマシンを選択するかのSelectorを持ちます。
  • ByoMachine:ByoHostへの参照と初期化スクリプトを定義します。
  • ByoCluster:コントロールプレーンのエンドポイントとKubernetesのバージョンを指定します。

つまりコントロールプレーンとそうでないものを分離するためには、KubeadmControlPlaneとMachineDeploymentを利用すればいいということになります。

余談ですが、MachineDeploymentやKubeadmControlPlaneではローリングアップデートの機能がサポートされており、ノードのKubernetesのバージョンを更新する際の影響を調整することも可能です。

多くのプロバイダでは、KubeadmControlPlaneとMachineDeploymentそれぞれのリソースを作成すればそれに応じたVMの作成や初期化処理が行われるため、何か特別な手順を踏む必要はありません。

しかし、BYOHでは既にLinuxマシンが存在する前提であり、それぞれにコントロールプレーン用、ワーカー用という区別はありません。

そこでBYOHではBYOHostリソースに手動でラベルを付与し、BYOMachineTemplateのSelectorによって、KubeadmControlPlaneで利用するLinuxマシンなのか、MachineDeploymentで利用するLinuxマシンなのかを制御します。

コードMachineTemplateのSelectorによるコントロールプレーンとワーカーの区別
---
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: ByoMachineTemplate
metadata:
  name: byoh-sample-cluster-md-0
  namespace: default
spec:
  template:
    spec:
      selector:
        matchLabels:
          "type": "worker"
---
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
kind: ByoMachineTemplate
metadata:
  name: byoh-sample-cluster-control-plane
  namespace: default
spec:
  template:
    spec:
      selector:
        matchLabels:
          "type": "controlplane"

コントロールプレーンの冗長化

kubeadmを用いて手動でKubernetesクラスタを構築する際、コントロールプレーンを冗長化させるのは少々手間が必要ですが、Cluster API BYOHではkube-vipを用いることで比較的簡単に冗長化させることができます。

kube-vipはKubeadmControlPlaneにstatic-podのマニフェストを定義します。そしてControlPlaneとなるLinuxマシン上で動作させます。

apiVersion: controlplane.cluster.x-k8s.io/v1beta1
kind: KubeadmControlPlane
metadata:
  labels:
    nodepool: pool0
  name: byoh-cluster-control-plane
  namespace: default
spec:
  kubeadmConfigSpec:
    clusterConfiguration:
      apiServer:
        certSANs:
        - localhost
        - 127.0.0.1
        - 0.0.0.0
        - host.docker.internal
      controllerManager:
        extraArgs:
          enable-hostpath-provisioner: "true"
    files:
    - content: |
        apiVersion: v1
        kind: Pod
        metadata:
          creationTimestamp: null
          name: kube-vip
          namespace: kube-system
        spec:
          containers:
          - args:
            - manager
            env:
            - name: cp_enable
              value: "true"
            - name: vip_arp
              value: "true"
            - name: vip_leaderelection
              value: "true"
            - name: vip_address
              value: 172.18.0.10
            - name: vip_interface
              value: 
            - name: vip_leaseduration
              value: "15"
            - name: vip_renewdeadline
              value: "10"
            - name: vip_retryperiod
              value: "2"
            image: ghcr.io/kube-vip/kube-vip:v0.4.1
            imagePullPolicy: IfNotPresent
            name: kube-vip
            resources: {}
            securityContext:
              capabilities:
                add:
                - NET_ADMIN
                - NET_RAW
            volumeMounts:
            - mountPath: /etc/kubernetes/admin.conf
              name: kubeconfig
          hostNetwork: true
          hostAliases:
            - hostnames:
                - kubernetes
              ip: 127.0.0.1
          volumes:
          - hostPath:
              path: /etc/kubernetes/admin.conf
              type: FileOrCreate
            name: kubeconfig
        status: {}
      owner: root:root
      path: /etc/kubernetes/manifests/kube-vip.yaml

(以下略)

kube-vipでは複数のLinuxホストのうちいずれかのホストがarpを用いて該当のVIP宛の通信を受け付けます。今回の例では172.18.0.10のアドレスがVIPとして受け付けています。

もちろん、kube-vip を用いずに個別に作成したロードバランサと仮想IPを使用することもできます。

その場合はBYOClusterリソースの.spec.controlPlaneEndpointに使用したいIPとPortを指定することでCluster APIのコントローラが疎通確認などを行います。

この際、ロードバランサにプールメンバーとしてLinuxホストを登録するのを忘れないようにしましょう。また、Machineリソースを削除した際にプールメンバーから外すといった処理も自分で実行する必要があります。

CNIやServiceTypeLB、Ingressの導入

BYOHはインフラストラクチャを問わずに既存のLinuxマシンを用いてKubernetesクラスタを構築します。故にCNIやLoadBalancer Service、Ingressといったよく使うであろう機能は自前で導入する必要があります。

とはいってもBYOHで構築されたクラスタはkubeadmで構築されたものなので、よく見るOSSをそのまま導入することが可能です。

  • CNI: Calico, Cilium
  • ServiceTypeLB: MetalLB
  • Ingress: ingress-nginx

これらのソフトウェアスタックを、構築したクラスタ環境に合わせて使うことになります。

まとめ

今回はCluster API BYOHについて紹介しました。

  • Cluster APIのメリットはKubernetesクラスタの管理をKubernetesのライフサイクルや自動回復、ローリングアップデートといった機能を利用して行える。
  • Cluster API BYOHは既存のLinuxマシンをCluster APIのリソースとして登録できる。
  • BYOHの実装は他のプロバイダと違い、エージェントを用いた特殊な構成である。
  • コントロールプレーンはkube-vipによって冗長化できる。
  • CNIやServiceTypeLB、Ingressなどは自前でOSSを活用する必要がある。

Cluster APIは本体やクラウドごとのプロバイダの開発が盛んに行われていて個人的に注目しているプロジェクトです。

現在はCluster API自体はv1beta1というapiVersionになっており、v1に至るまでリソース構造の変化や新しいリソースなどがこれからも追加される可能性があります。

AWSやGCP、そして今回紹介したBYOHのようなプロバイダ側の実装も場合によってはその変更に追従しなくてはならないので、そういった動きにも注目していると面白いかもしれません。

おすすめ記事

記事・ニュース一覧