Kubespray と Terraform でクラスターを構築する
アドオンは group_vars のスイッチ。有効にしたら動作を確かめる
目標
インストール前にgroup_varsでmetrics-server・local-path-provisioner・Helmを有効にし、インストール後にそれぞれが実際に動作するかを確認します。-eがブール値を文字列として渡す落とし穴と、デフォルトのネットワークプラグインのcalicoがどんなカプセル化で動いているかも見ます。
なぜ重要なのか
kubesprayでは、アドオンは変数1つです。そのため、有効にするのは簡単で、有効にしたという事実と動作するという事実が、混ざりやすいです。metrics-serverは起動していても、APIServiceがAvailableでなければHPAが止まり、StorageClassはあってもPVCがノードのディスクに結び付かなければ、ステートフルなアプリが起動しません。 ネットワークプラグインは、インストール後に変更するのが最も難しい選択なので、何がデフォルトで、そのデフォルトがどんなネットワーク条件を要求するかを知って選ぶ必要があります。
ステップ
metrics_server_enabled、local_path_provisioner_enabled、helm_enabledを、すべてtrueに変更してください(対象:/root/ks/inventory/lab/group_vars/k8s_cluster/addons.yml)。ansible-inventory --host node1で展開したとき、3つの値が文字列ではなくブール値のtrueである必要があります。/opt/ks/kubesprayで、ansible-playbook -i /root/ks/inventory/lab/inventory.ini playbooks/boilerplate.yml -e helm_enabled=trueと-e '{"helm_enabled": true}'をそれぞれ実行してみてください。次のフィールドを書いてください(書き込み先:/root/ks/addons/string-trap.json)。kv_failed_task(最初のコマンドが失敗したタスク名、ロールの接頭辞なし)、kv_type(最初のコマンドでhelm_enabledになった型:"str"または"bool")、json_passed(2番目のコマンドがfailed=0で終わったか、ブール値)です。/opt/ks/kubesprayでansible-playbook -i /root/ks/inventory/lab/inventory.ini cluster.ymlを実行して、出力の全体を残してください(約8分、保存先:/root/ks/logs/cluster-1.log)。PLAY RECAPのnode1がfailed=0である必要があります。kubectl top nodeがnode1のCPUとメモリを表示するまで待ってから、次のフィールドを書いてください(書き込み先:/root/ks/addons/metrics.json)。apiservice_available(APIServicev1beta1.metrics.k8s.ioのAvailable条件のstatus)、image(metrics-server Deploymentのコンテナイメージ)、insecure_tls(metrics-serverが--kubelet-insecure-tls引数で起動しているか、ブール値)です。- defaultネームスペースにPVC
data(storageClassNameはlocal-path、64Mi、ReadWriteOnce)と、それを/dataにマウントしたPodwriter(イメージはbusybox:latest、コマンドはsh -c 'echo kubespray > /data/hello.txt && sleep 3600')を作成してください。PVCがBoundになり、ノードのlocal-pathのストレージパスの下のそのボリュームのディレクトリに、hello.txtがkubesprayとしてある必要があります。 helm create /root/ks/addons/demoでチャートを作成し、helm install demo /root/ks/addons/demo -n demo --create-namespace --waitでインストールしてください。リリースdemoがdeployedで、PodがReadyである必要があります。次のフィールドを書いてください(書き込み先:/root/ks/addons/helm.json)。helm_version(helm version --template '{{.Version}}')、kubespray_helm_version(このkubesprayのバージョンのデフォルトのhelm_version、先頭にvを付けて)です。- 次のフィールドを書いてください(書き込み先:
/root/ks/addons/cni.json)。plugin(インベントリが展開したkube_network_plugin)、calico_version(calico-node DaemonSetのcalico-nodeコンテナのイメージタグ)、vxlan_mode、ipip_mode(calicoctl.sh get ippool default-pool -o jsonのspecの値)、pool_cidr(そのIPプールのcidr)です。
参考
- kubespray v2.32.0が
/opt/ks/kubesprayに、インベントリが/root/ks/inventory/lab/inventory.ini(kube_version 1.35.8)に用意されています。インストールは、ステップ3で自分で行います。 - アドオンのイメージは、registry.k8s.ioとdocker.ioから取得します。このVMは、パブリックの80と443で外へ出られます。
- よくあるミス: addons.ymlに
"true"のように引用符を付けることです。ある変数はvalidate_inventoryが止め、ある変数は、条件式で静かに異なって解釈されます。 - よくあるミス: kubectl topが最初の数十秒失敗するのを見て、metrics-serverをインストールし直すことです。最初の収集周期を待ってください。
- ドキュメント: Kubespray: CNIの選択(k8s-cluster.yml)・Kubespray: Calico・Kubernetes: Resource metrics pipeline
アドオンはインストール前に選ぶ
metrics_server_enabled、local_path_provisioner_enabled、helm_enabledを、すべてtrueに変更してください(対象: /root/ks/inventory/lab/group_vars/k8s_cluster/addons.yml)。ansible-inventory --host node1で展開したとき、3つの値が文字列ではなくブール値のtrueである必要があります。
サンプルのaddons.ymlには、3行がfalseで書かれています。YAMLでは、引用符のないtrueはブール値で、"true"は文字列です。ansible-inventoryのJSON出力では、両者はtrueと"true"で区別されます。
-eは文字列を渡す
/opt/ks/kubesprayで、ansible-playbook -i /root/ks/inventory/lab/inventory.ini playbooks/boilerplate.yml -e helm_enabled=trueと-e '{"helm_enabled": true}'をそれぞれ実行してみてください。次のフィールドを書いてください(書き込み先: /root/ks/addons/string-trap.json)。kv_failed_task(最初のコマンドが失敗したタスク名、ロールの接頭辞なし)、kv_type(最初のコマンドでhelm_enabledになった型: "str"または"bool")、json_passed(2番目のコマンドがfailed=0で終わったか、ブール値)です。
ansible-core 2.19から、条件式は必ずブール値である必要があり、-e key=valueは常に文字列を渡します。kubesprayは、いくつかの知られたブール値を、validate_inventoryで型として検査します。型は、ansible -i ... node1 -m debug -a 'msg={{{{ helm_enabled | type_debug }}}}' -e helm_enabled=trueで見られます。
アドオンと一緒に構築する
/opt/ks/kubesprayでansible-playbook -i /root/ks/inventory/lab/inventory.ini cluster.ymlを実行して、出力の全体を残してください(約8分、保存先: /root/ks/logs/cluster-1.log)。PLAY RECAPのnode1がfailed=0である必要があります。
アドオンは、cluster.ymlの最後のplay(Install Kubernetes apps)でインストールされます。すでに構築したクラスターなら、group_varsを変えた後に--tags appsやアドオンのタグ(metrics_serverなど)で、その部分だけを再実行することもできますが、ここでは最初から有効にして構築します。コンソールが切れても動き続けるように、systemd-runやtmuxで起動してください。
metrics-serverは本当に数値を出すか
kubectl top nodeがnode1のCPUとメモリを表示するまで待ってから、次のフィールドを書いてください(書き込み先: /root/ks/addons/metrics.json)。apiservice_available(APIServicev1beta1.metrics.k8s.ioのAvailable条件のstatus)、image(metrics-server Deploymentのコンテナイメージ)、insecure_tls(metrics-serverが--kubelet-insecure-tls引数で起動しているか、ブール値)です。
metrics-serverは、aggregation layerでAPIサーバーに接続されます。APIServiceがAvailableでなければ、kubectl topは「Metrics API not available」で失敗します。最初の数値が出るまでに数十秒かかります。kubesprayのデフォルト値(metrics_server_kubelet_insecure_tls: true)は、kubeletのサービング証明書を検証しないという意味なので、本番では、kubeletのサービング証明書を適切に発行する方向を検討する必要があります。
PVCがノードのディスクに結び付く
defaultネームスペースにPVCdata(storageClassNameはlocal-path、64Mi、ReadWriteOnce)と、それを/dataにマウントしたPodwriter(イメージはbusybox:latest、コマンドはsh -c 'echo kubespray > /data/hello.txt && sleep 3600')を作成してください。PVCがBoundになり、ノードのlocal-pathのストレージパスの下のそのボリュームのディレクトリに、hello.txtがkubesprayとしてある必要があります。
local-path-provisionerは、PVCを使うPodがスケジュールされるとき(WaitForFirstConsumer)、ノードのディスクにディレクトリを作ってPVとして渡します。PVのspec.hostPath.pathやspec.local.pathが、そのディレクトリです。busyboxはlocal-pathが使うヘルパーイメージなので、kubesprayがすでに取得してあります。
kubesprayがインストールしたHelmでリリースを1つ
helm create /root/ks/addons/demoでチャートを作成し、helm install demo /root/ks/addons/demo -n demo --create-namespace --waitでインストールしてください。リリースdemoがdeployedで、PodがReadyである必要があります。次のフィールドを書いてください(書き込み先: /root/ks/addons/helm.json)。helm_version(helm version --template '{{.Version}}')、kubespray_helm_version(このkubesprayのバージョンのデフォルトのhelm_version、先頭にvを付けて)です。
kubesprayのHelmは、get.helm.shからチェックサムで固定したバージョンを取得して、/usr/local/bin/helmに置きます。デフォルトのバージョンは、roles/kubespray_defaults/vars/main/checksums.ymlのhelm_archive_checksumsの最初のキーです。helm createが作ったチャートは、docker.ioのnginxイメージを使います。
calicoはどのように動いているか
次のフィールドを書いてください(書き込み先: /root/ks/addons/cni.json)。plugin(インベントリが展開したkube_network_plugin)、calico_version(calico-node DaemonSetのcalico-nodeコンテナのイメージタグ)、vxlan_mode、ipip_mode(calicoctl.sh get ippool default-pool -o jsonのspecの値)、pool_cidr(そのIPプールのcidr)です。
kubesprayは、calicoctlを/usr/local/bin/calicoctl.shとしてラップしてあります。デフォルトのIPプールは、kube_pods_subnetから作られ、カプセル化は、calico_vxlan_modeとcalico_ipip_modeの変数で決まります。VXLANはノード間のL3だけが通じればよく、IPIPはIPプロトコル4を通す必要があります。クラウドのファイアウォールが、判断を分けるポイントです。