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

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

cluster.yml を 2 回実行しても同じクラスター

TT Labで続きを見る

目標

用意されたインベントリでcluster.ymlを実行し、VM 1台(4 vCPU・4 GiB)にKubernetes 1.35.8を構築します。同じプレイブックをもう一度実行して、何が再び変わるかを確認し、値を1つ変更して、タグでその部分だけを再適用します。

なぜ重要なのか

kubesprayの運用方式は、「宣言を直して、同じプレイブックを再実行する」です。ノードを追加するときも、設定を変えるときも、同じcluster.ymlを実行します。 そのため、2回目の実行が何を変えるかを知っている必要があります。冪等という言葉はchangedが0という意味ではなく、毎回変わるタスクが何かを知っていて初めて、「今回の実行が意図したものだけを変えたか」を判断できます。長いプレイブックのログを末尾から読む方法(PLAY RECAPとTASKS RECAP)も、ここで身につけます。 このラボでは、インストール2回と部分実行1回で、合計約15分待ちます。セッションは60分なので、余裕が足りなければ延長してください。VMが終了すると、クラスターも消えます。

ステップ

  1. /opt/ks/kubesprayでansible-playbook -i /root/ks/inventory/lab/inventory.ini cluster.yml --list-tasksを実行してplayの一覧を見て、次のフィールドを数値で書いてください(書き込み先: /root/ks/install/plan.json)。play_count(playの個数)、etcd_play(「Install etcd」のplayの番号)、cni_play(「Invoke kubeadm and install a CNI」の番号)、apps_play(「Install Kubernetes apps」の番号)です。
  2. /opt/ks/kubesprayでansible-playbook -i /root/ks/inventory/lab/inventory.ini cluster.ymlを実行して、出力の全体を残してください(| teeまたはリダイレクト、保存先: /root/ks/logs/cluster-1.log)。約7分かかります。終わったら、PLAY RECAPのnode1がfailed=0で、kubectl get node node1がReadyである必要があります。
  3. 最初の実行について、次のフィールドを書いてください(書き込み先: /root/ks/install/run1.json)。ok、changed、failed(PLAY RECAPのnode1の値)、elapsed_sec(TASKS RECAPの見出しに出力された累積時間を秒で、整数)、slowest_task(TASKS RECAPの一覧の一番上のタスク名、ロールの接頭辞を含めてそのまま)、node_uid(kubectl get node node1のmetadata.uid)です。
  4. 同じコマンドをもう一度実行して、出力の全体を残してください(保存先: /root/ks/logs/cluster-2.log)。2回目もfailed=0である必要があり、ノードのUIDがステップ3で書いた値と同じである必要があります(クラスターを新しく作り直していないという意味です)。
  5. 2回目の実行でchanged: [node1]を出したタスクの名前を、ログのTASK [...](ハンドラーはRUNNING HANDLER [...])の括弧の中のまま(ロールの接頭辞を含む)、1行に1つずつ書いてください(書き込み先: /root/ks/install/changed.txt)。そして、2回目の実行のok、changed、failed、elapsed_secを書きます(書き込み先: /root/ks/install/run2.json)。
  6. containerd_max_container_log_line_size: 32768を追加し(追加先: /root/ks/inventory/lab/group_vars/all/containerd.yml)、cluster.yml --tags containerdでコンテナランタイムの部分だけをもう一度実行して、出力の全体を残してください(保存先: /root/ks/logs/containerd.log)。終わったら、/etc/containerd/config.tomlのmax_container_log_line_sizeが32768で、containerdが新しい設定で再び起動している必要があり、ノードは引き続きReadyである必要があります。
  7. 次のフィールドを書いてください(書き込み先: /root/ks/install/report.json)。kubespray(タグ)、server_version(APIサーバーのgitVersion)、first_run_sec、second_run_sec(2回の実行の累積時間、整数)、first_changed、second_changed、tags_run_changed(ステップ6の実行のchanged)、containerd_restarted(ステップ6でcontainerdが再び起動したか、ブール値)です。

参考

実行する前に順序を見る

/opt/ks/kubesprayでansible-playbook -i /root/ks/inventory/lab/inventory.ini cluster.yml --list-tasksを実行してplayの一覧を見て、次のフィールドを数値で書いてください(書き込み先: /root/ks/install/plan.json)。play_count(playの個数)、etcd_play(「Install etcd」のplayの番号)、cni_play(「Invoke kubeadm and install a CNI」の番号)、apps_play(「Install Kubernetes apps」の番号)です。

--list-tasksは、何も変更せずにプレイブックを展開して見せてくれます。出力のplay #N (호스트 패턴): 이름の行を見てください(プレースホルダーは番号、ホストパターン、名前です)。etcdがコントロールプレーンより、CNIがアドオンより先に来る理由を考えてみると、後で失敗した地点を読み取りやすくなります。

cluster.ymlを実行する

/opt/ks/kubesprayでansible-playbook -i /root/ks/inventory/lab/inventory.ini cluster.ymlを実行して、出力の全体を残してください(| teeまたはリダイレクト、保存先: /root/ks/logs/cluster-1.log)。約7分かかります。終わったら、PLAY RECAPのnode1がfailed=0で、kubectl get node node1がReadyである必要があります。

コンソールが切れると、プレイブックも一緒に終了することがあります。systemd-run --unit=<이름> --setenv=HOME=/root ...やtmuxで起動すれば(プレースホルダーはユニット名です)、ターミナルと無関係に動き、tail -fで見守れます。HOMEが空だと、kubesprayのkubeモジュールがkubeconfigを見つけられず、localhost:8080に向かいます。ログの途中の...ignoringが付いたfatalは、正常です。

ログの末尾で読み取るもの

最初の実行について、次のフィールドを書いてください(書き込み先: /root/ks/install/run1.json)。ok、changed、failed(PLAY RECAPのnode1の値)、elapsed_sec(TASKS RECAPの見出しに出力された累積時間を秒で、整数)、slowest_task(TASKS RECAPの一覧の一番上のタスク名、ロールの接頭辞を含めてそのまま)、node_uid(kubectl get node node1のmetadata.uid)です。

ansible.cfgが有効にしているprofile_tasksコールバックが、ログの末尾にTASKS RECAPを付けます。最初の行の最後の時間が全体の累積時間で、下の一覧が時間のかかった順です。ノードのUIDは、次のステップで「再実行しても同じノードか」を確認する基準になります。

もう一度実行する

同じコマンドをもう一度実行して、出力の全体を残してください(保存先: /root/ks/logs/cluster-2.log)。2回目もfailed=0である必要があり、ノードのUIDがステップ3で書いた値と同じである必要があります(クラスターを新しく作り直していないという意味です)。

kubesprayは、すでに構築したクラスターにcluster.ymlを再実行しても問題ないように作られています。ノードを追加するときや設定を変えるときに、同じプレイブックを再実行するのが、基本の運用方法です。2回目の実行は、ダウンロードするものがキャッシュにあるので、1回目より速いです。

冪等なのにchangedが0ではない

2回目の実行でchanged: [node1]を出したタスクの名前を、ログのTASK [...](ハンドラーはRUNNING HANDLER [...])の括弧の中のまま(ロールの接頭辞を含む)、1行に1つずつ書いてください(書き込み先: /root/ks/install/changed.txt)。そして、2回目の実行のok、changed、failed、elapsed_secを書きます(書き込み先: /root/ks/install/run2.json)。

冪等(idempotent)は「何回実行しても結果の状態が同じ」という意味であり、「どのタスクもchangedを出さない」という意味ではありません。毎回何かを実行するcommandやshellのタスクや、値を比較せずに書き直すタスクが、changedを出します。ログでchanged: [node1]の行のすぐ上にある、最も近いTASK(またはRUNNING HANDLER)の見出しが、そのタスクです。

値を1つ変えて、その部分だけをもう一度

containerd_max_container_log_line_size: 32768を追加し(追加先: /root/ks/inventory/lab/group_vars/all/containerd.yml)、cluster.yml --tags containerdでコンテナランタイムの部分だけをもう一度実行して、出力の全体を残してください(保存先: /root/ks/logs/containerd.log)。終わったら、/etc/containerd/config.tomlのmax_container_log_line_sizeが32768で、containerdが新しい設定で再び起動している必要があり、ノードは引き続きReadyである必要があります。

タグを指定すると、そのタグが付いたタスク(とalwaysタグの準備タスク)だけが動きます。どんなタグがあるかは、kubesprayのドキュメントのタグの表や--list-tagsで見ます。設定ファイルだけが変わってデーモンが再び起動しないと、古い値のまま動き続けます。ロールのハンドラーが再起動を担当します。ドキュメントが警告するように、タグは、何が動くかを確実に知っているときにだけ使います。

インストールのレポート

次のフィールドを書いてください(書き込み先: /root/ks/install/report.json)。kubespray(タグ)、server_version(APIサーバーのgitVersion)、first_run_sec、second_run_sec(2回の実行の累積時間、整数)、first_changed、second_changed、tags_run_changed(ステップ6の実行のchanged)、containerd_restarted(ステップ6でcontainerdが再び起動したか、ブール値)です。

前のステップの記録と3つのログ、そして現在のクラスターから、すべて再計算できる値です。採点ツールも、同じところから再計算して照合します。containerdが再び起動したかどうかは、containerd.logで再起動ハンドラーがchangedと出力されたかどうかで判断します。