TT Lab
はじめる
学ぶ 学習パス コース

CKA — Kubernetes管理者

3ノード — join・drain・kubelet 復旧

TT Labで続きを見る

目標

ノード3台にsshで入ってkubeadmクラスターを組み立て、ワーカー1台を空にしてメンテナンスしたあと、再起動して戻ってこないもう1台のワーカーを復活させます。 CKAの実技が求める「複数のノードを行き来して作業する手」を、本物のVM3台で身につけます。

なぜ重要なのか

1台のクラスターでは、ノードが何なのか見えません。ノードが複数になった瞬間、3つのことが変わります。 1つ目、ノードのアドレスが問題になります。このラボの3つのVMは、最初のNICのアドレスがすべて10.0.2.2で、実際のクラスターネットワークは、2つ目のNIC(eth1)です。 kubeletの--node-ip、APIサーバーのadvertiseアドレス、CNIのトンネル用NICが、すべてeth1を指す必要があります。複数NICのサーバーでKubernetesを立ち上げるときに、実際に最も多く間違える箇所です。 2つ目、メンテナンスが生まれます。ノードを停止する前にPodを空にするdrainと、元に戻すuncordonは、運用の日常です。 3つ目、kubeletはPodではなく、systemdのサービスです。ノードがNotReadyのとき、kubectlでは原因に届かず、そのノードに入って、サービスを見る必要があります。

ステップ

  1. controlplaneでssh node01・ssh node02で各ノードに入り、hostnameとeth1のIPv4アドレスを確認してください。3つのノードを1行ずつ이름 주소の形式で、controlplane・node01・node02の順に書いてください(プレースホルダーは名前とアドレスです。保存先: /root/cluster/nodes.txt)。
  2. controlplaneで、kubeadm initを--kubernetes-version v1.36.4 --apiserver-advertise-address <controlplane 의 eth1 주소> --pod-network-cidr 172.20.0.0/16 --service-cidr 172.21.0.0/16で実行し(プレースホルダーはcontrolplaneのeth1アドレスです)、/etc/kubernetes/admin.confをコピーしてください(コピー先: /root/.kube/config)。controlplaneノードのInternalIPが、eth1のアドレスである必要があります。
  3. あらかじめ取得しておいたFlannel v0.28.9のマニフェストで(場所: /root/cluster/kube-flannel.yml)、net-conf.jsonのNetworkを172.20.0.0/16に変更し、kube-flannelコンテナのargsに--iface=eth1を追加して、適用してください。controlplaneがReadyになり、CoreDNSがAvailableである必要があります。
  4. controlplaneで参加コマンドを作成し(kubeadm token create --print-join-command)、node01とnode02で実行してください。3つのノードがすべてReadyで、node01・node02のInternalIPが、それぞれのeth1のアドレスである必要があります。
  5. defaultネームスペースにDeploymentwebを、イメージregistry.k8s.io/e2e-test-images/agnhost:2.53、コマンド/agnhost netexec --http-port=8080、レプリカ2で作成してください。2つのPodがワーカーでReadyで、controlplaneから各PodのIPの:8080/hostnameが、そのPod名を返す必要があります。
  6. node01をkubectl drainで空にして(DaemonSetのPodは残しておきます)、その出力の全体を保存してください(保存先: /root/cluster/drain.log)。node01にDaemonSetではないPodが1つもなく、webは2つのPodがどちらもReadyである必要があります。
  7. node02を再起動してください(ssh node02 reboot)。戻ってきたあと、node02がNotReadyのまま残る原因をnode02で見つけて直し、次の再起動でも自力で戻ってくるようにしてください。
  8. node01を再びスケジュール可能にしてください。3つのノードがすべてReadyでスケジュール可能で、Flannel DaemonSetが3つのノードで準備できており、webの2つのPodがReadyである必要があります。

参考

3つのノードに入って2つ目のNICを確認する

controlplaneでssh node01・ssh node02で各ノードに入り、hostnameとeth1のIPv4アドレスを確認してください。3つのノードを1行ずつ이름 주소の形式で、controlplane・node01・node02の順に書いてください(プレースホルダーは名前とアドレスです。保存先: /root/cluster/nodes.txt)。

ip -4 addrを見ると、NICが2つあります。最初のNIC(enp1s0)のアドレスが、3つのノードすべてで同じであることを確認してみてください。そのアドレスでは、ノードを区別できません。ssh node01 'ip -4 -o addr show eth1'のように、コマンドだけを送ってもかまいません。

eth1のアドレスでコントロールプレーンを立ち上げる

controlplaneで、kubeadm initを--kubernetes-version v1.36.4 --apiserver-advertise-address <controlplane 의 eth1 주소> --pod-network-cidr 172.20.0.0/16 --service-cidr 172.21.0.0/16で実行し(プレースホルダーはcontrolplaneのeth1アドレスです)、/etc/kubernetes/admin.confをコピーしてください(コピー先: /root/.kube/config)。controlplaneノードのInternalIPが、eth1のアドレスである必要があります。

advertiseアドレスを指定しないと、kubeadmはデフォルトのルートのNIC(10.0.2.2)を選びます。そうすると、ワーカーがそのアドレスでAPIサーバーを探しに行って、自分自身につながります。kubelet側のアドレスは、/etc/default/kubeletの--node-ipが決めます。すでに書かれているので、読んでみてください。

FlannelにどのNICでトンネルを作るかを教える

あらかじめ取得しておいたFlannel v0.28.9のマニフェストで(場所: /root/cluster/kube-flannel.yml)、net-conf.jsonのNetworkを172.20.0.0/16に変更し、kube-flannelコンテナのargsに--iface=eth1を追加して、適用してください。controlplaneがReadyになり、CoreDNSがAvailableである必要があります。

Flannelは、デフォルトのルートのNICでVXLANを作ります。そのNICのアドレスが3つのノードすべてで同じだと、トンネルの宛先がすべて自分自身になります。ノードはReadyなのに、ほかのノードのPodに届かない症状です。argsは、--kube-subnet-mgrの行の下に、同じインデントで1行追加します。

ワーカー2台を参加させる

controlplaneで参加コマンドを作成し(kubeadm token create --print-join-command)、node01とnode02で実行してください。3つのノードがすべてReadyで、node01・node02のInternalIPが、それぞれのeth1のアドレスである必要があります。

参加コマンドは、ワーカーでrootとして実行します。ssh node01 '<조인 명령>'です(プレースホルダーは参加コマンドです)。参加が終わっても、FlannelのPodがそのノードで起動するまで、Readyは少し遅れます。参加の出力のWARNINGの行も、読んでおいてください。あとで役に立ちます。

別のノードのPodに実際に届くかを見る

defaultネームスペースにDeploymentwebを、イメージregistry.k8s.io/e2e-test-images/agnhost:2.53、コマンド/agnhost netexec --http-port=8080、レプリカ2で作成してください。2つのPodがワーカーでReadyで、controlplaneから各PodのIPの:8080/hostnameが、そのPod名を返す必要があります。

kubectl create deployment web --image=… --replicas=2 -- /agnhost netexec --http-port=8080の1行で済みます。controlplaneにはcontrol-planeテイントがあるので、Podはワーカーにだけ行きます。curlが止まるなら、FlannelのNICから疑ってください。

node01をメンテナンスのために空にする

node01をkubectl drainで空にして(DaemonSetのPodは残しておきます)、その出力の全体を保存してください(保存先: /root/cluster/drain.log)。node01にDaemonSetではないPodが1つもなく、webは2つのPodがどちらもReadyである必要があります。

ドレインは、cordon(スケジュール禁止)+エビクションです。Flannel・kube-proxyのようなDaemonSetのPodは、エビクトしてもすぐ同じノードに再び作られるので、--ignore-daemonsetsでスキップします。エビクトされたwebのPodは、node02に移っていきます。出力は、2>&1 | teeで、画面とファイルの両方に残せばよいです。

再起動したnode02が戻ってこない

node02を再起動してください(ssh node02 reboot)。戻ってきたあと、node02がNotReadyのまま残る原因をnode02で見つけて直し、次の再起動でも自力で戻ってくるようにしてください。

ノードがNotReadyなら、そのノードのkubeletから見ます。systemctl status kubeletです。今起動しているか(active)と、起動時に有効になるか(enabled)は、別の質問です。参加したときに出たWARNINGを、覚えていますか。

メンテナンスを終えて元に戻す

node01を再びスケジュール可能にしてください。3つのノードがすべてReadyでスケジュール可能で、Flannel DaemonSetが3つのノードで準備できており、webの2つのPodがReadyである必要があります。

drainを元に戻すのは、uncordonです。元に戻しても、すでにnode02に移ったPodが、ひとりでに戻ってくることはありません。スケジューラーは、新しいPodを配置するときにだけ判断します。