Kubernetesディストリビューション — 自分で立てる
スナップショットを実行したらデータストアが SQLite だった
目標
k3sサーバー1台のデータストアがSQLite(kine)であることを確認し、etcdのスナップショットが拒否される理由を見たうえで、--cluster-initで再起動して内蔵etcdへ移行します。 スナップショットをトークンと一緒にバックアップし、--cluster-resetで復元して、スナップショット以降の変更が消えることと、以前のデータがどこに残るかを記録します。
なぜ重要なのか
k3sは1台で始めると、etcdの代わりにSQLiteを使います。軽量で高速ですが、複数のサーバーで共有できず、k3s etcd-snapshotのようなetcdのツールが動作しません。
そのため「バックアップを導入しよう」という日になって初めてデータストアが何かを確認することになり、そのときの選択肢は、ファイルを丸ごとコピーするSQLiteのバックアップか、etcdへの移行です。
etcdへの移行は再起動1回で済みますが、復元は「その時点へ戻すこと」なので、スナップショット以降に作ったものは消えます。そして、サーバートークンがないとスナップショットは役に立ちません。
このラボでは、その3つ、すなわちデータストアの確認、移行、復元が元に戻す範囲を、本物のk3sで1回ずつ体験します。etcdを最初から使うk0sのラボと違い、データストアを切り替える過程そのものを扱います。
ステップ
- ネームスペース
k3s-dsにConfigMapmarker(stage=sqlite)を作成してください。そして次のフィールドを書いてください(書き込み先:/root/k3s-ds/datastore.json)。datastore(sqliteまたはetcd)、db_files(/var/lib/rancher/k3s/server/dbのファイル名をソートした配列)、kine_table(state.dbの中のテーブル名のうちkineが使うもの)、kine_endpoint(k3sのログのKine available atの後のアドレス)、marker_uid(markerのUID)です。 - 現在の状態で
k3s etcd-snapshot saveを実行し、標準出力と標準エラー出力をまとめて保存してください(保存先:/root/k3s-ds/snapshot-refused.txt)。そして、SQLiteのデータストアをバックアップするためにコピーすべきディレクトリとファイルの絶対パスを、1行に1つずつ書いてください(書き込み先:/root/k3s-ds/sqlite-backup.txt)。 /etc/rancher/k3s/config.yamlにcluster-init: trueを書いて、k3sを再起動してください。markerが残っていることを確認し、次のフィールドを書いてください(書き込み先:/root/k3s-ds/migrate.json)。marker_uid(再起動後のmarkerのUID)、sqlite_file_now(dbディレクトリで元のstate.dbが変わった名前)、node_roles(ノードのnode-role.kubernetes.io/ラベルの名前をソートした配列。例: ["control-plane"])、member_name(db/etcd/nameファイルの内容)です。- markerの
stageをsnapshottedに変更してから、k3s etcd-snapshot save --name lab-beforeでスナップショットを取得してください。次のフィールドを書いてください(書き込み先:/root/k3s-ds/snapshot.json)。name(作成されたスナップショット名の全体)、path(ファイルの絶対パス)、size(バイト数、整数)、sha256(ファイルのSHA-256)です。 /root/k3s-ds/backup/ディレクトリに、ステップ4のスナップショットファイル(同じ名前)とサーバートークンファイル(名前はtoken、権限は600)をコピーしてください。次のフィールドを書いてください(書き込み先:/root/k3s-ds/token-backup.json)。token_source(トークンの元ファイルの絶対パス)、token_sha256(トークンファイルのSHA-256)、snapshot_sha256(バックアップしたスナップショットのSHA-256)です。トークンの値そのものは、どこにも書かないでください。- スナップショットの後に、ネームスペース
k3s-dsにConfigMapafter-snap(x=1)を作成し、markerのstageをchangedに変更してください。次のフィールドを書いてください(書き込み先:/root/k3s-ds/after.json)。after_uid(after-snapのUID)、after_created(そのcreationTimestamp)、marker_stage(現在のmarkerのstage)です。 - k3sを停止し、
k3s server --cluster-reset --cluster-reset-restore-path=<4단계 스냅숏 경로>で復元してから(プレースホルダーはステップ4のスナップショットのパスです。出力の全体を/root/k3s-ds/reset.logに保存します)、k3sを再び起動してください。次のフィールドを書いてください(書き込み先:/root/k3s-ds/restore.json)。old_dir(復元が以前のetcdデータを移したディレクトリ名)、restart_hint(reset.logの中で、k3sが次にすることを知らせている文のうち、restart withoutを含む部分までの最初の1文)、after_snap_exists(ブール値)、marker_stage(復元後のmarkerのstage)、member_name(復元後のdb/etcd/nameの内容)です。 - 次のフィールドを書いてください(書き込み先:
/root/k3s-ds/report.json)。datastore_now(sqliteまたはetcd)、lost_objects(復元で消えたConfigMap名をソートした配列)、marker_stage(現在の値)、snapshot_dir(スナップショットが保存されたディレクトリの絶対パス)、restore_needs_token(別のサーバーで復元するときに元のトークンが必要かどうか、ブール値)、member_name_changed(復元の前後でetcdのメンバー名が変わったかどうか、ブール値)です。
参考
- VMの中にk3s v1.35.8+k3s1が1台あります(traefikとmetrics-serverは無効)。再起動は
systemctl restart k3sです。 - ステップ3の後、
k3s etcd-snapshotコマンドは、config.yamlのcluster-initを知らないキーだとして警告を1行出します。無害です(実測)。 - 復元コマンドは、ドキュメントの手順どおり
systemctl stop k3sでサービスを停止してから実行します。 - よくあるミス: スナップショットだけをバックアップして、
/var/lib/rancher/k3s/server/tokenを忘れること。 - よくあるミス:
--cluster-resetをサービスの引数やconfig.yamlに入れること。復元は1回だけ別に実行するコマンドで、k3sはreset-flagファイルで連続した初期化を防ぎます。 - Cluster Datastore・High Availability Embedded etcd・etcd-snapshot・Backup and Restore
このクラスターのデータストアは何かを確認する
ネームスペースk3s-dsにConfigMapmarker(stage=sqlite)を作成してください。そして次のフィールドを書いてください(書き込み先: /root/k3s-ds/datastore.json)。datastore(sqliteまたはetcd)、db_files(/var/lib/rancher/k3s/server/dbのファイル名をソートした配列)、kine_table(state.dbの中のテーブル名のうちkineが使うもの)、kine_endpoint(k3sのログのKine available atの後のアドレス)、marker_uid(markerのUID)です。
k3sはSQLiteをAPIサーバーに直接接続せず、etcd APIを模倣するkineを間に置きます。APIサーバーの--etcd-serversが何を指しているかを、ログで確認してください。テーブル名はsqlite3 <파일> .tablesで見られます(プレースホルダーはファイル名です)。
スナップショットコマンドを実行したらデータストアがSQLiteだった
現在の状態でk3s etcd-snapshot saveを実行し、標準出力と標準エラー出力をまとめて保存してください(保存先: /root/k3s-ds/snapshot-refused.txt)。そして、SQLiteのデータストアをバックアップするためにコピーすべきディレクトリとファイルの絶対パスを、1行に1つずつ書いてください(書き込み先: /root/k3s-ds/sqlite-backup.txt)。
etcd-snapshotはサーバーにリクエストを送り、サーバーが内蔵etcdでスナップショットを取得します。データストアがSQLiteならサーバーが拒否し、詳しい理由はサーバーのログに残します。SQLiteは特別なコマンドなしにファイルをコピーしてバックアップしますが、データストア内の機密データを暗号化する値も一緒に保管する必要があります。
再起動1回でetcdへ移行する
/etc/rancher/k3s/config.yamlにcluster-init: trueを書いて、k3sを再起動してください。markerが残っていることを確認し、次のフィールドを書いてください(書き込み先: /root/k3s-ds/migrate.json)。marker_uid(再起動後のmarkerのUID)、sqlite_file_now(dbディレクトリで元のstate.dbが変わった名前)、node_roles(ノードのnode-role.kubernetes.io/ラベルの名前をソートした配列。例: ["control-plane"])、member_name(db/etcd/nameファイルの内容)です。
SQLiteで動いていたサーバーをcluster-initで起動すると、k3sがSQLiteの内容をetcdへ移します。すでにetcdのデータがディスクにある場合、この引数は無視されます。ログのMigrating content from sqlite to etcdを探してみてください。
名前を付けてスナップショットを取得する
markerのstageをsnapshottedに変更してから、k3s etcd-snapshot save --name lab-beforeでスナップショットを取得してください。次のフィールドを書いてください(書き込み先: /root/k3s-ds/snapshot.json)。name(作成されたスナップショット名の全体)、path(ファイルの絶対パス)、size(バイト数、整数)、sha256(ファイルのSHA-256)です。
--nameは名前の前半部分だけを決め、k3sがノード名と時刻を付け足します。保存場所は--etcd-snapshot-dirのデフォルト値です。k3s etcd-snapshot lsとkubectl get etcdsnapshotfileが、同じスナップショットを表示します。
スナップショットだけでは復元できない
/root/k3s-ds/backup/ディレクトリに、ステップ4のスナップショットファイル(同じ名前)とサーバートークンファイル(名前はtoken、権限は600)をコピーしてください。次のフィールドを書いてください(書き込み先: /root/k3s-ds/token-backup.json)。token_source(トークンの元ファイルの絶対パス)、token_sha256(トークンファイルのSHA-256)、snapshot_sha256(バックアップしたスナップショットのSHA-256)です。トークンの値そのものは、どこにも書かないでください。
k3sはサーバートークンで、データストア内の機密のブートストラップデータを暗号化します。別のトークンで復元すると、スナップショットは使えません。コピーするときに権限が広がらないようにしてください。
スナップショットの後にできたもの
スナップショットの後に、ネームスペースk3s-dsにConfigMapafter-snap(x=1)を作成し、markerのstageをchangedに変更してください。次のフィールドを書いてください(書き込み先: /root/k3s-ds/after.json)。after_uid(after-snapのUID)、after_created(そのcreationTimestamp)、marker_stage(現在のmarkerのstage)です。
次のステップの復元がこの2つをどう変えるかを見るためのものです。復元後にも、この記録が本物だったかを確認できるよう、UIDと時刻を正確に書いてください。
復元するとスナップショットの後の変更が消えた
k3sを停止し、k3s server --cluster-reset --cluster-reset-restore-path=<4단계 스냅숏 경로>で復元してから(プレースホルダーはステップ4のスナップショットのパスです。出力の全体を/root/k3s-ds/reset.logに保存します)、k3sを再び起動してください。次のフィールドを書いてください(書き込み先: /root/k3s-ds/restore.json)。old_dir(復元が以前のetcdデータを移したディレクトリ名)、restart_hint(reset.logの中で、k3sが次にすることを知らせている文のうち、restart withoutを含む部分までの最初の1文)、after_snap_exists(ブール値)、marker_stage(復元後のmarkerのstage)、member_name(復元後のdb/etcd/nameの内容)です。
復元は、サービスが停止した状態で、同じバイナリを1回だけ別に実行するものです。終わると自分で終了して、再起動するよう知らせます。以前のデータは削除せず、脇に移しておきます。連続した初期化を防ぐ目印のファイルが作られ、正常に起動すると削除されます。
何が残り、何が消えたのか
次のフィールドを書いてください(書き込み先: /root/k3s-ds/report.json)。datastore_now(sqliteまたはetcd)、lost_objects(復元で消えたConfigMap名をソートした配列)、marker_stage(現在の値)、snapshot_dir(スナップショットが保存されたディレクトリの絶対パス)、restore_needs_token(別のサーバーで復元するときに元のトークンが必要かどうか、ブール値)、member_name_changed(復元の前後でetcdのメンバー名が変わったかどうか、ブール値)です。
前のステップのjsonと、現在のディスクとクラスターを根拠にして書きます。採点ツールは、同じ値を記録ファイル・etcd-oldディレクトリ・クラスターからもう一度計算します。