はじめに
kube-vipを使ったHAクラスターの構築例は多くありますが、多くがStatic Podを利用したものです。DaemonSetを使った構築を挑戦したのでその記録を共有します
環境
- 仮想化環境: Proxmox8.2
- ベースイメージ: Ubuntu24.04 - cloud-init
kube-vipについて
公式サイト: https://kube-vip.io/
kube-vipはコントロールプレーンに対するVIPや、ロードバランサー(Serviceのやつ)を作成できるものです。ここではコントロールプレーンに対するVIPを利用し、HAクラスタ構築を行います
構築方法として、Static PodとDaemonSetの2種類がありますが各コントロールプレーンにStatic Podを毎回書くのは大変なため、DaemonSetを使って構築します
構築手順
前提
VIPを192.168.20.100に作ることにします。またIPアドレスなどは各自の環境に合わせて読み替えてください
VMの作成
Ubuntu24.04をベースイメージにしてVMを作成します。私の環境ではcloud-initのものを使いましたが、通常の版のものでも問題ないと思います。スペックは以下のようにしておきます
| name | value |
|---|---|
| Memory | 4.0GB |
| Processors | 2 |
| Hard Disk | 8GB |

コンテナランタイムのインストール
コンテナランタイムにはcontainerdやcri-oなどがありますが、今回はcontainerdを使います。ここでは以下のインストール手順を参考に進めます
cri-oでも試してみましたが、なぜかkube-vipがうまく動きませんでした
IPv4フォワーディングを有効にします
# sysctl params required by setup, params persist across rebootscat <<EOF | sudo tee /etc/sysctl.d/k8s.confnet.ipv4.ip_forward = 1EOF
# Apply sysctl params without rebootsudo sysctl --system以下のコマンドを使ってDockerリポジトリを追加し、containerdをインストールします
# Add Docker's official GPG key:sudo apt-get updatesudo apt-get install ca-certificates curlsudo install -m 0755 -d /etc/apt/keyringssudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.ascsudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/nullsudo apt-get update
sudo apt-get install containerd.ioCNIは別で入れるためここではcontainerd.ioを入れます。インストール完了後動作していることを確認してください
sudo systemctl status containerd.service● containerd.service - containerd container runtime Loaded: loaded (/usr/lib/systemd/system/containerd.service; enabled; prese> Active: active (running) since Mon 2024-06-17 12:05:52 UTC; 2min 29s ago Docs: https://containerd.io Process: 1888 ExecStartPre=/sbin/modprobe overlay (code=exited, status=0/SU> Main PID: 1890 (containerd) Tasks: 8 Memory: 12.0M (peak: 12.4M) CPU: 137ms CGroup: /system.slice/containerd.service └─1890 /usr/bin/containerd追加でcontainerdのオプションを一部変更しておきます
containerd config default | sudo tee /etc/containerd/config.tomlsudo vim /etc/containerd/config.toml sandbox_image = "registry.k8s.io/pause:3.6" sandbox_image = "registry.k8s.io/pause:3.9"[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] SystemdCgroup = false SystemdCgroup = truecontainerdを再起動します
sudo systemctl restart containerdkubeadmのインストール
参考
スワップを無効化します
sudo swapoff -asudo vim /etc/fstab次にkubeadmやその他のツールをインストールします。kubeletのバージョンが変わると困るので固定しておきます
sudo apt-get install -y apt-transport-https ca-certificates curl gpgcurl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpgecho 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.listsudo apt-get updatesudo apt-get install -y kubelet kubeadm kubectlsudo apt-mark hold kubelet kubeadm kubectlkube-vipの準備
参考
kube-vip用のマニフェストを生成します。VIPの値を各自が設定したいVIPのアドレス、INTERFACEはVIPが待ち受けを行うネットワークインターフェイスを指定してください。
お使いの環境でのネットワークインターフェイスはnetworkctl listで確認できます
export VIP=192.168.20.100export INTERFACE=eth0KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases | jq -r ".[0].name")alias kube-vip="sudo ctr image pull ghcr.io/kube-vip/kube-vip:$KVVERSION; sudo ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip /kube-vip"kube-vip manifest daemonset \ --interface $INTERFACE \ --address $VIP \ --inCluster \ --taint \ --controlplane \ --services \ --arp \ --leaderElection | tee vip-daemonset.yaml次に/etc/hostsに設定を書き加えます(cloud-initの影響で変更しているファイルが若干違います)。ここはお使いのDNSで設定してもよいと思います
tail /etc/cloud/templates/hosts.debian.tmpl --line 2192.168.20.100 k8s-api-server-endpointクラスタの初期化
先ほど作成したVMを停止し、適当な数クローンします。この際3以上の奇数である必要があることに注意してください。今回は3個クローンしました。 また、この際IPアドレスを固定しておいてください。今回は次のようにしました
- kube-vip1: 192.168.20.80
- kube-vip2: 192.168.20.81
- kube-vip3: 192.168.20.82
kube-vip1に接続し/etc/hostsを書き換えます
sudo vim /etc/hoststail /etc/hosts --lines=2127.0.0.1 k8s-api-server-endpoint
sudo systemctl restart systemd-resolved.service次のコマンドでクラスタを初期化します。この際出ていたjoin用のコマンドはメモしておいてください
sudo kubeadm init --control-plane-endpoint "k8s-api-server-endpoint:6443" --pod-network-cidr=10.1.0.0/16 --upload-certs --apiserver-cert-extra-sans "192.168.20.100" --skip-phases=addon/kube-proxy一応動作確認をしておきます
mkdir -p $HOME/.kubesudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/configsudo chown $(id -u):$(id -g) $HOME/.kube/configkubectl get pod -Akube-vipのデプロイ
参考
まずデプロイするためのRBACを作成します
kubectl apply -f https://kube-vip.io/manifests/rbac.yaml先ほど作成したkube-vipのマニフェストをデプロイします
kubectl apply -f vip-daemonset.yaml簡単に動作確認をします。kube-vip関連のPodが動いでいることを確認してください
kubectl get pod -ANAMESPACE NAME READY STATUS RESTARTS AGEkube-system coredns-7db6d8ff4d-728kx 0/1 Pending 0 7m54skube-system coredns-7db6d8ff4d-7lt66 0/1 Pending 0 7m54skube-system etcd-kube-vip1 1/1 Running 0 8m8skube-system kube-apiserver-kube-vip1 1/1 Running 0 8m8skube-system kube-controller-manager-kube-vip1 1/1 Running 0 8m8skube-system kube-scheduler-kube-vip1 1/1 Running 0 8m8skube-system kube-vip-ds-rsbn9 1/1 Running 0 63s #これですCiliumのデプロイ
参考
- https://helm.sh/docs/intro/install/
- https://docs.cilium.io/en/stable/network/kubernetes/kubeproxy-free/
CNIのCiliumをデプロイするために、Helmをインストールします
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3chmod 700 get_helm.sh./get_helm.shCiliumをデプロイします。この時まだkube-vipは動作していないため現在のノードのIPアドレスにすることを注意してください
helm repo add cilium https://helm.cilium.io/API_SERVER_IP=192.168.20.80# Kubeadm default is 6443API_SERVER_PORT=6443helm install cilium cilium/cilium --version 1.15.6 \ --namespace kube-system \ --set kubeProxyReplacement=true \ --set k8sServiceHost=${API_SERVER_IP} \ --set k8sServicePort=${API_SERVER_PORT}デプロイ後、STATUSがReadyになっていることを確認します
kubectl get nodeNAME STATUS ROLES AGE VERSIONkube-vip1 Ready control-plane 13m v1.30.2kube-vipのデプロイ
参考
次にkube-vipのデプロイを行います。まずkube-vip用のRBACを作成します
kubectl apply -f https://kube-vip.io/manifests/rbac.yaml次に作成したkube-vipのマニフェストをapplyします
kubectl apply -f vip-daemonset.yamlkube-vipのPodが動作していることを確認してください
kubectl get -f vip-daemonset.yamlNAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGEkube-vip-ds 1 1 1 1 1 <none> 23s.kube/configを編集してVIPを宛先に変更しても、kubectlが使えることを確認します
server: https://k8s-api-server-endpoint:6443server: https://192.168.20.100:6443 kubectl get nodeNAME STATUS ROLES AGE VERSIONkube-vip1 Ready control-plane 20m v1.30.2他のコントロールプレーン追加
他のノードに入り、出力されていたjoinコマンドを実行します
sudo kubeadm join k8s-api-server-endpoint:6443 --token <token> \ --discovery-token-ca-cert-hash <token-hash> \ --control-plane --certificate-key <key>mkdir -p $HOME/.kubesudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/configsudo chown $(id -u):$(id -g) $HOME/.kube/configもしここまでに時間がかかってしまい、トークンの有効期限が切れてしまった場合、次のコマンドでトークンを再生成できます
echo $(kubeadm token create --print-join-command) --control-plane --certificate-key $(sudo kubeadm init phase upload-certs --upload-certs | grep -vw -e certificate -e Namespace)この作業をkube-vip2,kube-vip3で実行します
最終的な状態
ここまでの手順をすべて完了すると次のような出力が得られるはずです
kubectl get nodeNAME STATUS ROLES AGE VERSIONkube-vip1 Ready control-plane 25m v1.30.2kube-vip2 Ready control-plane 2m43s v1.30.2kube-vip3 Ready control-plane 43s v1.30.2コントロールプレーンが3台存在し、動作していることがわかります。ここで試しに3VMの内1つ、kube-vip1をシャットダウンさせても動作することができるか確認してみます

kube-vip1をProxmoxのUIからシャットダウンします


kube-vip2もしくはkube-vip3に入り、kubectlが現在も使用できることを確認します
kubectl get nodeNAME STATUS ROLES AGE VERSIONkube-vip1 NotReady control-plane 33m v1.30.2kube-vip2 Ready control-plane 10m v1.30.2kube-vip3 Ready control-plane 8m26s v1.30.2必要があればワーカーノードも追加してみてください
終わりに
Static Podを使わずにDaemonSetを使ったHAクラスタ構築ができました。個人的にkube-vipで気に入っているのはHAにするのにほかのアプリケーション(keepalivedやhaproxy)が不要な点です。 すべてがkubernetes上で完結しているのでとてもシンプルだと思います。
今回はARPモードでkube-vipを動かしましたが、BGPを使ったモードもあるようです。ちょうどBGPを扱えるルータがあるので、時間があるときにこちらも試してみたいと思います