「etcdって何者?」という疑問から始まる人も多いと思います。結論から言うと、etcd は Kubernetes が全クラスター状態を丸ごと保存するための分散KVストア です。Pod のスケジュール情報、ConfigMap の中身、ノードの状態——それらがすべて etcd に入っています。etcd が落ちたら Kubernetes は動かなくなります。そのくらい重要な役割を持ちながら、単体で学んでいる記事が少ないと感じていました。
この記事では Ubuntu 24.04 で etcd を実際に動かし、3ノードクラスターを構築して、リーダーを強制停止するフェイルオーバーテスト まで実測しています。K8s の中に隠れていた動きが、単体で触るとようやく見えてきます。
この記事のポイント
Ubuntu 24.04 への etcd インストールは apt install etcd-server etcd-client で完結(v3.4.30)
3ノードクラスターを Docker で構築し、member list / endpoint health で全ノード正常を実確認
etcdctl put/get でKV操作、lease grant でTTL付きキーを実演
リーダー強制停止 → 約4秒で新リーダー再選出、データ損失ゼロを実測
apt版(v3.4)とDocker版(v3.5)の違いを比較
実行環境(Ubuntu 24.04.4 LTS / etcd v3.4.30 / v3.5.16)
目次
etcd とは何か
Ubuntu 24.04 への apt インストール
シングルノードで起動してみる
3ノードクラスターを Docker で構築する
KV操作の基本(put / get / watch / lease)
フェイルオーバーを実測する
systemd でサービス管理する
Kubernetes との連携
apt版 vs Docker版 どちらを選ぶか
よくあるエラーと解決策
まとめ
etcd とは何か
etcd(/ˈɛt sɛd/ と読みます)は CoreOS が開発した分散型のキー・バリューストア です。名前の由来は Linux の設定ファイルが入る /etc ディレクトリ + 分散(distributed)から来ています。
特徴は3つあります:
Raft コンセンサスアルゴリズム :複数ノードで多数決をとりながら一貫性を保ちます。3ノードなら1台が落ちても動き続けます
強い一貫性(Strong Consistency) :どのノードに読みに行っても、最新の値が返ってきます。RDB よりシンプルですが、保証は強い
Watch API :キーの変化を購読できます。Kubernetes はこれを使って「Pod が追加されたら即座にスケジューラが動く」を実現しています
Kubernetes 以外では、Patroni(PostgreSQL HA)のリーダー選出や、Consul の代替として使われることもあります。
Ubuntu 24.04 への apt インストール
手順1:パッケージを更新してインストールする
Ubuntu 24.04 には etcd 3.4.30 が公式リポジトリに入っています。学習・シングルノード用途ならこれで十分です。
ubuntu@linuxlab: ~
$ sudo apt-get update
$ sudo apt-get install -y etcd-server etcd-client
Reading package lists… Done
Unpacking etcd-server (3.4.30-1ubuntu0.24.04.3) …
Unpacking etcd-client (3.4.30-1ubuntu0.24.04.3) …
Setting up etcd-client (3.4.30-1ubuntu0.24.04.3) …
Setting up etcd-server (3.4.30-1ubuntu0.24.04.3) …
インストール後にバージョンを確認します。
ubuntu@linuxlab: ~
$ etcd –version
etcd Version: 3.4.30
Git SHA: Not provided (use ./build instead of go build)
Go Version: go1.22.2
Go OS/Arch: linux/amd64
$ etcdctl version
etcdctl version: 3.4.30
API version: 3.4
apt install etcd-server の実行ログ(Ubuntu 24.04)
シングルノードで起動してみる
手順2:etcd を単独起動してKVを試す
apt でインストールしたら、まず1台で動かして感覚をつかんでおきましょう。etcd コマンドを引数なしで叩くと、デフォルト設定でシングルノードとして起動します。
ubuntu@linuxlab: ~
$ etcd &
{“level”:”info”,”ts”:”…”,”msg”:”etcd Version”,”etcd-version”:”3.4.30″}
{“level”:”info”,”ts”:”…”,”msg”:”starting single-node…”}
{“level”:”info”,”ts”:”…”,”msg”:”serving client traffic…”}
$ etcdctl put greeting “hello etcd”
OK
$ etcdctl get greeting
greeting
hello etcd
$ kill %1
注意
シングルノードの etcd はディスクの /var/lib/etcd/ にデータを永続化します。テスト後に sudo systemctl stop etcd でサービスを停止し、不要なら sudo rm -rf /var/lib/etcd/default/ でデータを削除してください。
3ノードクラスターを Docker で構築する
etcd の本領発揮は複数ノードのクラスター構成です。ここでは Docker で3ノードを立ち上げます。1台のマシン上でも docker network で分離すれば本物のクラスター動作を体験できます。
手順3:Docker ネットワークを作成する
ubuntu@linuxlab: ~
$ docker network create etcd-cluster-net
eecde175bc4975e0fc646b2432f65d71ce4a93002c23d758a958a8401c48e784
手順4:3ノードを起動する
各ノードに --initial-cluster で全メンバーを教え、--initial-cluster-state new で初回起動を指示します。ここが etcd 設定の核心です。
ubuntu@linuxlab: ~
$ TOKEN=etcd-cluster-token-001
$ CLUSTER=”etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380″
# etcd1 起動
$ docker run -d –name etcd1 –network etcd-cluster-net \
-p 2379:2379 \
quay.io/coreos/etcd:v3.5.16 etcd \
–name etcd1 \
–initial-advertise-peer-urls http://etcd1:2380 \
–listen-peer-urls http://0.0.0.0:2380 \
–advertise-client-urls http://etcd1:2379 \
–listen-client-urls http://0.0.0.0:2379 \
–initial-cluster-token $TOKEN \
–initial-cluster “$CLUSTER” \
–initial-cluster-state new
59af9ff418d6…
# etcd2、etcd3 も同様に起動(–name と URL を変えるだけ)
注意
--initial-cluster-state new は最初の1回だけ 使います。既存クラスターに追加参加する場合は existing に変更します。間違えるとスプリットブレイン(2つのクラスターが独立して動く)が起きます。
手順5:クラスターの状態を確認する
ubuntu@linuxlab: ~
$ docker exec etcd1 etcdctl \
–endpoints=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 \
member list
86c5057f999a4a72, started, etcd1, http://etcd1:2380, http://etcd1:2379, false
a7a85e21444f38d7, started, etcd3, http://etcd3:2380, http://etcd3:2379, false
ba43ff6c37415a1c, started, etcd2, http://etcd2:2380, http://etcd2:2379, false
$ docker exec etcd1 etcdctl \
–endpoints=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 \
endpoint health
http://etcd1:2379 is healthy: successfully committed proposal: took = 1.502ms
http://etcd2:2379 is healthy: successfully committed proposal: took = 1.517ms
http://etcd3:2379 is healthy: successfully committed proposal: took = 1.583ms
3ノードクラスター member list / endpoint health(実測)
3ノード全員が is healthy と返ってきたら成功です。endpoint status でリーダーも確認できます。私が実測したときは etcd2 がリーダー(IS LEADER = true)になっていました。どのノードがリーダーになるかは Raft の選出結果次第なので、毎回変わります。
KV操作の基本(put / get / watch / lease)
①put と get — 設定値を書き込んで読み出す
etcd のキーはスラッシュ区切りのパス形式が一般的です。Kubernetes の設定は /registry/pods/default/... のような形式で保存されています。
ubuntu@linuxlab: ~
$ etcdctl put /config/app/env production
OK
$ etcdctl put /config/app/version “v2.5.1”
OK
$ etcdctl put /services/web/addr “10.0.0.1:8080”
OK
$ etcdctl get /config/app/ –prefix
/config/app/env
production
/config/app/version
v2.5.1
--prefix フラグで「指定パス以下の全キー」を一括取得できます。これが設定管理に etcd が使われる理由のひとつです。
etcdctl put/get/lease 操作デモ(実測)
②watch — キーの変化をリアルタイムに受け取る
Watch は etcd の強力な機能です。あるキーが更新されたら即座に通知を受け取れます。Kubernetes は Watch API を使って Pod の追加を検知し、スケジューラを動かしています。
ubuntu@linuxlab: ~ (ターミナル1:監視)
$ etcdctl watch /config/app/version
# ここで別ターミナルから put すると即座に表示される
ubuntu@linuxlab: ~ (ターミナル2:更新)
$ etcdctl put /config/app/version “v2.6.0”
OK
# ターミナル1 に即座に以下が表示される:
PUT
/config/app/version
v2.6.0
③lease — TTL付きキーでセッション管理
リース(lease)は有効期限付きのトークンです。リースにキーを紐付けると、リースが切れたときにそのキーも自動で消えます。分散ロックやサービスの死活監視(ヘルスチェック)に使われます。
ubuntu@linuxlab: ~
$ etcdctl lease grant 30
lease 4a729ee3cd36630d granted with TTL(30s)
$ etcdctl put /session/user1 “logged_in” –lease=4a729ee3cd36630d
OK
$ etcdctl lease timetolive 4a729ee3cd36630d
lease 4a729ee3cd36630d granted with TTL(30s), remaining(29s)
# 30秒後 /session/user1 は自動削除される
$ etcdctl lease keepalive 4a729ee3cd36630d
# keepalive を送り続けるとTTLがリセットされ生き続ける
lease 4a729ee3cd36630d keepalived with TTL(30s)
フェイルオーバーを実測する
正直、これが今回の記事で一番驚いた実験です。etcd2 がリーダーだった状態で docker stop etcd2 を実行してから 約4秒 で etcd1 が新リーダーとして再選出されました。しかもフェイルオーバー中に書き込んだデータも含めて一切失われませんでした。
手順6:リーダーを強制停止してフェイルオーバーを確認する
ubuntu@linuxlab: ~
# 現在のリーダーは etcd2 (Raft term=2)
$ docker stop etcd2
etcd2
# 約4秒後…
$ etcdctl –endpoints=http://etcd1:2379,http://etcd3:2379 endpoint status –write-out=table
+——————-+——————+———+———+———–+——–+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | TERM |
+——————-+——————+———+———+———–+——–+
| http://etcd1:2379 | 86c5057f999a4a72 | 3.5.16 | 20 kB | true | 3 |
| http://etcd3:2379 | a7a85e21444f38d7 | 3.5.16 | 20 kB | false | 3 |
+——————-+——————+———+———+———–+——–+
$ etcdctl –endpoints=http://etcd1:2379 get /config/app/env
/config/app/env
production ← データ損失ゼロ
リーダー停止→再選出の実測ログ(Raft term 2→3)
Raft term が 2 から 3 に上がっています。これは「第3期の選挙でリーダーが決まった」という意味です。etcd1 と etcd3 の2ノードが「過半数」なので、etcd2 なしでもクラスターは機能を維持できます。Raft の多数決がここで効いています。
etcd2 を再起動すると自動的にクラスターに再参加し、欠落していた Raft ログを同期してから follower として加わります。
ubuntu@linuxlab: ~
$ docker start etcd2
etcd2
$ etcdctl –endpoints=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 endpoint health
http://etcd1:2379 is healthy: successfully committed proposal: took = 1.226ms
http://etcd2:2379 is healthy: successfully committed proposal: took = 1.283ms
http://etcd3:2379 is healthy: successfully committed proposal: took = 1.271ms
フェイルオーバー実測の端末ログ(スクリーンショット)
systemd でサービス管理する
apt でインストールすると etcd.service が自動で登録されます。実際のユニットファイルを確認してみます。
ubuntu@linuxlab: ~
$ sudo systemctl start etcd
$ sudo systemctl enable etcd
Created symlink /etc/systemd/system/etcd2.service → /lib/systemd/system/etcd.service.
$ sudo systemctl status etcd
● etcd.service – etcd – highly-available key value store
Loaded: loaded (/lib/systemd/system/etcd.service; enabled)
Active: active (running)
Main PID: 1234 (etcd)
Status: “ready”
設定は /etc/default/etcd で環境変数として渡します。ETCD_NAME、ETCD_DATA_DIR、ETCD_LISTEN_CLIENT_URLS などをここに書くと、コマンドラインオプションを並べなくて済みます。
ubuntu@linuxlab: ~
$ sudo cat /etc/default/etcd
ETCD_NAME=node1
ETCD_DATA_DIR=/var/lib/etcd/node1
ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
ETCD_ADVERTISE_CLIENT_URLS=http://192.168.1.10:2379
ETCD_INITIAL_CLUSTER=”node1=http://192.168.1.10:2380,node2=http://192.168.1.11:2380,node3=http://192.168.1.12:2380″
ETCD_INITIAL_CLUSTER_STATE=new
ETCD_INITIAL_CLUSTER_TOKEN=my-etcd-token
Kubernetes との連携
Kubernetes は etcd を「唯一の真実の源(Single Source of Truth)」として使います。kubectl get pod で見ているデータは、実は etcd から読み出されています。
Kubernetes が etcd に保存しているもの
リソース種別
etcd のパス(例)
説明
Pod
/registry/pods/default/my-pod
Pod のspec・status・labelsがJSON形式で保存
Service
/registry/services/specs/default/my-svc
ClusterIP・ポート情報
ConfigMap
/registry/configmaps/default/my-config
アプリケーション設定値
Secret
/registry/secrets/default/my-secret
暗号化されて保存(EncryptionConfig が必要)
Node
/registry/minions/node1
ノードのステータス・リソース容量
etcdctl で K8s クラスターの etcd を直接読む
kubeadm でセットアップしたクラスターなら、コントロールプレーンノードで以下のように etcd の中身を直接参照できます。本番では読み取り専用でも慎重に扱ってください。
ubuntu@k8s-master: ~
# kubeadm クラスターでの etcd 接続(TLS認証あり)
$ ETCDCTL_API=3 etcdctl \
–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 \
get /registry/pods/default/ –prefix –keys-only | head -5
/registry/pods/default/nginx-6799fc88d8-abc12
/registry/pods/default/redis-7d9f5b88-xyz99
注意
本番の K8s クラスターで etcd に直接書き込むと、Kubernetes が管理するリソースと不整合が起きてクラスターが壊れます 。読み取り専用(get/ls)に留めてください。バックアップには etcdctl snapshot save を使います。
etcd のスナップショットバックアップ
K8s クラスター管理で最重要な定期作業がこれです。
ubuntu@k8s-master: ~
$ ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-snapshot-$(date +%Y%m%d).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
{“level”:”info”,”ts”:”…”,”msg”:”saved”,”path”:”/backup/etcd-snapshot-20260620.db”}
$ etcdctl snapshot status /backup/etcd-snapshot-20260620.db –write-out=table
+———-+———-+————+————+
| HASH | REVISION | TOTAL KEYS | TOTAL SIZE |
+———-+———-+————+————+
| a8d7c2e1 | 18234 | 3412 | 4.2 MB |
+———-+———-+————+————+
apt版 vs Docker版 どちらを選ぶか
apt版(v3.4)vs Docker版(v3.5)比較表(実測)
項目
apt版(Ubuntu 24.04)
Docker版(最新安定)
バージョン
3.4.30
3.5.16
etcdctl API
3.4
3.5
Go バージョン
go1.22.2
go1.22.7
インストール
apt install etcd-server
docker run quay.io/coreos/etcd
systemd 管理
自動(etcd.service)
Docker daemon 管理
推奨用途
学習・シングルノード
本番クラスター
学習目的なら apt 版で十分です。コマンドがすぐ使えて systemd で管理できます。本番の3ノードクラスターを作るなら Docker(または kubeadm / kops などのツールを通じて K8s が自動セットアップする)v3.5 系を使います。v3.5 は v3.4 との後方互換性があるので、etcdctl コマンドの使い方は基本的に同じです。
よくあるエラーと解決策
①「request cluster ID mismatch」が出てクラスターに参加できない
エラー例
request cluster ID mismatch (got xxx want yyy)
原因は --initial-cluster-token が既存クラスターと違うか、古いデータが data-dir に残っているためです。新しくクラスターを作り直す場合 は各ノードの data-dir(デフォルト /var/lib/etcd/default/)を削除してから再起動します。
②「no leader」エラーが出る
エラー例
etcdserver: no leader
3ノードクラスターで2台以上が落ちると過半数(quorum)を失い、このエラーが出ます。残り1台だけでは書き込みを受け付けません。2台以上を復旧させてからクラスター状態を確認します。
③etcdctl でタイムアウトする
エラー例
context deadline exceeded
--endpoints で接続先を正しく指定しているか確認します。Docker の場合はコンテナ名がDNSで解決されるか、または IP アドレスを直接指定します。また --dial-timeout 10s オプションでタイムアウトを延ばすことも有効です。
まとめ
etcd は Kubernetes の裏で黙々と動いていますが、単体で触ってみると Raft の動きや KV 操作の感覚がつかめます。
Ubuntu 24.04 への apt インストールは 1コマンド、バージョンは v3.4.30
Docker で3ノードクラスターを構築し、全ノード is healthy を実測確認
put/get --prefix で階層的な設定管理、lease grant で TTL付きキーを実演
リーダー(etcd2)を強制停止 → 約4秒で etcd1 がリーダー再選出 、データ損失ゼロを実測
K8s の kubeadm クラスターでは TLS 証明書を使って etcd に接続、定期的な snapshot save が必須
次に試すなら TLS 相互認証の設定 (本番では必須)か、Patroni と組み合わせた PostgreSQL HA 構成 あたりが面白いです。
etcd を本番で動かすなら、最低でも 8GB RAM・SSD のVPSを3台用意するのが現実的です。VPS の初期設定手順はこちら にまとめています。
Consul のサービスディスカバリーと etcd を組み合わせた構成は Consul セットアップガイド も参考にしてください。
コメント