Kubespray と Terraform でクラスターを構築する
ネットワークプラグインを選ぶ理由、アドオンを有効にした後に確かめること
一言でいうと
kubesprayのアドオンとネットワークプラグインは、group_varsのスイッチです。スイッチを有効にしたことと、それが動作することは、別に確認する必要があります。ネットワークプラグインだけは、あとから変更するのが難しいので、インストール前に理由を持って選びます。
なぜ必要なのか
kubeadmは、CNIも、metrics-serverも、ストレージも選びません。人がマニフェストを探してバージョンを合わせて適用する必要があり、そのバージョンがクラスターのバージョンと合うかどうかも、人が見ます。kubesprayは、これを変数にまとめました。kube_network_plugin: calicoの1行がcalicoのCRD・DaemonSet・IPプールを作り、metrics_server_enabled: trueの1行がmetrics-serverとAPIServiceを作ります。バージョンとイメージのアドレスは、kubesprayのリリースが固定しているので、同じインベントリはいつ実行しても、同じアドオンをインストールします。その代わり、有効にしたという事実だけが残り、動作を確認する作業は、依然として人の担当です。
どう動くのか
ネットワークプラグイン。group_vars/k8s_cluster/k8s-cluster.ymlのkube_network_pluginが選びます。サンプルのコメントが挙げている選択肢は、cilium、calico、kube-ovn、flannel、そして自分でインストールするときに使うcni(プラグインのバイナリだけを展開し、設定は空にしておく)とnoneです。デフォルトはcalicoで、v2.32.0のcalicoのデフォルトはcalico_vxlan_mode: Always、calico_ipip_mode: Neverです。つまり、ノード間のPodのトラフィックをVXLAN(UDP 4789)で包みます。
選ぶ理由は、たいてい3つです。1つ目はNetworkPolicyです。flannelはPodネットワークだけを提供してポリシーを強制しないので、ポリシーが必要ならcalicoかciliumです。2つ目はネットワーク条件です。IPIPはIPプロトコル4を、VXLANはUDP 4789を、BGPモードはTCP 179を、ノード間で通す必要があります。kubesprayのポートのドキュメントが、CNIごとにこの表を別に置いている理由です。3つ目は運用負担です。ciliumはeBPFでkube-proxyの代わりをしてオブザーバビリティ(Hubble)まで提供しますが、カーネルのバージョンと設定項目が増えます。どちらの場合も、インストール後に変更することは、事実上の再インストールです。PodのIPのCIDR範囲とノードのルーティングが、プラグインに結び付いているからです。
アドオン。group_vars/k8s_cluster/addons.ymlにまとまっていて、サンプルではすべてfalseです。このモジュールで有効にする3つは、次のとおりです。
metrics_server_enabled kubectl top · HPA 의 자원 지표. aggregation layer 로 API 서버에 붙는다
local_path_provisioner_enabled 노드 디스크(/opt/local-path-provisioner/)를 PV 로 주는 동적 프로비저너
helm_enabled helm 바이너리를 체크섬으로 고정한 판으로 /usr/local/bin 에 둔다
このコードブロックの韓国語の部分は、metrics_server_enabledはkubectl topとHPAのリソースメトリクスで、aggregation layerでAPIサーバーに接続されること、local_path_provisioner_enabledはノードのディスク(/opt/local-path-provisioner/)をPVとして渡す動的プロビジョナーであること、helm_enabledはhelmバイナリをチェックサムで固定したバージョンで/usr/local/binに置くことを述べています。
アドオンは、cluster.ymlの最後のplayである「Install Kubernetes apps」でインストールされ、各ロールにタグ(metrics_serverなど)があるので、すでに構築したクラスターでその部分だけを再実行することもできます。
ブール値の落とし穴。ansible-core 2.19(Ansible 12)から、条件式は必ずブール値である必要があります。ところが-e helm_enabled=trueは、文字列の"true"を渡します。kubesprayは、いくつかのよく知られたスイッチを、validate_inventoryの「Stop if known booleans are set as strings」で止めますが、実測すると、この検査が見るのは、download_run_once・download_always_pull・helm_enabled・openstack_lbaas_enabledの4つだけです。残りのスイッチを文字列で渡すと、その検査には引っかからず、条件式が使われる場所で別に問題になります。リリースノートが勧めるとおり、-e '{"helm_enabled": true}'のようにJSONで渡すか、引用符のないYAMLのブール値としてインベントリに書くのが正解です。
現場での姿
metrics-serverを有効にしてあるのに「HPAが増えない」という問い合わせを受けることは、よくあります。確認の順序は、APIServiceのAvailable条件 → metrics-serverのログ → kubeletへの接続です。kubesprayのデフォルト値metrics_server_kubelet_insecure_tls: trueは、metrics-serverがkubeletのサービング証明書を検証しないという意味です。シングルノードのラボでは楽ですが、本番では、kubeletのサービング証明書を適切に発行して(kubelet_rotate_server_certificates)、この値を無効にする方向を検討する必要があります。有効にしやすいデフォルト値には、たいていこのような取引が隠れています。
local-path-provisionerは、PVCを使うPodがスケジュールされるとき、そのノードのディスクにディレクトリを作ってくれます。便利ですが、データがノードに結び付くので、ノードがなくなればデータもなくなります。ラボ用やキャッシュ用にはよいですが、レプリケーションが必要なデータには合いません。
次のラボですること
addons.ymlで3つのアドオンを有効にして、-e key=valueとJSON形式が、boilerplateの検査でどのように異なって解釈されるかを確認します。インストールしたあと、kubectl topとAPIService、PVCがノードのディスクに結び付く様子、kubesprayがインストールしたHelmで作ったリリースを順に確認し、calicoのIPプールでカプセル化の方式を読み取ります。