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

Kubernetesディストリビューション — 自分で立てる

k3s は削除した traefik をなぜ再インストールするのか

TT Labで続きを見る

一言でいうと

k3sはサーバーのmanifestsディレクトリを起動時とファイルの変更時に適用し、デフォルトのコンポーネントのファイルは起動のたびに書き直すので、コンポーネントをなくすにはkubectlではなく--disableを、値を変えるにはファイルの修正ではなくHelmChartConfigを使う必要があります。

なぜ必要なのか

マネージドKubernetesでは、Ingressコントローラーやメトリクスサーバーを「インストールする人」が別にいます。不要ならkubectl deleteで削除し、また必要になったら再インストールします。k3sは、インストール1行でcoredns・traefik・local-storage・metrics-serverまで揃ったクラスターを提供するために作られました。そのためには、k3s自身がそれらのコンポーネントのインストール担当でなければならず、誰かが手で壊しても元の姿に戻るようにしておく必要があります。そこでk3sは、デフォルトのコンポーネントのマニフェストをサーバーのディスクに置き、起動するたびに書き直して適用します。公式ドキュメントは、これらのファイルは完全性を保つために起動のたびに書き直されるので、編集しないよう書いています。

この設計が現場でどう現れるかは、実測で確認しました(v1.35.8+k3s1)。

kubectl -n kube-system delete helmchart traefik   → helm-delete Job 이 릴리스를 지움, traefik 사라짐
(20초 기다려도 그대로)
systemctl restart k3s                              → API 5초, HelmChart 가 새 UID 로 생기고 20초 뒤 traefik 복귀

このコードブロックの韓国語の説明は、順に、HelmChartを削除するとhelm-deleteジョブがリリースを削除してtraefikが消えること、20秒待っても変わらないこと、k3sを再起動するとAPIが5秒で戻り、HelmChartが新しいUIDで作られて20秒後にtraefikが復帰することを述べています。

「使わないから削除したのに、リブートしたらまたある」という事故の正体が、これです。

どう動くのか

層が2つあります。

1つ目の層はデプロイコントローラーとAddOnです。/var/lib/rancher/k3s/server/manifestsの下にあるファイル1つ(サブディレクトリを含む)が、kube-systemネームスペースのAddOnオブジェクト1つになり、名前はファイル名から拡張子を除いたものです。コントローラーはファイルをkubectl applyに近い形で適用し、AddOnのspec.checksumに内容のハッシュを書き込みます。適用のきっかけは2つだけです。k3sの起動と、ファイル内容の変更です。実測してみると、クラスターからオブジェクトを削除しても、ファイルをtouchしただけでも再適用されず、値を変更すると数秒で新しいUIDで再び作られました。逆に、ファイルを削除してもクラスターのオブジェクトとAddOnは残ります。ドキュメントも、ファイルの削除はリソースを削除しないとはっきり書いています。

2つ目の層はhelm-controllerとHelmChartです。traefik.yamlにはDeploymentではなくHelmChartオブジェクトが入っていて、helm-controllerがそれを見てhelm-install-traefikジョブを起動し、チャートをインストールします。チャートファイルはAPIサーバーのstaticパスから取得します。値の優先順位は、チャートのデフォルト値 → HelmChartのvaluesContent → HelmChartConfigのvaluesContent → HelmChartのspec.setの順で、後のものが勝ちます。

apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
  name: traefik          # 대상 HelmChart 와 이름·네임스페이스가 같아야 한다
  namespace: kube-system
spec:
  valuesContent: |-
    logs:
      general:
        level: DEBUG

このコードブロックの韓国語コメントは、名前とネームスペースが対象のHelmChartと同じでなければならないという意味です。

HelmChartConfigは、k3sが書き直すファイルではなく別に置いたオブジェクトなので、起動時に上書きされません。適用するとhelm upgradeが動き、リリースSecretが1つ増えます。

無効にする方法も2つあり、性質が異なります。

--disable=traefik     AddOn 을 실제로 제거하고 원본 파일도 지운다. 구성은 기동할 때 읽힌다
traefik.yaml.skip     그 파일을 없는 것처럼 무시한다. 이미 만든 객체는 지우지 않는다

2つの韓国語の説明は、順に、AddOnを実際に削除して元のファイルも消し、構成は起動時に読み込まれることと、そのファイルをないものとして無視し、すでに作成したオブジェクトは削除しないことを述べています。

構成は/etc/rancher/k3s/config.yamlとconfig.yaml.d/*.yaml(名前順)から読み込まれ、同じキーは最後の値が勝ち、キーの末尾に+を付けるとリストに追加されます。ファイルとCLI引数が同じキーを持つ場合は、CLIが勝ちます。インストールスクリプトに渡したINSTALL_K3S_EXECはsystemdユニットの引数として保存されるので、CLI側です。

現場での姿

最も多いのは、Ingressをnginxに切り替えたいチームがtraefikをkubectlで削除するケースです。その日は静かですが、ノードのリブートやk3sのアップグレードの日にtraefikが復活してポート80と443を占有し、新しいIngressコントローラーのLoadBalancerがPendingのまま止まります。原因を知らないと、まず「誰がインストールしたのか」を探すことになります。

2つ目は、traefik.yamlを直接編集して値を変えたケースです。その場では反映されますが、次の起動で元に戻ります。値はHelmChartConfigで、削除は--disableで行わないと、リブートやアップグレードに耐えられません。

3つ目は、構成ファイルを直したのに反映されないケースです。実測では、config.yamlにwrite-kubeconfig-mode: "0600"を書いて再起動しても、k3s.yamlは644のままでした。インストール時に渡した--write-kubeconfig-mode 644がユニットの引数として残っていたからです。drop-inでdisable:を+なしで書くと前のファイルのリストが丸ごと上書きされ、無効にしておいたコンポーネントが再びインストールされるのも、同じ系統のミスです。

実務で本当に大切なこと

次のラボですること

VM内のk3sでAddOnの一覧を記録し、ユーザーAddOnをkubectlで削除した場合とファイルを修正した場合を比べます。HelmChart traefikを削除してから再起動し、復活することをUIDで確認したうえで、.skip・drop-inのdisable・CLIの優先順位・HelmChartConfigを順に適用し、何が再起動を必要とするのかを表にまとめます。

参考ドキュメント: Managing Packaged Components・Helm (HelmChart・HelmChartConfig)・Configuration Options