Kubernetesディストリビューション — 自分で立てる
k0s の設定の正はどこにあるのか
一言でいうと
k0sのクラスター設定は、静的構成なら各コントローラーのファイル、動的構成ならAPI内のClusterConfigオブジェクトにあります。どちらのモードかを知らずにファイルを直すと、「直したのに何も起きない」ことになります。
なぜ必要なのか
k0sは、バイナリ1つとk0s.yaml1つでクラスターを構築できると紹介されています。そのため、運用者は設定を変更するとき、自然に/etc/k0s/k0s.yamlを開きます。ここで2つの事故が起きます。
1つ目、デフォルトの静的構成では、k0sはファイルを監視しません。構成のドキュメントは、実行中にファイルを変更することはできますが、反映するにはk0sを再起動するよう書いています。コントローラーが複数台あるなら、すべてのコントローラーのファイルを同じに揃えて、全部を再起動する必要があります。1台だけ直して忘れると、次にそのノードが再起動されたときに初めて設定が変わり、コントローラー同士が異なる設定を持つことになります。
2つ目、この不便をなくそうと動的構成(--enable-dynamic-config)を有効にすると、逆方向の落とし穴が生まれます。動的構成のドキュメントによると、クラスターを最初に作るとき、最初のコントローラーがファイルをブートストラップ値として1回だけ読み取ってAPIに保存し、その後はAPI内のオブジェクトがすべてのコントローラーにとって信頼できる情報源になります。これ以降、ファイルのクラスターレベルの設定は、直して再起動しても無視されます。
どう動くのか
設定ファイルは一部だけ書いてもよい
k0s config createは、デフォルト値がすべて埋まった設定を出力します。ただしk0sは部分的な設定を受け取って、足りない値をデフォルト値で埋めるので、実際のファイルには変更したいものだけを書いておくほうが読みやすいです。デフォルト値を見る理由は、「自分が書かなかった値が何に決まるのか」を知るためです。このラボのVMでのデフォルトの出力は、PodのCIDR範囲が10.244.0.0/16、ServiceのCIDR範囲が10.96.0.0/12、データストアがetcd、telemetryが有効でした。このVMはKubernetesの上で動いているため、デフォルトのCIDR範囲がホストクラスターと重なってしまい、ファイルで172.20と172.21に変更してあります。
k0s sysinfoは、同じバイナリがインストール前に実行する事前チェックです。メモリ、/var/lib/k0sのファイルシステムと空き容量、cgroupのバージョンとコントローラー、カーネル設定を項目ごとにpassとwarningで表示し、-o jsonで機械が読める形にもできます。
クラスター設定とノード設定は異なる
動的構成でも、ファイルがすべて無視されるわけではありません。ドキュメントは、spec.api(そのノードのAPIサーバー)、spec.storage(そのノードのetcdまたはSQLite)、spec.network.controlPlaneLoadBalancingをノードごとの設定に分類して、引き続きファイルから読み取ると説明しています。APIサーバーとデータストアが起動しなければオブジェクトを読めないので、当然の設計です。また、network.podCIDR、serviceCIDR、providerなどは、クラスターを作った後に変更できない項目なので、手動インストールのときにファイルに必ず書く必要があるとのことです。
そのほかのクラスターレベルの設定(ワーカープロファイル、kube-routerやkube-proxyの設定、Helm拡張など)は、kube-systemネームスペースのclusterconfig/k0sオブジェクトが決めます。コントローラーはOperator方式でこのオブジェクトを見守り、変更があれば関連するリソースを作り直して、結果をイベントとして残します。k0s config statusが、そのイベント(SuccessfulReconcile、FailedReconciling)を表示します。
정적 구성 파일 수정 ──(재시작해야)──▶ 반영
동적 구성 파일 수정 ──(재시작해도)──▶ 클러스터 수준 설정은 무시
ClusterConfig 수정 ──(즉시)──▶ 반영, 이벤트 기록
このコードブロックの韓国語の部分は、静的構成ではファイルを変更して再起動すると反映されること、動的構成ではファイルを変更して再起動してもクラスターレベルの設定は無視されること、ClusterConfigを変更するとすぐに反映されてイベントが記録されることを述べています。
ワーカープロファイルはConfigMapとして現れる
ワーカーノード構成のドキュメントのワーカープロファイル(spec.workerProfiles)は、kubeletの設定を上書きするまとまりです。k0sはプロファイルごとにConfigMapを作り、ワーカーは--profileで選んだConfigMapを起動時に読み取ります。実測では、名前がworker-config-<프로필>-1.36のようにKubernetesのマイナーバージョンが付きました(プレースホルダーはプロファイル名です)。そのため、設定が反映されたかどうかを、このConfigMapの存在とkubeletConfiguration内の値で、目に見える形で確認できます。
Helm拡張はChartオブジェクトを作る
Helmチャートのドキュメントは、2つの方法を説明しています。Chartオブジェクトを直接作る方法(推奨)と、spec.extensions.helmにリポジトリとチャートを宣言すると、k0sがChartオブジェクトに変換してくれる方法です。リポジトリはindex.yamlがある正式なHelmリポジトリである必要があり、Chartが削除されると、k0sがリリースを削除します。実測では、宣言で作られたChartの名前はk0s-addon-chart-<차트 이름>で(プレースホルダーはチャート名です)、削除用のfinalizerが付いていました。
現場での姿
実測で見た場面を書き写します(k0s v1.36.4+k0s.0)。
- 静的構成でファイルにワーカープロファイルを入れて45秒待ってもConfigMapはできず、
k0s stopとk0s startの後、17秒でできました。 - すでにインストールされているコントローラーに
k0s install controller --enable-dynamic-configをもう一度実行すると、「Init already exists」で拒否され、--forceが必要でした。 - 動的構成に切り替えた後に作られたClusterConfigは、ファイルのワーカープロファイルを持っていましたが、
spec.network.serviceCIDRが10.96.0.0/12と表示されていました。実際のAPIサーバーの--service-cluster-ip-rangeとkube-dnsのアドレスは、ファイルのとおり172.21でした。変更できない項目は、オブジェクトに表示されている値を信じず、実際のコンポーネントで確認する必要があります。 - 動的構成でファイルにプロファイルを追加して再起動までしても、オブジェクトの
generationはそのままで、ConfigMapもありませんでした。オブジェクトをpatchすると、1秒以内にできました。 - オブジェクトの
workerProfilesをmerge patchで新しいリストだけを入れて送ると、リストが丸ごと置き換わり、抜けたプロファイルのConfigMapがすぐに削除されました。リストに追加するときは、JSON patchのaddを使います。 - 宣言はそのままにして、Chartオブジェクトだけを
kubectl deleteするとリリースがすぐに削除されましたが、99秒待っても、ClusterConfigをもう一度直しても復活せず、k0sを再起動した後にようやく再び作られました。宣言と実際が、静かにずれることがあるという意味です。
実務で本当に大切なこと
- まず、モードを確認します。サービスユニットの実行行に
--enable-dynamic-configがあるかを見るのが最も速いです。すべてのコントローラーが同じモードである必要があり、混在すると衝突すると、ドキュメントが警告しています。 - 静的構成なら、すべてのコントローラーのファイルを同じに揃えて、再起動までが1つの作業です。
- 動的構成なら、クラスターレベルの変更はオブジェクトで行い、
k0s config statusで結果を確認します。ファイルでは、ノードごとの設定と、変更できないネットワークの値だけが意味を持ちます。 - 反映されたかどうかは、成果物で確認します。コマンドが成功したことよりも、ConfigMap・Chart・リリースが実際にできたか、消えたかを見ます。
- Helm拡張を削除するときは、宣言を削除します。Chartだけを削除すると、次の再起動で戻ってきます。逆に、宣言を削除するとリリースが削除されるので、データがあるチャートなら、その結果を先に考える必要があります。ネームスペースは残りました。
次のラボですること
静的構成で起動したk0s 1台から始めます。デフォルト値とファイルを比較し、事前チェックを読み取ったうえで、ファイルにワーカープロファイルを入れて、再起動の前後を比べます。動的構成に切り替えてClusterConfigができることを確認し、同じ方法でファイルを直すと、今度は再起動しても無視されることを確認します。最後に、オブジェクトにワーカープロファイルとpodinfoチャートを宣言し、宣言を削除したときに何が残るかを記録します。