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

CKA — Kubernetes管理者

Readyと動いているは別の命題だ

TT Labで続きを見る

一言でいうと

トラブルシューティングは、CKAの配点の30%で、5つのドメインの中で最も大きいです。そしてコツは1つです。状態を上から下へ1層ずつ下りながら確認し、どの層で話が途切れるのかを見つけること。Podの状態が、診断の出発点です。

なぜ必要なのか

症状だけを見て原因を当てようとすると、外れます。同じ「接続できない」が、セレクターのタイプミスかもしれず、スケジュールの失敗かもしれず、PVCの未バインドかもしれません。そのため、順序を決めておきます。

Podの状態 どこで詰まったか まず見るもの
Pending スケジューラーのfilter段階 describeのEvents、リソース要求、テイント、nodeSelector、PVCのバインド
ContainerCreating kubeletのボリューム/ネットワークの準備 ボリュームのマウント、CNI、イメージ
ImagePullBackOff イメージの取得 タグのタイプミス、レジストリの認証
CrashLoopBackOff コンテナが死に続けている ログ、設定、プローブ
Runningなのにトラフィックがない サービス層 セレクター、Ready、ポート

この表で最もよく出てくるのがPendingで、その中で最もよく出てくるのが、リソース要求の単位のミスです。cpu: 500は、500ミリコアではなく、500コアです。500mと書く必要があります。memory: 2000Giも、2000Miのタイプミスであることが多いです。スケジューラーのイベントは、次のように語ります。

0/3 nodes are available: 3 Insufficient cpu.

どう動くのか

etcdのバックアップは、コントロールプレーンのDRの最後の保険です。

ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-$(date +%Y%m%d%H%M).db   --endpoints=https://127.0.0.1:2379   --cacert=... --cert=... --key=...
etcdctl snapshot status /backup/etcd-*.db --write-out=table

復旧の原則は3つです。

  1. 既存のdata-dirを上書きしてはいけません。--data-dirで新しいパスに展開し、設定をそのパスに変えて起動します。
  2. 復旧中はapiserverを停止します。生きているapiserverが書き込みを続けると、復旧したものとずれます。
  3. --initial-clusterとpeer URL(2380)を、正確に合わせます。クォーラムを失った状況なら、まず単一ノードで復旧してから、メンバーを1つずつ追加し直します。

そして、必ず指摘しておくべきことがあります。クォーラムは障害への備えであり、ミスへの備えではありません。誤った削除は、すぐにすべてのメンバーに複製されます。特定の時点に復旧できるのは、スナップショットだけです。また、etcdのスナップショットには、PV内のデータがありません。アプリケーションのデータには、Veleroのような別の手段が必要です。

現場での姿

事例1: すべてReadyなのに動きません。ホームラボにKubeVirtを導入したとき、コンポーネントの状態はすべてAllComponentsReadyだったのに、VMは起動しませんでした。virt-launcherのPodのマニフェストを詳しく調べると、initコンテナが実行するバイナリを含むボリュームマウントが抜けていました。筆者の表現をそのまま借りれば、「状態がReady」と「実際に動作する」は別の命題だということを、そのクラスターだけで3回目に確認した瞬間でした。上位のstatusフィールドは、そのコントローラーが知っている範囲のことしか語りません。

事例2: バイナリがあることと、設定されていることは別物です。GPU Operatorをインストールするときに、ノードにnvidia-ctkバイナリがあるのを見て、toolkitのインストールを無効にしました。結果は、次のとおりでした。

Failed to create pod sandbox: rpc error: code = Unknown
  desc = failed to get sandbox runtime: no runtime for "nvidia" is configured

Podは、起動すらできませんでした。コンテナの中で何かが失敗したのではなく、サンドボックスを作る段階で詰まったのです。確認してみると、kubectl get runtimeclassにはnvidiaがありますが、ノードでは、grep -c nvidia /etc/containerd/config.tomlが0でした。RuntimeClassはhandler: nvidiaという名前を指すラベルにすぎず、実体はノードのランタイム設定になければならないのに、再構築でランタイムをcri-dockerdからcontainerdに変えたときに、その設定が消えていたのです。ホストのバイナリは、過去の名残でした。

修正したあとも、config.tomlは依然として0でした。設定は、/etc/containerd/conf.d/99-nvidia.tomlというdrop-inファイルに入っていました。grepした場所がすべてだと信じたことが、2つ目の落とし穴でした。

事例3: クォーラムがあるからといって、バックアップが不要なわけではありません。コントロールプレーンを3台に増やしてetcdメンバー3つを確保したあとも、残りの課題リストの2行目は、これでした。「etcdの定期スナップショット: クォーラムは障害への備えであり、ミス(誤削除)への備えではない」。データが3つ複製されていても、誤ったkubectl deleteを一度実行すれば、3つすべてに即座に反映されます。

次のラボですること

最初のラボで、etcdのスナップショットを実際に取得し、バックアップ前後のリソースを照合して、スナップショットに含まれないものが何かを目で確認し、復旧計画をドキュメントとして残します。2つ目のラボでは、5種類の障害を自分で作って、自分で直します。誤ったイメージタグ、リソース要求の単位のミス、トレラレーションの欠落、ラベルの不一致、ResourceQuotaの超過、PDBで塞がれたdrainです。直す前に症状をファイルに残すことが、採点の対象です。