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

Kubespray と Terraform でクラスターを構築する

Kubespray が直してくれるもの、知らないもの

TT Labで続きを見る

一言でいうと

kubesprayは、スワップ・モジュール・sysctlを自分で整えてくれますが、他人が占有しているポートと、あとから値を元に戻す設定ファイルは知りません。インストール前の点検は、その境界を知ることです。

なぜ必要なのか

kubesprayのインストールは、1回に数分かかります。その数分後に失敗した場合、原因はたいていインストール前にすでにあったものです。そして、そのような失敗は、エラーの文言が原因を指していません。別のプロセスが10250を占有していると、最初のkubeadm initがpreflightの[ERROR Port-10250]で止まります。ところがkubesprayは、最初の試行でkubeletがすでに起動した可能性があると考え、再試行でPort-10250を無視リストに入れてもう一度実行します(roles/kubernetes/control-plane/tasks/kubeadm-setup.yml)。すると、原因を述べている行はログの上のほうの最初の試行の出力にしか残らず、目に付く最後のエラーは、まったく別のことを言います。最初のリブートの後にPod同士の通信が切れるのに、kubesprayのログはすべて緑色です。こうしたことを、インストール後に逆向きに追跡するよりも、インストール前にホストが何を受け入れられるかを見るほうが、はるかに安上がりです。

どう動くのか

Kubernetesがノードに要求することは、公式ドキュメントに散らばっています。まとめると、4系統です。

스왑        kubelet 은 기본값(failSwapOn: true)으로 스왑이 켜져 있으면 시작을 거부한다
커널 모듈    overlay(containerd 의 기본 스냅샷터) · br_netfilter(브리지 트래픽이 iptables 를 거치게)
sysctl      net.ipv4.ip_forward = 1 · net.bridge.bridge-nf-call-iptables = 1
포트        6443(API) · 2379-2380(etcd) · 10250(kubelet) · 10257(controller-manager) · 10259(scheduler)

このコードブロックの韓国語の部分は、行の見出しがスワップ、カーネルモジュール、sysctl、ポートであること、スワップはkubeletがデフォルト値(failSwapOn: true)でスワップが有効だと起動を拒否すること、overlayはcontainerdのデフォルトのスナップショッターで、br_netfilterはブリッジのトラフィックがiptablesを通るようにするものであることを述べています。

kubesprayは、このうち最初の3つをロールで処理します。roles/kubernetes/preinstall/tasks/0010-swapoff.ymlは、fstabからスワップの行を削除し、swap.targetをマスク(mask)して再び有効にならないようにし、swapoff -aを呼び出します。このタスクはkubelet_fail_swap_onが真のときにだけ動き、デフォルトは真です。スワップを使いたいなら、この値を偽にして、kubeletがswapBehavior: LimitedSwapで起動するようにする道も開かれています。br_netfilterはnodeロールが読み込んで、/etc/modules-load.d/kubespray-br_netfilter.confとして残します。ip_forwardのような値は、sysctl_file_path(デフォルトは/etc/sysctl.d/99-sysctl.conf)に書きます。Ubuntuでは、このファイルが../sysctl.confを指すシンボリックリンクなので、kubesprayがリンクをたどって/etc/sysctl.confに書きますが(0080-system-configurations.yml)、起動時に読まれる位置は、やはり99-sysctl.confという名前の順序です。

ポートは違います。kubesprayには他人のプロセスを止めるタスクがなく、あってもいけません。何がポートを占有しているかは、そのサーバーの事情だからです。そのため、ポートは人が先に見ます。ss -ltnpがPIDを表示するので、そのPIDを起動したsystemdユニットを探して、停止してdisableする必要があります。プロセスだけを終了させても、Restart=alwaysのユニットが2秒で復活させます。

sysctlには、順序の落とし穴があります。起動時にsystemd-sysctlが、そして人がsysctl --systemを実行するときにprocpsが、/etc/sysctl.d・/run/sysctl.d・/usr/lib/sysctl.dの*.confをファイル名の順に読み取り、同じキーは、後に読んだ値が勝ちます。名前が同じなら、/etcのほうが勝ちます。そのため、k8s.confにip_forward = 1を書いても、zz-hardening.confが0を書いていると、今は1なのに、リブートすると0になります。kubesprayが使う99-sysctl.confも、同じルールの中にあります。数字は英字より前に並ぶので、名前が英字で始まるファイルは、すべてその後に読まれます。

最後に、kubespray自身の事前チェックがあります。0040-verify-settings.ymlは、Ansibleが集めたファクト(facts)で判定します。コントロールプレーンのノードのメモリがminimal_master_memory_mb(1500MB)より小さいと止まり、サポートしていないディストリビューションでも止まります。そしてip変数を指定しないと、ファクトのデフォルト経路のアドレス(default_ipv4)に、APIサーバーとetcdを結び付けます。インターフェースが複数あるサーバーで、見当違いのネットワークにコントロールプレーンが結び付く事故が、ここから起きます。

現場での姿

このモジュールのラボのVMには、3つの痕跡をわざと残してあります。どれも、実際によくある形です。1つ目、メモリが足りなかった頃に、誰かがスワップファイルを作ってfstabに書いておきました。2つ目、古い監視エージェントが10250でHTTPを受け付けています。kubeletと同じポートなので、インストール後にkubeletがbind: address already in useで再起動を繰り返すことになります。3つ目、セキュリティ点検が「ルーティング禁止」としてip_forwardを0にしたsysctlファイルを残しましたが、名前がzz-で始まるため、どのKubernetes設定よりも後に読まれます。

この3つのうち、kubesprayが自動で解決するのは、スワップだけです。ポートには手を付けず、sysctlはインストールの瞬間には値を有効にしますが、リブートのときにzz-ファイルが再び0に戻します。そのため、現場のチェックリストは、「何を設定したか」ではなく、「リブートの後もそうなのか」を問います。

次のラボですること

修正する前の状態を先に記録し、スワップを現在と起動時の両方で無効にします。モジュールを読み込んでsysctlを適用したうえで、zz-ファイルのせいでリブート時に値が戻ってしまうことを確認して修正します。10250を占有しているユニットを探して停止し、kubesprayが見るファクトを集めて最小メモリと比べます。最後に、ロールのコードを読んで、4つの問題を誰が解決するのかを見分けます。