kubernetesクラスタにおけるetcdコンポーネントの動作検証

Kubernetesクラスタにおけるデータストアとしてetcdがある。 Kubernets The Hard Wayでetcdのセットアップを行ったので、その設定詳細について確認する。

また、Kubernetesにおける etcdクラスタについては以下のドキュメントが参考になる。

kubernetes.io

ユニットファイル

etcdの起動はsystemdで管理しており、そのunitファイルがリポジトリに格納されている これらの内容は以下の通り。詳細なオプション説明については以下が参考になる。

etcd.io

ところで、etcd v3.4までTo start etcd automatically using custom settings at startup in Linux, using a systemd unit is highly recommended.と説明記載あったが、v3.5からは削除されたことが気になる。 また、各種オプションの説明についてもv3.4までの方がより詳細な説明が記載されており、v3.5は情報量が落ちている。これらの説明がv3.5では他に移動したのか、意図して削除したのか気になる。基本的には利用バージョンのドキュメントを参照しつつも、自分のように新しく学ぶ段階ではv3.4のドキュメントも参照するとよさそう。

name
etcdメンバを識別するためのHuman-readableな名前。Kubernetes The Hard Wayではcontrollerと設定されている。 このオプションはinitial-clusterオプションで利用する。

特に複数のetcdメンバーから構成されるetcdクラスタを構築するときに重要になる。 etcdクラスタの構築方法がstatic bootstrappingであってもdiscovery bootstrappingであっても、クラスタ内でユニークな名前となるように設定した方がよさそう。シングルメンバetcdクラスタの場合はおそらくnameは重要ではない。

initial-advertise-peer-urls
etcdがクラスタに接続するときに利用するURL。Kubernetes The Hard Wayではシングルノードetcdで動作するので利用しない。 プロダクションレディなKubernetesではコントロールプレーンの全ノードに対するドメイン名になるのだろうか。

listen-peer-urls
etcdクラスタの接続を許可するURL。Kubernetes The Hard Wayではシングルノードetcdで動作するので利用しないし、 http://127.0.0.1:2380 の設定なので他ノードから接続できない。

initial-advertise-peer-urls とは異なり、どのアドレスでリッスンするかを指定するので、ドメイン名は指定できない。全許可なら http://0.0.0.0:2380 のような設定になるし、コントロールプレーン用のネットワークが 192.168.128.0/24 だったりしたら http://192.168.128.0:2480 のような設定になるはず? v3.4までのドキュメントには invalid exampleやv3.5以降より具体的な説明が記載されていたのでわかりやすかった。

listen-client-urls
etcdクライアントが接続するURL。Kubernetesにおいてetcdのclientとは kube-apiserverのことで、kube-apiserver以外のコンポーネントのユニットファイルにはetcdの接続URLは記載されていないし、Kubernetesコンポーネント図にはetcdとkube-apiserverのみ接続線が図示されている。

Kubernetes The Hard Wayの設定においては http://127.0.0.1:2379 が指定されているので、コントロールプレーンノードにおいてetcdとkube-apiserverが必ず動作し、kube-apiserverはローカルetcdに接続することが想定されていると理解できる。

advertise-client-urls
etcdクライアント(kube-apiserver)がetcdクラスタに接続するときに利用するURL。Kubernetes The Hard Wayにおいては http://127.0.0.1:2379の設定になっており、kube-apiserverのローカルでetcdが動作すればよいという設計になっていることがわかる。

listen-client-urlsadvertise-client-urlsの関係は listen-peer-urlsinitial-advertise-peer-urlsの関係に等しく、etcdがどのURLで接続許可するかとkube-apiserverがどのURLで接続するのかを設定できる。ただ、Kubernetesにおいて、etcdとkube-apiserverが同居しないコントロールプレーンの設計が存在しうるのか気になるところ。

initial-cluster-token
etcdクラスタを識別するためのトークン。Kubernetes The Hard Wayでは複数のクラスタを同時に構築することは想定していないので etcd-cluster-0 で固定。 複数クラスタを同じ設定で構築する場合もinitial-cluster-tokenはそれぞれユニークな値を指定することで、クラスタを識別できるようになるしetcdメンバが混在すること防ぐことができる。

initial-cluster
etcdクラスタにおける初期メンバ一覧。Kubernetes The Hard Wayにおいてはシングルメンバのetcdクラスタなのであまり意味はない。

マルチメンバかつstatic bootstrappingの場合は事前に全メンバがわかっているので、メンバの名前と接続用のURLを記載できる。 ドキュメントには --initial-cluster infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380のような記載例が提示されておりイメージしやすい。

etcdクラスタメンバが動的に構成される場合はこのようにメンバのIP一覧を事前に列挙することはできないので、Discoveryの仕組みを利用する。

initial-cluster-state
etcdクラスタの初期構築(new)か、既存のetcdクラスタへの追加(existing)なのかを指定する。

もし間違った値を指定した場合もetcdクラスタを壊さず安全に停止してくれるらしいが、この値の指定がどのような意味を持つのかよくわかっていない。とりあえず既存クラスタにjoinするように動作し、joinできなかったら新規クラスタを構築するような動作はできないのだろうか。

バックアップ・リストア

Kuberneteのetcdクラスタ運用において、バックアッププランはちゃんと作成しておけよと注意書きがあるのでここだけ検証しておく。

Kubernetes The Hard Wayでは --data-dir=/var/lib/etcd を指定しているのでこのディレクトリをバックアップしてもよい(volume snapshot)し、etcdctl snapshot save snapshot.dbのコマンドでスナップショットを作成してもよい(built-in snapshot)。
Kubernetesのドキュメントには --endpointの指定もあるが、これは指定するなら --endpints=http://127.0.0.1:2379 のようになる。これがデフォルト値なので変更なしなら指定しなくてよい。運用系の操作なので2380ポートかと思ったが、etcdctlからの操作はクライアント接続でありgRPCプロトコルなので2379ポートらしい。また、クライアント接続なので --listen-client-urlsで指定したURLからでないと接続できない。

root@khw-server:~# etcdctl snapshot save snapshot.db
{"level":"info","ts":1726459074.9597218,"caller":"snapshot/v3_snapshot.go:119","msg":"created temporary db file","path":"snapshot.db.part"}
{"level":"info","ts":"2024-09-16T12:57:54.988563+0900","caller":"clientv3/maintenance.go:200","msg":"opened snapshot stream; downloading"}
{"level":"info","ts":1726459074.99662,"caller":"snapshot/v3_snapshot.go:127","msg":"fetching snapshot","endpoint":"127.0.0.1:2379"}
{"level":"info","ts":"2024-09-16T12:57:55.494366+0900","caller":"clientv3/maintenance.go:208","msg":"completed snapshot read; closing"}
{"level":"info","ts":1726459075.562186,"caller":"snapshot/v3_snapshot.go:142","msg":"fetched snapshot","endpoint":"127.0.0.1:2379","size":"1.2 MB","took":0.594269111}
{"level":"info","ts":1726459075.573733,"caller":"snapshot/v3_snapshot.go:152","msg":"saved","path":"snapshot.db"}
Snapshot saved at snapshot.db
root@khw-server:~# etcdctl  --write-out=table snapshot status snapshot.db
+----------+----------+------------+------------+
|   HASH   | REVISION | TOTAL KEYS | TOTAL SIZE |
+----------+----------+------------+------------+
| 45051425 |   163644 |        927 |     1.2 MB |
+----------+----------+------------+------------+

このファイルを別サーバに転送してリストアする。 etcdctlのスナップショットリストアはetcdメンバにバックアップデータを投入するのではなく、データディレクトリに展開する役目を持つ。このため、リストアする際はetcdメンバを停止させ、データディレクトリを空にした上で実行する。その上でetcdを起動すればリストアできる。

$ etcdctl --data-dir /tmp/etcd/ snapshot restore snapshot.db
Deprecated: Use `etcdutl snapshot restore` instead.

2024-09-16T13:18:39+09:00   info    snapshot/v3_snapshot.go:265 restoring snapshot  {"path": "snapshot.db", "wal-dir": "/tmp/etcd/member/wal", "data-dir": "/tmp/etcd/", "snap-dir": "/tmp/etcd/member/snap", "initial-memory-map-size": 0}
2024-09-16T13:18:39+09:00   info    membership/store.go:141 Trimming membership information from the backend...
2024-09-16T13:18:39+09:00   info    membership/cluster.go:421   added member    {"cluster-id": "cdf818194e3a8c32", "local-member-id": "0", "added-peer-id": "8e9e05c52164694d", "added-peer-peer-urls": ["http://localhost:2380"]}
2024-09-16T13:18:39+09:00   info    snapshot/v3_snapshot.go:293 restored snapshot   {"path": "snapshot.db", "wal-dir": "/tmp/etcd/member/wal", "data-dir": "/tmp/etcd/", "snap-dir": "/tmp/etcd/member/snap", "initial-memory-map-size": 0}

# etcdを別ターミナルで起動する

$ etcdctl get /registry/secrets/default/kubernetes-the-hard-way | hexdump -C
00000000  2f 72 65 67 69 73 74 72  79 2f 73 65 63 72 65 74  |/registry/secret|
00000010  73 2f 64 65 66 61 75 6c  74 2f 6b 75 62 65 72 6e  |s/default/kubern|
00000020  65 74 65 73 2d 74 68 65  2d 68 61 72 64 2d 77 61  |etes-the-hard-wa|
00000030  79 0a 6b 38 73 3a 65 6e  63 3a 61 65 73 63 62 63  |y.k8s:enc:aescbc|
00000040  3a 76 31 3a 6b 65 79 31  3a b8 f6 3b 4f 4d 76 b4  |:v1:key1:..;OMv.|
00000050  ea 1d 0f 0f c4 f5 0d ad  19 bb 4e ef 97 bd 35 df  |..........N...5.|
00000060  50 ef db a6 23 29 58 f1  5a 73 d7 b9 83 a3 e0 b1  |P...#)X.Zs......|
00000070  a0 e4 24 3c 7d 5b ab de  5d 62 a6 e1 59 48 84 f2  |..$<}[..]b..YH..|
00000080  40 58 1f ec 5a 9b e2 a5  15 c8 58 b3 78 36 2f eb  |@X..Z.....X.x6/.|
00000090  90 0e 31 86 53 c5 1d 17  78 43 4d 10 69 55 61 42  |..1.S...xCM.iUaB|
000000a0  df 5c 76 70 64 3f 47 db  09 14 a4 bb ca 7e 26 0e  |.\vpd?G......~&.|
000000b0  c7 2b c6 97 54 68 4d 35  54 11 96 38 25 81 d6 98  |.+..ThM5T..8%...|
000000c0  6a 46 77 0b e6 12 32 db  cf 84 98 11 01 5b cf 49  |jFw...2......[.I|
000000d0  7a 75 92 48 54 57 e0 6b  14 9f 48 05 2a 3b d0 23  |zu.HTW.k..H.*;.#|
000000e0  ed a0 09 56 37 0b fa 48  5c 87 99 bd 34 e3 41 e0  |...V7..H\...4.A.|
000000f0  76 29 87 35 eb 8c fc 09  ff e8 ad 8e ac 6e 57 c5  |v).5.........nW.|
00000100  7b 3e cf ea 93 31 c5 4d  48 88 b9 d8 b3 7f 5c 85  |{>...1.MH.....\.|
00000110  a1 97 a6 0b 65 52 3f b1  35 4b 26 eb b9 de 3d 42  |....eR?.5K&...=B|
00000120  73 e3 93 c8 74 08 37 7b  74 6b bf 91 e8 8e 21 1a  |s...t.7{tk....!.|
00000130  8d 76 33 2c 15 13 76 cf  2f 1e 38 24 eb 91 9a dc  |.v3,..v./.8$....|
00000140  98 0f a8 5d 53 36 83 e4  58 22 9f 82 8c 2b 2e 3e  |...]S6..X"...+.>|
00000150  3c 79 98 ab 12 d2 44 19  fb 0a                    |<y....D...|
0000015a