Docker Compose版k3sについては以下
タイトル通りの操作を行うと後処理が必要になるため、情報整理してみた。
なお、上記の記事を書いた当時と比較してagentノード用のボリュームも定義される修正がcomposeファイルに追加されている。
(おそらくv1.29.4以降)
(serverノードは元々ボリューム設定はあった)
docker composeのdown/upの動作おさらい
docker compose down: コンテナの停止+削除docker compose up: コンテナの作成+起動
downによってボリュームで永続化していないファイルシステム領域はコンテナ再作成によって消える。
down -vだとボリュームも消える。
down/upするとどうなる?
serverノードで永続化されているボリューム内にクラスター情報は保存されている。
サンプルのComposeファイルの場合、server/agentノードのノード名は明示的に設定されていないため、この場合デフォルトとしてはコンテナIDがノード名として使用される。
よって、downによって既存のノードコンテナが削除され、upによって新規にノードコンテナが作成される際は、コンテナIDであるノード名は異なっており、また、永続されている領域は /var/lib/rancher/k3sのため、クラスターに参加するために使用するノードパスワードである /etc/rancher/node/password も異なるものになる。
そのため、K3sのKubernetesクラスターから見ると、「downによって削除されたノードコンテナは行方不明(一定時間経過後にNotReadyに遷移)になり、upによって作成されたノードコンテナは新しいノードとして登録される」と認識される。
正しい状態にするには?
downによって削除されたノードコンテナはすでに存在しないため、NotReadyになったノードをkubectl delete nodeで削除すれば良い。
なお、登録されたノードのパスワードはkube-systemネームスペースのsecretリソースとして登録されているが、このリソースはノード削除によって自動的に消える。(<host>.node-password.k3sの書式でリソース名にノード名が付与されている)
回避策
前述の通りdown/upで消えたノードを削除すれば基本的に良いけど、down/upの操作を運用に組み込んだりした場合、ノード削除を都度実行するのも面倒だよね、ということで回避策について検討してみた。
ポイントは下記2点
- ノード名の固定
- ノードパスワードの固定
ノード名の固定については以下に情報があった。しかし手元で試してみてもノード名固定だけだとうまくいかない。いろいろ検証した結果ノードパスワードの保持も必要だと判断。
ノード名のみ固定してもノードパスワード情報を維持しなかった場合は「名前は同じだが中身が異なるノード」のように認識されるため、以下のeventが記録されノードはNotReadyになる。
2m13s Warning NodePasswordValidationFailed node/server Deferred node password secret validation failed: unable to verify password for node server: hash does not match 86s Normal NodeNotReady node/agent Node agent status is now: NodeNotReady
ノード名の固定
k3sの起動オプションに--node-nameがあるのでそれを使用。
ただノードのホスト名が未指定だとコンテナIDが使用され、この不一致で正しく動作しないため、Compsoeの書式としてhostnameも指定する。
まとめると最小限の設定としては以下。
(agentの定義はデフォルトではcommandが無いので、行ごと追加)
services: server: hostname: server command: server --node-name server # 中略 agent: hostname: agent command: agent --node-name agent
ちなみに試した限り、hostnameがあれば--node-nameは(未指定だとホスト名が使われるため)無くても動作した。
ノードパスワードの固定
/etc/rancher領域をボリューム指定する。
まとめると以下の通り。
services: server: volumes: - k3s-server:/var/lib/rancher/k3s - k3s-server-etc:/etc/rancher # 中略 agent: volumes: - k3s-agent:/var/lib/rancher/k3s - k3s-agent-etc:/etc/rancher volumes: k3s-server: {} k3s-agent: {} k3s-server-etc: {} k3s-agent-etc: {}
この定義内容であれば、down/upでコンテナを再作成しても「同一ノードとして認識」されるための情報は維持されるため、ノードのdelete操作は必要なくなる。
まとめ
K3sが接続されたノードを以前のものと同一と見なすかは、ノード名とノードパスワードを参照する。
今回はコンテナ版での検証だったが、K3sは基本この動作になると思われる。
よって、複数VMでマルチノードクラスターを組んでる場合にノードを交換するような場合も同様の動作・処置が必要になる。特にVMのホスト名が同じだと一致判定が中途半端になり、正しい状態にならないため注意が必要。
(おそらくホスト名が同じでもノード名にランダム性を持たせるために起動引数に --with-node-id があり、VM名にsuffixとしてランダム(?)なIDを追加する設定ができるようになっている)
エージェントは、ノードクラスターシークレットと、
/etc/rancher/node/passwordに保存されるランダムに生成されたパスワードを使用してサーバーに登録されます。サーバーは個々のノードのパスワードをKubernetesシークレットとして保存し、後続の試行では同じパスワードを使用する必要があります。ノードパスワードシークレットは、<host>.node-password.k3sテンプレートを使用した名前でkube-systemネームスペースに保存されます。これはノードIDの整合性を保護するために行われます。.
エージェントの
/etc/rancher/nodeディレクトリが削除された場合、または既存の名前を使用してノードを再参加させたい場合は、クラスターからノードを削除する必要があります。これにより、古いノードエントリとノードパスワードシークレットの両方がクリーンアップされ、ノードがクラスターに再参加できるようになります。.
ホスト名を頻繁に再利用するが、ノードパスワードシークレットを削除できない場合は、
--with-node-idフラグを使用してK3sサーバーまたはエージェントを起動することで、ホスト名に一意のノードIDを自動的に追加できます。有効にすると、ノードIDも/etc/rancher/node/に保存されます。