Certified Kubernetes Administrator (CKA) #7 etcd バックアップとリストア: etcdctl snapshot save/restore

Kubernetes クラスターのすべての状態は一か所に集まります。Deployment、Service、Secret、RBAC ルール、ネームスペース、ノード情報まで、クラスターが記憶するものすべてが etcd というキーバリューストアに入っています。apiserver は事実上 etcd の前に置かれた門番にすぎず、本物のデータは etcd が握っています。だから etcd が飛ぶと、クラスターの記憶全体が飛びます。

このことから etcd バックアップとリストア は CKA 実技でほぼ常連として出ます。採点ポイントが明確で、コマンド 1〜2 行の正確さで点数が分かれる作業なので、手に覚えておけば確実な得点源です。逆に証明書フラグを 1 つ落としたり、復元後の data-dir 反映を忘れたりすると丸ごと間違えます。今回の記事では etcdctl snapshot save でスナップショットを取り、snapshot restore で蘇らせる全過程を、落とし穴まで押さえて整理します。

etcd はどこに立っているか #

kubeadm で建てたクラスターでは、etcd は control plane ノードの上の static Pod として動きます。static Pod は kubelet がディスクのマニフェストディレクトリを直接監視して立ち上げる Pod で、apiserver を経由しません。etcd のマニフェストは次の場所にあります。

/etc/kubernetes/manifests/etcd.yaml

バックアップとリストアに必要な情報はすべてこのファイルの中に書かれています。暗記して入れるのではなく、毎回このファイルから読み取る ことでミスがなくなります。次の 3 つを探します。

  • --data-dir: etcd が実際にデータを書くディレクトリ。通常は /var/lib/etcd
  • 証明書パス 3 つ: --trusted-ca-file (cacert)、--cert-file (cert)、--key-file (key)
  • endpoint: etcd が待ち受けるアドレス。通常は https://127.0.0.1:2379

マニフェストから該当する行だけ抜き出してみます。

grep -E 'data-dir|cert-file|key-file|trusted-ca-file|listen-client-urls' \
  /etc/kubernetes/manifests/etcd.yaml

おおむね次のように出ます。

    - --data-dir=/var/lib/etcd
    - --cert-file=/etc/kubernetes/pki/etcd/server.crt
    - --key-file=/etc/kubernetes/pki/etcd/server.key
    - --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
    - --listen-client-urls=https://127.0.0.1:2379,https://10.0.0.10:2379

ここでバックアップコマンドに入る値がそのまま決まります。証明書パスはクラスターごとに異なる可能性があるので、試験場で暗記したパスをそのまま使わず、このファイルで確認する 習慣が安全です。

etcdctl の準備 #

コマンドは etcdctl で実行します。etcd v3 API を使う必要があるので、環境変数 ETCDCTL_API=3 を必ず設定します。最新バージョンでは v3 がデフォルトですが、試験環境のバージョンによっては v2 として動作してコマンドが丸ごと失敗することがあるので、明示する方が安全です。

export ETCDCTL_API=3

# etcdctl が見えるか、バージョン確認
etcdctl version

etcdctl がなければ etcd コンテナの中で実行するか、パッケージでインストールします。kubeadm クラスターの control plane ノードにはたいてい既に入っています。

ステップ 1: スナップショット保存 (snapshot save) #

ここでスナップショットを取ります。endpoint と証明書 3 つをすべて渡す必要があります。1 つでも欠けると認証失敗でコマンドが通りません。

ETCDCTL_API=3 etcdctl snapshot save /opt/snapshot.db \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

フラグ名の対応関係を取り違えないようにします。マニフェストの --trusted-ca-file が etcdctl の --cacert--cert-file--cert--key-file--key です。マニフェスト側は etcd サーバーが使うフラグで、etcdctl 側はクライアントが使うフラグなので名前が異なります。

保存が終わると Snapshot saved at /opt/snapshot.db が出力されます。スナップショットがきちんと取れたか確認します。

ETCDCTL_API=3 etcdctl snapshot status /opt/snapshot.db --write-out=table

次のようにハッシュ・キー個数・DB サイズが表で出れば正常です。

+----------+----------+------------+------------+
|   HASH   | REVISION | TOTAL KEYS | TOTAL SIZE |
+----------+----------+------------+------------+
| fe01cf57 |    24390 |       1287 |     5.4 MB |
+----------+----------+------------+------------+

snapshot status は証明書が要りません。既に取っておいたファイルを読むだけだからです。逆に snapshot save は生きている etcd に接続してデータを受け取るので、endpoint と証明書が両方とも必要です。

ステップ 2: スナップショット復元 (snapshot restore) #

リストアは取っておいたスナップショットファイルから 新しい data-dir にデータを展開する 作業です。既存の data-dir に上書きせず別ディレクトリに復元してから、etcd がそのディレクトリを見るようにマニフェストを変える方式が安全です。

ETCDCTL_API=3 etcdctl snapshot restore /opt/snapshot.db \
  --data-dir=/var/lib/etcd-restore

ここで重要な点があります。snapshot restore は生きている etcd に接続せず、ファイルからローカルディレクトリにデータを展開するオフライン作業 です。だから --endpoints や証明書フラグが要りません。試験で習慣的に証明書を付ける人がいますが、restore には無害でも本質的に不要です。実際に必要なのは --data-dir 1 つです。

コマンドが終わると、/var/lib/etcd-restore の中に member ディレクトリができ、その中に復元された etcd データが入ります。

ステップ 3: etcd が復元されたディレクトリを見るようにする #

復元しただけではクラスターは戻ってきません。生きている etcd は依然として旧 data-dir (/var/lib/etcd) を見ているからです。etcd static Pod が新しいディレクトリを見るようにマニフェストを直す 必要があります。直す箇所は 2 つです。

まず /etc/kubernetes/manifests/etcd.yaml を開きます。data-dir はコンテナの引数と hostPath ボリュームの 2 か所に現れます。

コンテナ引数の --data-dir はそのままでよいです。この値はコンテナ 内部 のパスだからです。実際に変える箇所はホストディレクトリをコンテナにマウントする volume の hostPath です。

  volumes:
  - hostPath:
      path: /var/lib/etcd-restore   # 既存の /var/lib/etcd から変更
      type: DirectoryOrCreate
    name: etcd-data

name: etcd-data ボリュームがコンテナの中で --data-dir が指すパス (/var/lib/etcd) にマウントされます。したがって hostPath だけを復元ディレクトリに変えれば、コンテナの中の etcd は同じパス (/var/lib/etcd) でデータを見ますが、ホストの立場では復元されたディレクトリを読むことになります。volumeMounts の mountPath とコンテナ引数 --data-dir には手を付けないのが最も単純な方法です。

ステップ 4: etcd 再起動と確認 #

マニフェストを保存すると、kubelet が変更を検知して etcd Pod を再生成します。static Pod なので kubectl apply のようなコマンドは要りません。ファイルを直すだけで kubelet が旧コンテナを殺し、新しい引数で立て直します。

マニフェストを保存すると kubelet がしばらく後に新しい etcd を上げます。反映が遅ければ、マニフェストをディレクトリの外へしばらく移してから戻して強制的に再ロードできます。

# 強制再ロードが必要なとき
mv /etc/kubernetes/manifests/etcd.yaml /tmp/etcd.yaml
# しばらく後に
mv /tmp/etcd.yaml /etc/kubernetes/manifests/etcd.yaml

etcd が新しいデータで立ち上がると apiserver が再び etcd に繋がり、クラスター状態がスナップショット時点に戻ります。コンテナが立っているか、apiserver が応答するか確認します。

# crictl で etcd コンテナの状態
crictl ps | grep etcd

# kubelet ログで再起動を追跡
journalctl -u kubelet -f

# apiserver が戻れば、クラスターが応答する
kubectl get nodes
kubectl get pods -A

kubectl get コマンドがスナップショット時点のリソースを見せれば復旧が終わりです。

外部 etcd の場合 #

ここまでは #4 で扱った stacked etcd (etcd が control plane ノードの static Pod として動く構成) を前提にしました。#5外部 etcd cluster は違いがあります。etcd が別ノードで systemd サービスとして動くので、マニフェスト修正ではなく systemctl stop etcd 〜 復元 〜 etcd 設定ファイルの data-dir 変更 〜 systemctl start etcd の流れで進め、save/restore コマンド自体は同じです。

落とし穴 #

CKA 実技でこの作業を間違えるパターンはほぼ決まっています。

  • ETCDCTL_API=3 の欠落: v2 で動作すると snapshot サブコマンド自体が違って解釈されて失敗します。コマンドの先頭に ETCDCTL_API=3 を付けるか export で固定します。
  • 証明書フラグの欠落: snapshot save は endpoint と cacert/cert/key の 3 証明書をすべて要求します。1 つだけ欠けても認証失敗で落ちます。パスは暗記せずマニフェストで確認します。
  • restore に証明書を入れようとする: 逆に snapshot restore はファイルベースのオフライン作業なので endpoint・証明書が要りません。実際に必要な --data-dir を落とさないことが肝心です。
  • restore 後に data-dir を反映しない: 最もよくある失敗です。復元だけしてマニフェストの hostPath を新しいディレクトリに変えないと、etcd は旧データを見続けるのでクラスターが復旧しません。
  • フラグ名の混同: サーバー側の --trusted-ca-file/--cert-file/--key-file とクライアント側の --cacert/--cert/--key を混ぜて使ってしまいがちです。etcdctl にはクライアントの名前を使います。
  • 保存パスを確認しない: 問題が指定したスナップショットパス (例: /opt/snapshot.db) と違う場所に保存すると採点から外れます。snapshot status で取れたファイルを確認します。

試験ポイント #

  • etcd バックアップ・リストアは CKA の常連出題項目で、コマンドの正確さで点数が分かれます。
  • バックアップ: ETCDCTL_API=3 etcdctl snapshot save <ファイル> --endpoints --cacert --cert --key。すべての証明書をマニフェストで確認して入れます。
  • 復元: ETCDCTL_API=3 etcdctl snapshot restore <ファイル> --data-dir=<新しいディレクトリ>。endpoint・証明書は不要、--data-dir は必須です。
  • 復元の後 /etc/kubernetes/manifests/etcd.yaml の hostPath を新しい data-dir に変えてこそ kubelet が etcd を新しいデータで再起動します。
  • snapshot status --write-out=table で取れたスナップショットの整合性を確認します。
  • 外部 etcd はマニフェストの代わりに systemd で stop/start し、save/restore コマンドは同じです。

まとめ #

この記事で押さえたこと:

  • etcd はクラスター状態の単一ストア。etcd バックアップがすなわちクラスターバックアップです。
  • バックアップの 3 要素: ETCDCTL_API=3、endpoint (https://127.0.0.1:2379)、証明書 3 つ。パスは /etc/kubernetes/manifests/etcd.yaml から読み取ります。
  • 復旧の流れ: snapshot restore で新しい data-dir に復元 → マニフェスト hostPath 変更 → kubelet が etcd 再起動 → apiserver 復旧。
  • 落とし穴: API バージョンの欠落、証明書フラグの欠落、restore 後の data-dir 未反映。

これで etcd を失ってもスナップショット 1 つでクラスターを時点復旧できます。バックアップの相方は 証明書 です。etcd データが生きていても証明書が期限切れになると、apiserver と etcd が互いを信じられず通信が切れます。

次へ — 証明書管理 #

#8 証明書管理: PKI、kubeconfig、証明書更新 では、kubeadm が作っておく PKI 構造 (ca.crt を頂点とした証明書チェーン)、kubeconfig ファイルがどのように認証情報を抱えるのか、そして期限切れの証明書を kubeadm certs renew で更新する手順を整理します。CKA トラブルシューティングで証明書期限切れは apiserver が丸ごと死ぬ原因としてよく登場するので、期限切れかどうかを確認して蘇らせる感覚を手に覚えさせます。

X