はじめに
kubernetesをkubeadm使って構築する際、Vagrant環境だとNATアドレスが優先されてしまう。
それに対処する個別の設定方法はネットで探すと出てくるものの、毎回探すのが大変。
さらにkubernetesの本家の手順はVagrant環境意識していないので手順通りにやるとハマったり、いろんな情報が混在して、結局何を設定すればいいのかわかりにくかったため、自分の備忘録用に整理。
前提
- Vagrantで作ったVM2台にインストール(Master用とWorker用にそれぞれ一つ)
- Masterノード:192.168.56.53
- Workerノード:192.168.56.54
- VMはUbuntu20.04を利用
- kubernetes構築はkubeadmを利用
- Container Runtimeはcontainerdを利用
- cgroupドライバはsystemdを利用
- CNIプラグイン実装はcalicoを利用
- calicoで使うアドレス帯
192.168.0.0/16
がVagrantのアドレス帯192.168.56.0/24
と重複しているので、calicoのアドレス帯を172.168.0.0/16
に変更
手順
以下の手順で進めた。VagrantでのVMはすでにある前提で省略。
-
Masterノードの構築
- Container Runtime(containerd)をインストール
- kubeadm, kubelet, kubectlのインストール
- kubernetesクラスタの作成(Masterノード側)
- CNIプラグインのインストール
-
Workerノードの構築
- Container Runtime(containerd)をインストール
- kubeadm, kubeletのインストール
- kubernetesクラスタを作成(Workerノード側)
Masterノードの構築
最初Masterノードから。
Container Runtimeのインストール
swapをoffにする
/etc/fstab
のswapをコメントアウト
sudo vi /etc/fstab
# コメントアウトしてswap を永続的にOFFにする
# /swap.img none swap sw 0 0
シャットダウン後、swap確認
# shutdown
sudo shutdown -r now
# 起動後に再度ログインしてswap確認
free -m
パケットforward設定
昔の手順見ると他にも設定項目があったが、kubernetes1.31ではこれだけでいいらしい。
# sysctl params required by setup, params persist across reboots
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.ipv4.ip_forward = 1
EOF
# Apply sysctl params without reboot
sudo sysctl --system
sysctl net.ipv4.ip_forward
[結果:設定されているなら1]
net.ipv4.ip_forward = 1
cgroupドライバをどれにするか決める。
cgroupfs driver
と systemd cgroup driver
の2種類のドライバがあるが、
systemd起動しているシステムではsystemd cgroup driver
を使えとあるのでsystemd
にする。
kubernetesインストール時に指定するので、今は何もしない。
containerdのインストール
containerdの説明ページから辿れるcontainerdのインストールページには公式のバイナリでのインストールする方法と、Dockerでインストールする方法があり、ネットで調べてもDockerでインストールする方法が多く紹介されている。
ここでは公式のバイナリでのインストールにする。(Dockerインストール試したけどうまくいかなかったので諦めた・・)
containerdインストールの大まかな流れは以下のとおり。
- Step1. containerdインストール
- Step2. runcインストール
- Step3. CNIプラグインインストール
Step1.containerdインストール
ダウンロードページから取得。
2.x系もあったが、最近出たばっかりでハマりそうだったので1.7系をインストールする。
この後インストールするruncのバージョン1.2.2に対応しているとのこと。
# 資材をdownloadしてインストール
curl -OL https://github.com/containerd/containerd/releases/download/v1.7.24/containerd-1.7.24-linux-amd64.tar.gz
sudo tar Cxzvf /usr/local containerd-1.7.24-linux-amd64.tar.gz
# service起動用スクリプトもdownlodして設定する
curl -OL https://raw.githubusercontent.com/containerd/containerd/main/containerd.service
sudo cp ./containerd.service /lib/systemd/system/containerd.service
sudo systemctl daemon-reload
sudo systemctl enable --now containerd
## 起動していることを確認
systemctl status containerd
Step2. runcインストール
containerdに対応しているrunc v1.2.2
をダウンロード。
curl -OL https://github.com/opencontainers/runc/releases/download/v1.2.2/runc.amd64
sudo install -m 755 runc.amd64 /usr/local/sbin/runc
Step3. CNIプラグインインストール
どのバージョンが適切か不明だったので最新バージョンにする。
curl -OL https://github.com/containernetworking/plugins/releases/download/v1.6.1/cni-plugins-linux-amd64-v1.6.1.tgz
sudo mkdir -p /opt/cni/bin
sudo tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-v1.6.1.tgz
kubeadm, kubelet, kubectlのインストール
基本的にkubernetesのインストール手順に従って実施する。
必要なパッケージのインストール
sudo apt-get update
# apt-transport-https may be a dummy package; if so, you can skip that package
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
とりあえず、マニュアルに書かれている通りに・・・
sudo mkdir -p /etc/apt/keyrings
# If the directory `/etc/apt/keyrings` does not exist, it should be created before the curl command, read the note below.
# sudo mkdir -p -m 755 /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.31/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
技術者として理解することを放棄し・・・
# This overwrites any existing configuration in /etc/apt/sources.list.d/kubernetes.list
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.31/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
エラーが出ないことだけを祈りつつ・・・
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
# パッケージが更新されないようにする
sudo apt-mark hold kubelet kubeadm kubectl
自動起動を有効にしてkubeletサービス起動
sudo systemctl enable --now kubelet
この段階ではkubeletサービスは再起動を繰り返して正常に起動しないが問題ないとインストールガイドに書いている。確かにactivating
状態のままであり、まともに立ち上がっていない。
$ systemctl status kubelet
## 結果
vagrant@kubeadm:/etc/containerd$ systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/lib/systemd/system/kubelet.service; enabled; vendor preset: enabled)
Drop-In: /usr/lib/systemd/system/kubelet.service.d
└─10-kubeadm.conf
Active: activating (auto-restart) (Result: exit-code) since Mon 2024-12-30 21:47:54 JST; 7s ago
Docs: https://kubernetes.io/docs/
Process: 14992 ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARG>
Main PID: 14992 (code=exited, status=1/FAILURE)
kubernetesクラスタの作成(Masterノード側)
事前準備
cgroup driverでsystemdを利用する宣言と、node-ipを設定する。
--node-ip
オプションをつけないとkubectl get node -o wide
で出力されるINTERNAL_IPがVagrantのNAT IP(10.2.0.15)が優先的に割り当てられる。
cat << EOF | sudo tee /etc/default/kubelet
KUBELET_EXTRA_ARGS=--cgroup-driver=systemd --node-ip=192.168.56.53
EOF
sudo systemctl daemon-reload
sudo systemctl restart kubelet
Masterノードのクラスタ作成
--apiserver-advertise-address
でクラスタ構成のIPを指定。--node-name
はノード名を変更したい場合のみに指定。指定しない場合はホスト名がノード名となる。
sudo kubeadm init --pod-network-cidr=172.16.0.0/16 --apiserver-advertise-address=192.168.56.53 --node-name=master
[出力結果]
sudo kubeadm init --pod-network-cidr=172.16.0.0/16 --apiserver-advertise-address=192.168.56.53 --node-name=master
I0102 10:54:02.171604 5513 version.go:261] remote version is much newer: v1.32.0; falling back to: stable-1.31
[init] Using Kubernetes version: v1.31.4
[preflight] Running pre-flight checks
[WARNING Hostname]: hostname "master" could not be reached
[WARNING Hostname]: hostname "master": lookup master on 127.0.0.53:53: server misbehaving
・・・
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.56.53:6443 --token z8vnl0.lugg1c3jvihk2dg6 \
--discovery-token-ca-cert-hash sha256:7c41629dc4f0ac5abaea5b1712dbb3264842ea71580203be607875367685599d
正常終了後の出力結果をそのまま実行
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
このタイミングでkubeletサービスが正常に起動される。
またkubeletサービスにcgroup driverでsystemd、node-ipが設定されていることがわかる。
# kubeletサービスがactive, オプションにsystemdとnode-ipの引数が設定されている
systemctl status kubelet
[出力(抜粋)]
● kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/lib/systemd/system/kubelet.service; enabled; vendor preset: enabled)
Drop-In: /usr/lib/systemd/system/kubelet.service.d
└─10-kubeadm.conf
Active: active (running) since Thu 2025-01-02 10:59:08 JST; 8min ago
Docs: https://kubernetes.io/docs/
Main PID: 6384 (kubelet)
Tasks: 11 (limit: 2274)
Memory: 33.5M
CGroup: /system.slice/kubelet.service
└─6384 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime-endpoint=unix:///var/run/containerd/containerd.sock --hostname-override=master --pod-infra-container-image=registry.k8s.io/pause:3.10 --cgroup-driver=systemd --node-ip=192.168.56.53
またノード名、INTERNAL_IPも正しく設定されている。nodeのSTATUSはNotReady
でよい。またcoredns以外のPodも正常に起動されているのがわかる。
corednsはインストールガイドによるとCNIプラグインをインストールするまでPending状態とのことなので問題なし。
$ kubectl get node -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
master NotReady control-plane 18m v1.31.4 192.168.56.53 <none> Ubuntu 20.04.4 LTS 5.4.0-110-generic containerd://1.7.24
# dns以外のpodは正常起動
$ kubectl get pod -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-7c65d6cfc9-jcfjb 0/1 Pending 0 19m
kube-system coredns-7c65d6cfc9-zjlgw 0/1 Pending 0 19m
kube-system etcd-master 1/1 Running 0 20m
kube-system kube-apiserver-master 1/1 Running 0 20m
kube-system kube-controller-manager-master 1/1 Running 0 20m
kube-system kube-proxy-tddbf 1/1 Running 0 20m
kube-system kube-scheduler-master 1/1 Running 0 20m
CNIプラグインのインストール
CNIプラグインのcalicoをインストールする。
基本的にインストールガイドの通りやるだけ。
Calicoオペレータを追加
# install Calico operator
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.29.1/manifests/tigera-operator.yaml
Calicoではcidrとして192.168.0.0/16
を使っている。これはVagrantと被るので、Masterノード作成時に指定した172.16.0.0/16
へ修正する。
# cidrを記載しているので、修正して適用するため一旦ダウンロード
curl -OL https://raw.githubusercontent.com/projectcalico/calico/v3.29.1/manifests/custom-resources.yaml
# cidrを修正
vi custom-resources.yaml
cidr: 192.168.0.0/16
↓
cidr: 172.16.0.0/16
# 修正したyamlファイルを適用しCalicoをインストール
kubectl apply -f ./custom-resources.yaml
# Podの正常起動を確認(全Podが起動するまで数分程度かかる)
kubectl get pod -A
[結果]
NAMESPACE NAME READY STATUS RESTARTS AGE
calico-apiserver calico-apiserver-697587c558-2ltzq 1/1 Running 0 2m2s
calico-apiserver calico-apiserver-697587c558-v5fkh 1/1 Running 0 2m2s
calico-system calico-kube-controllers-6dbdfd75fd-ccf42 1/1 Running 0 2m2s
calico-system calico-node-b45wn 1/1 Running 0 2m2s
calico-system calico-typha-7d7889b79-bdvhw 1/1 Running 0 2m2s
calico-system csi-node-driver-7fwr2 2/2 Running 0 2m2s
kube-system coredns-7c65d6cfc9-jcfjb 1/1 Running 0 56m
kube-system coredns-7c65d6cfc9-zjlgw 1/1 Running 0 56m
kube-system etcd-master 1/1 Running 0 56m
kube-system kube-apiserver-master 1/1 Running 0 56m
kube-system kube-controller-manager-master 1/1 Running 0 56m
kube-system kube-proxy-tddbf 1/1 Running 0 56m
kube-system kube-scheduler-master 1/1 Running 0 56m
tigera-operator tigera-operator-76c4976dd7-rk7qm 1/1 Running 0 2m44s
Masterノードのtaint削除
taint削除してPodのSchedulingを可能とする。
kubectl describe node master |grep -i taint
[結果]
Taints: node-role.kubernetes.io/control-plane:NoSchedule
kubectl taint nodes --all node-role.kubernetes.io/control-plane-
[結果]
node/master untainted
Masterノード、Podが正常に動作しているなら構築完了。
kubectl get node -o wide
kubectl get pod -A
Workerノードの構築
Container Runtimeのインストール(Workerノード)
containerdのインストールはMasterノードと同様のためそちらを参照
kubeadm, kubeletのインストール
Masterノードのインストール手順とほぼ同様。唯一の違いはkubectl設定がないだけ。手順だけ記載。
###
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
###
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.31/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
###
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.31/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
###
sudo apt-get update
sudo apt-get install -y kubelet kubeadm
sudo apt-mark hold kubelet kubeadm
###
sudo systemctl enable --now kubelet
systemctl status kubelet
kubernetesクラスタを作成(Workerノード側)
クラスタ作成での事前準備
Masterノード同様、cgroup driverでsystemdを利用する宣言と、node-ipを設定する。
ここで設定変更後、kubeletを再起動してもまだkubeletサービスは正しく起動していないので、kubeadm join
後に変更した方がいいかもしれないが未調査。
cat << EOF | sudo tee /etc/default/kubelet
KUBELET_EXTRA_ARGS=--cgroup-driver=systemd --node-ip=192.168.56.54
EOF
sudo systemctl daemon-reload
sudo systemctl restart kubelet
Workerノードのクラスタ作成
Masterノードインストール時に発行されたトークンは有効期限があるため、Tokenを再発行しておく。Masterノードで実行。
# Masterノードで実施すること!
sudo kubeadm token create --print-join-command
kube join
コマンドでMasterノードに参加する。これはWorkerノードで実施。
Masterノードで発行したTokenにアドバタイズするWorkerノード自身のIPアドレス192.168.56.54
を追加する。
sudo kubeadm join 192.168.56.53:6443 --token ae23nz.3z2wgkowa4egops7 --discovery-token-ca-cert-hash \
sha256:690a36f5e45e096d0e0a34bddceae0b6775cbec024cfb26cee0f8cea38ee084e \
--apiserver-advertise-address=192.168.56.54
Workerノードが作成されたことを確認
Workerノードで確認
まずはWorkerノードでkubeletサービス
が正しく起動され、node-ipが設定されていることを確認する
systemctl status kubelet
[結果(抜粋)]
...
Active: active (running) since Thu 2025-01-02 13:02:30 JST; 22min ago
...
CGroup: /system.slice/kubelet.service
└─12478 /usr/bin/kubelet (略) --cgroup-driver=systemd --node-ip=192.168.56.54
Masterノードで確認
続いてMasterノードにWorkerノードがクラスタに参加されたことを確認する。またINTERNAL_IPがVagrantのNAT IPでないことを確認する。
kubectl get node -o wide
[結果]
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
master Ready control-plane 155m v1.31.4 192.168.56.53 <none> Ubuntu 20.04.4 LTS 5.4.0-110-generic containerd://1.7.24
worker1 Ready <none> 27m v1.31.4 192.168.56.54 <none> Ubuntu 20.04.4 LTS 5.4.0-110-generic containerd://1.7.24
うまくいけば、同様の手順でWorkerノードを追加できる。
その他
ノードのリセット
kubeadm init
やkubeadm join
をやり直す
Masterノードのリセット
sudo kubeadm reset
rm -rf ~/.kube
Workerノードのリセット
Masterノードで実施、クラスタからWorkerノードを切り離す。
kubectl drain worker1 --ignore-daemonsets --force
kubectl delete node worker1
Workerノードで実施、Workerノードのリセット
sudo kubeadm reset
rm -rf ~/.kube
INTERNAL_IPの変更
INTERNAL_IPの変更手順:その1
/etc/default/kubelet
のKUBELET_EXTRA_ARGS
で指定したnode-ip
を変更しkubeletを再起動してもINTERNAL_IPに反映されない。
反映させる場合の手順は以下。
-
/etc/default/kubelet
からnode-ipを削除してkubelet再起動
→このタイミングでNATのIPがアドバタイズされている模様(INTERNAL_IPがNATのIPに変わる) - 再びnode-ipを設定してkubelet再起動
INTERNAL_IPの変更手順:その2
/etc/default/kubelet
にnode-ipを記載しないで、別のファイルに書いてもいいらしい。
sudo vi /lib/systemd/system/kubelet.service.d/10-kubeadm.conf
# KUBELET_CONFIG_ARGSにnode-ipを追加
Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml --node-ip=x.x.x.x"
# 再起動
sudo systemctl daemon-reload
sudo systemctl restart kubelet
まとめ
cgroup driverの設定部分がネットで調べていると迷子になってしまい、結果動いてはいるものの設定が設定不足の可能性あります。誤り等あればコメント頂けたらありがたいです。
これまでminikube使っていたけど、これだとクラスタ組めるのでノード停止時の動作とか色々検証できるはず(やる気があれば)