iT邦幫忙

2026 iThome 鐵人賽

DAY 29
0
Kubernetes

從零到 CKA:30 天掌握 Kubernetes 核心觀念與實作系列 第 29

Day 29|etcd — Kubernetes 的狀態資料核心

  • 分享至 

  • xImage
  •  

前言

昨天,我們用 cert-manager 自動簽發了 TLS 憑證,也實際看到了 Custom Resource、Controller 與 Secret 之間的運作方式。

但你有沒有想過:當你執行 kubectl get podkubectl get deploymentkubectl get certificate 時,這些資源的狀態究竟存在哪裡?

答案就是 etcd

etcd 是 Kubernetes Control Plane 用來保存叢集狀態的重要 Key-Value Store。

不管是 Pod、Service、Deployment,還是 cert-manager 建立的 Certificate、Issuer 與 Secret,這些 Kubernetes API Resource 的狀態最終都會由 API Server 持久化到 etcd。

可以把 etcd 想成整個 Kubernetes 叢集的「記憶核心」:

API Server 負責提供操作入口,而 etcd 負責保存叢集目前知道的狀態。

如果 etcd 發生嚴重故障,Control Plane 就會失去可靠的狀態讀寫能力,新的資源建立、更新與排程等操作都可能受到影響。

今天我們會先理解 etcd 在 Kubernetes 裡的角色與資料流向,接著認識它背後的 Raft 共識機制,再實際查看 etcd 儲存的資料,最後完成備份與還原操作。

今天內容涵蓋:

  1. 什麼是 etcd? — 認識 etcd 在 Kubernetes 中的角色
  2. Raft 共識演算法 — 理解 Leader、Quorum 與資料同步
  3. 實作一:探索 etcd 中的資料 — 用 etcdctl 查看叢集與儲存內容
  4. 實作二:備份與還原 etcd — 建立 Snapshot 並完成 Restore
  5. etcd 的健康檢查與效能調校 — 檢查健康狀態與日常維運重點

以下操作皆在 master 節點執行。


一、什麼是 etcd?

一個分散式的 Key-Value Store

etcd 是一個具備強一致性的分散式 Key-Value Store

簡單來說,可以把 etcd 想成 Kubernetes Control Plane 共用的「狀態資料庫」:

  • Key-Value:使用 Key 對應 Value 的方式儲存資料,例如 Kubernetes 內部會以類似 /registry/... 的路徑組織資源資料
  • 分散式:可以由多個 Member 組成 etcd Cluster,並在節點之間複製資料
  • 強一致性:透過 Raft 共識機制,確保多個 Member 對已提交的資料變更維持一致

為什麼 Kubernetes 選擇 etcd?

需求 etcd 怎麼滿足
叢集狀態要可靠儲存 透過 Raft 在多個 Member 之間複製並提交資料
多個 API Server 要讀寫同一份資料 多個 kube-apiserver 可以共用同一個 etcd Cluster
Controller 需要監聽資源變化 etcd 提供 Watch 能力,kube-apiserver 再向其他元件提供 Kubernetes Watch API
Control Plane 需要低延遲存取 etcd 專門針對一致性與 Metadata 類型的工作負載設計

💡 連結 Day 27–28

還記得 cert-manager Controller 會監聽 Certificate 資源的變化嗎?

cert-manager 並不會直接連線 etcd,而是透過 Kubernetes API Server 的 Watch API 接收資源變化。

當你執行:

kubectl apply
     ↓
kube-apiserver
     ↓
   etcd

資源狀態被持久化後,kube-apiserver 會透過 Watch 機制把對應的變化提供給正在監聽的 Controller,cert-manager 再開始進行 Reconciliation。

etcd 在 Kubernetes 架構中的位置

https://ithelp.ithome.com.tw/upload/images/20260824/20181928q9GagybCfV.png

⚠️ 重要觀念

在標準 Kubernetes 架構中,kube-apiserver 是直接讀寫 etcd 的 Control Plane 元件。

kube-schedulerkube-controller-manager、kubelet,以及 cert-manager 等 Controller,都是透過 Kubernetes API Server 讀取或修改叢集狀態,而不是直接操作 etcd。


二、Raft 共識演算法

etcd 的高可用與一致性能力,核心來自 Raft 共識演算法

Raft 讓多個 etcd Member 可以針對資料變更達成一致,即使部分節點發生故障,只要叢集仍然維持 Quorum,就可以繼續運作。

三個角色

可以把 Raft 想成一艘船上的三種角色:

角色 做什麼 比喻
Leader 負責協調新的寫入,將 Log Entry 複製到其他 Member 船長 —— 負責下達新的航行指令
Follower 接收 Leader 的 AppendEntries,並回應投票與複製請求 水手 —— 接收船長指令並同步航海日誌
Candidate Election Timeout 到期後發起新一輪選舉 候選船長 —— Leader 失聯後爭取其他節點投票

Leader 選舉流程

https://ithelp.ithome.com.tw/upload/images/20260824/20181928Dq5VdUbd8L.png

💓 什麼是 Heartbeat?

Leader 當選後,會定期向 Follower 發送 AppendEntries RPC。

當沒有新的 Log Entry 時,這些請求可以是空的,主要用來告訴 Follower:「Leader 還活著」。

如果 Follower 在 Election Timeout 內都沒有收到有效的 Heartbeat,就可能轉成 Candidate 並發起新的選舉。

當有新的 Log Entry 需要同步時,AppendEntries 也會負責將資料複製到 Follower。

寫入流程(Log Replication)

https://ithelp.ithome.com.tw/upload/images/20260824/20181928yiiKqMWoYV.png

當新的寫入發生時,大致流程是:

  1. Leader 先將新的 Log Entry 加入自己的 Log
  2. Leader 使用 AppendEntries 將 Log Entry 複製到 Follower
  3. 當該 Entry 已複製到多數 Member 後,Leader 就可以將它標記為 committed
  4. committed Entry 會被套用到狀態機,最後再回應 Client

為什麼要奇數節點?

Raft 需要取得 多數節點(Quorum) 才能繼續進行共識操作。

Quorum 可以簡單理解成:

Quorum = floor(N / 2) + 1
節點數 Quorum 可容忍故障數 說明
1 1 0 單節點,不具備節點故障容錯
2 2 0 任一 Member 故障都會失去 Quorum
3 2 1 ✅ 常見的 HA 配置
4 3 1 與 3 個 Member 的故障容忍數相同
5 3 2 ✅ 可以容忍 2 個 Member 故障

💡 為什麼通常使用奇數 Member?

因為偶數 Member 通常不會提升故障容忍能力。

例如 3 個 Member 和 4 個 Member 都只能容忍 1 個 Member 故障,但 4 個 Member 需要多維護一份資料複製與網路通訊。

因此 etcd 通常建議使用奇數個 Member,例如 3 或 5 個。


三、實作一:探索 etcd 中的資料

概念講完了,接下來直接看看 etcd 裡實際存了什麼。

Step 1:確認 etcd 的運行狀態

在 kubeadm 建立的叢集中,etcd 預設會以 Static Pod 的形式運行在 Control Plane Node 上。

先確認 etcd Pod 是否正常:

kubectl get pods -n kube-system | grep etcd

https://ithelp.ithome.com.tw/upload/images/20260824/2018192869t6OlY1SY.png

應該會看到類似:

etcd-master

只要 Pod 顯示為 Running,就代表 etcd 目前有正常運行。

Step 2:安裝 etcdctl 與 etcdutl

在 kubeadm 環境中,etcd 通常以 Static Pod 的形式運行,主機上不一定會預先安裝 etcdctletcdutl

先確認目前 etcd 使用的版本:

kubectl describe pod etcd-master -n kube-system | grep Image:

輸出類似:

Image: registry.k8s.io/etcd:3.6.4-0

https://ithelp.ithome.com.tw/upload/images/20260824/20181928fgsptzuQhT.png

接著安裝對應版本的 etcdctletcdutl

# Kubernetes 的 etcd Image Tag 可能帶有 "-0" 後綴,
# GitHub Release 則使用 v3.6.4 這類版本號
ETCD_VER=v3.6.4

curl -L \
  https://github.com/etcd-io/etcd/releases/download/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz \
  -o /tmp/etcd.tar.gz

tar xzf /tmp/etcd.tar.gz -C /tmp/

sudo mv /tmp/etcd-${ETCD_VER}-linux-amd64/etcdctl /usr/local/bin/
sudo mv /tmp/etcd-${ETCD_VER}-linux-amd64/etcdutl /usr/local/bin/

rm -rf /tmp/etcd.tar.gz /tmp/etcd-${ETCD_VER}-linux-amd64

確認版本:

etcdctl version

https://ithelp.ithome.com.tw/upload/images/20260824/20181928IPudTmnviQ.png

⚠️ 版本建議保持一致

實作時建議讓 etcdctletcdutl 與 etcd Server 使用相同版本,避免因版本差異造成操作行為或功能不一致。

Step 3:設定 etcdctl 連線資訊

kubeadm 建立的 etcd 預設使用 TLS 保護 Client Connection,因此 etcdctl 需要指定 Endpoint、CA 與 Client Certificate。

export ETCDCTL_ENDPOINTS=https://127.0.0.1:2379
export ETCDCTL_CACERT=/etc/kubernetes/pki/etcd/ca.crt
export ETCDCTL_CERT=/etc/kubernetes/pki/etcd/healthcheck-client.crt
export ETCDCTL_KEY=/etc/kubernetes/pki/etcd/healthcheck-client.key

其中:

  • ETCDCTL_ENDPOINTS:etcd Client Endpoint
  • ETCDCTL_CACERT:驗證 etcd Server 憑證的 CA
  • ETCDCTL_CERT:etcdctl 使用的 Client Certificate
  • ETCDCTL_KEY:Client Certificate 對應的 Private Key

可以先測試是否能正常連線:

etcdctl endpoint health

正常情況下會看到類似:

https://127.0.0.1:2379 is healthy

💡 關於 ETCDCTL_API=3

不需要再設定:

export ETCDCTL_API=3

etcdctl 從 v3.4 起就已經預設使用 v3 API,而 etcd v3.6 也已移除舊的 v2 Server API 支援。

Step 4:確認 etcd 連線

先確認目前是否能正常連線到 etcd:

etcdctl endpoint health

如果連線正常,會看到類似:

https://127.0.0.1:2379 is healthy

https://ithelp.ithome.com.tw/upload/images/20260824/20181928AGqIOuTqky.png

如果畫面出現:

unrecognized environment variable "ETCDCTL_API=3"

代表目前 Shell 還保留舊版 etcdctl 使用的環境變數,可以移除:

unset ETCDCTL_API

etcd 3.6 已經不需要再設定 ETCDCTL_API=3

接著查看 etcd Cluster 的成員:

etcdctl member list -w table

https://ithelp.ithome.com.tw/upload/images/20260824/20181928ukosVrjc7C.png

這個 Lab 是單節點 etcd,因此只會看到一個 Member:

master

在多 Control Plane 的 HA 架構中,則通常會看到多個 etcd Member。

Step 5:探索 Kubernetes 的資料結構

接下來直接查看 etcd 裡儲存的 Key:

etcdctl get / --prefix --keys-only | head -30

https://ithelp.ithome.com.tw/upload/images/20260824/201819288Rx97LH0Ve.png

可以看到 Kubernetes 的資源資料通常會儲存在 /registry/ 這個 Storage Prefix 底下,再依照不同資源類型組織資料。

例如截圖中可以看到:

/registry/apiextensions.k8s.io/customresourcedefinitions/certificates.cert-manager.io
/registry/apiextensions.k8s.io/customresourcedefinitions/certificaterequests.cert-manager.io
/registry/apiextensions.k8s.io/customresourcedefinitions/clusterissuers.cert-manager.io

💡 連結 Day 28

這些 Key 就是 Day 28 安裝 cert-manager 時建立的 CRD 定義

certificates.cert-manager.iocertificaterequests.cert-manager.io 等 CRD 本身也是 Kubernetes Resource,因此它們的狀態同樣會由 kube-apiserver 持久化到 etcd。

至於我們實際建立的 CertificateCertificateRequest 等 Custom Resource,也會由 kube-apiserver 儲存在 etcd,只是會位於各自對應的 Storage Key 下。

Step 6:查看特定資源的內容

先直接查看某個 Namespace 在 etcd 中的資料:

etcdctl get /registry/namespaces/default

https://ithelp.ithome.com.tw/upload/images/20260824/20181928zqpJLc7kBt.png

你會看到輸出中混雜著可讀文字,例如 defaultActive,以及一些看起來像亂碼的二進位內容。

這是因為 kube-apiserver 在 etcd 中儲存許多內建 Kubernetes Resource 時,通常會使用 Protocol Buffers(Protobuf) 進行序列化,而不是直接存成 JSON。

Protobuf 是一種緊湊的二進位格式,因此:

  • 字串內容有時仍然可以直接看到
  • 欄位結構與其他資訊則會以二進位形式呈現

💡 補充

Custom Resource 的儲存格式可能不同,CRD 建立的資源通常不會使用和內建資源完全相同的 Protobuf Schema。

接著看看目前 etcd 裡總共有多少 Key:

etcdctl get / --prefix --keys-only | wc -l

https://ithelp.ithome.com.tw/upload/images/20260824/20181928CN5lusPFCX.png

這個數字代表目前 etcd 中儲存的 Key 數量

它不完全等於 Kubernetes Resource 的數量,但可以讓你感受到一個叢集背後其實保存了大量的狀態資料。


四、實作二:備份與還原 etcd

etcd 保存了 Kubernetes 叢集的重要狀態資料,因此定期建立 Snapshot 是 Control Plane 維運中非常重要的一環。

Step 1:備份 etcd

先建立備份目錄:

mkdir -p /opt/etcd-backup

接著使用 etcdctl snapshot save 建立 Snapshot:

etcdctl snapshot save /opt/etcd-backup/snapshot-$(date +%Y%m%d).db

https://ithelp.ithome.com.tw/upload/images/20260824/20181928N9HP23Go8l.png

成功後會看到類似:

Snapshot saved at /opt/etcd-backup/snapshot-20260306.db

如果要確認 Snapshot 的內容,可以使用 etcdutl snapshot status

etcdutl snapshot status \
  /opt/etcd-backup/snapshot-$(date +%Y%m%d).db \
  -w table

輸出會包含 Snapshot 的 Hash、Revision、Key 數量與檔案大小。

Step 2:模擬資源誤刪

為了驗證 Snapshot 還原是否真的有效,我們先建立一個測試用的 Deployment,接著再把它刪除,模擬資源被誤刪的情境。

# 記錄目前的 Deployment 列表
kubectl get deployments -A

https://ithelp.ithome.com.tw/upload/images/20260824/20181928jv2edEAB3f.png

建立一個測試用的 Deployment:

kubectl create deployment etcd-test \
  --image=nginx \
  --replicas=2

確認 Deployment 已正常建立:

kubectl get deployment etcd-test

https://ithelp.ithome.com.tw/upload/images/20260824/20181928hheClKq4WF.png

接著再建立一份 Snapshot,確保這份備份中包含 etcd-test

etcdctl snapshot save /opt/etcd-backup/snapshot-with-test.db

現在模擬資源被誤刪:

kubectl delete deployment etcd-test

確認它已經不存在:

kubectl get deployment etcd-test

預期會看到:

Error from server (NotFound): deployments.apps "etcd-test" not found

https://ithelp.ithome.com.tw/upload/images/20260824/20181928jvHCUsdSB3.png

Step 3:還原 etcd

⚠️ 注意

還原 etcd 會讓叢集狀態回到 Snapshot 建立時的時間點,Snapshot 之後建立或修改的 Kubernetes Resource 都可能消失。

正式環境操作前,務必確認 Snapshot、etcd Member 設定與還原流程都正確。

先停止 kube-apiserver 與 etcd 的 Static Pod:

sudo mv /etc/kubernetes/manifests/kube-apiserver.yaml /tmp/
sudo mv /etc/kubernetes/manifests/etcd.yaml /tmp/

等待 kubelet 停止對應容器:

sleep 10
sudo crictl ps | grep -E "etcd|kube-apiserver"

如果沒有輸出,代表兩個容器都已經停止。

接著保留目前的 etcd Data Directory:

sudo mv /var/lib/etcd /var/lib/etcd.bak

使用剛才包含 etcd-test Deployment 的 Snapshot 進行還原:

sudo etcdutl snapshot restore \
  /opt/etcd-backup/snapshot-with-test.db \
  --name=master \
  --data-dir=/var/lib/etcd \
  --initial-cluster=master=https://10.140.0.33:2380 \
  --initial-advertise-peer-urls=https://10.140.0.33:2380

💡 為什麼要指定這些參數?

snapshot restore 會建立新的 etcd Member 與 Cluster identity,因此這裡要讓還原後的 Member 設定與 kubeadm 的 etcd Static Pod 保持一致。

可以從 /etc/kubernetes/manifests/etcd.yaml 查看目前使用的 --name--initial-cluster--initial-advertise-peer-urls

還原完成後,把 Static Pod Manifest 放回去:

sudo mv /tmp/etcd.yaml /etc/kubernetes/manifests/
sudo mv /tmp/kube-apiserver.yaml /etc/kubernetes/manifests/

等待 Control Plane 恢復:

sleep 30

💡 正式 Kubernetes 災難復原的補充

如果是從較舊的 Snapshot 還原,etcd 官方建議考慮使用 --bump-revision--mark-compacted,避免 Kubernetes Controller / Informer 因 etcd Revision 倒退而保留過期 Cache。

Step 4:驗證還原結果

還原完成後,先重新設定 etcdctl 的連線資訊:

unset ETCDCTL_API

export ETCDCTL_ENDPOINTS=https://127.0.0.1:2379
export ETCDCTL_CACERT=/etc/kubernetes/pki/etcd/ca.crt
export ETCDCTL_CERT=/etc/kubernetes/pki/etcd/healthcheck-client.crt
export ETCDCTL_KEY=/etc/kubernetes/pki/etcd/healthcheck-client.key

先確認 etcd 是否恢復健康:

etcdctl endpoint health

接著確認 Kubernetes Control Plane 是否已恢復:

kubectl get nodes

最後驗證剛才被刪除的 Deployment 是否重新出現:

kubectl get deployment etcd-test

https://ithelp.ithome.com.tw/upload/images/20260824/20181928cGOBse2Wax.png

如果一切正常,你會再次看到 etcd-test Deployment。

這代表叢集狀態已經回到 Snapshot 建立時的時間點,也驗證了這次 etcd Snapshot Restore 成功。

https://ithelp.ithome.com.tw/upload/images/20260824/20181928HJ6PlzudyS.png


五、etcd 的健康檢查與效能調校

etcd 的延遲與健康狀態,會直接影響 Kubernetes Control Plane 的反應速度。

最後我們來看看幾個常用的健康檢查方式,以及日常維運時需要注意的效能指標。

基本健康檢查指令

# 查看 Endpoint 健康狀態
etcdctl endpoint health -w table
# 執行簡單的效能測試
etcdctl check perf

https://ithelp.ithome.com.tw/upload/images/20260824/20181928PHlmOL2eP8.png

endpoint health 主要用來確認 etcd 是否能正常處理請求。

check perf 則會對目前 Endpoint 做簡單的寫入效能測試,適合快速確認磁碟與 etcd 寫入表現是否明顯異常。

關鍵效能指標

指標 觀察重點
WAL fsync 延遲 越低越好;如果長期升高,通常要優先檢查磁碟 I/O
Backend commit 延遲 反映 Backend 寫入延遲,持續升高可能代表磁碟效能不足
Leader 選舉次數 應該維持低且穩定;頻繁選舉可能代表網路、CPU 或磁碟不穩定
DB Size 持續增長時要注意 Backend Quota、歷史 Revision 與碎片空間

💡 Backend Quota

etcd 的 Backend Database 有大小限制,常見預設值約為 2 GiB,但實際上可以透過 --quota-backend-bytes 調整,因此應以目前叢集設定為準。

etcd 資料壓縮與碎片整理

etcd 使用 MVCC 保存歷史 Revision。

隨著資料持續更新,舊 Revision 會逐漸累積,因此可以透過 Compaction 移除不再需要的舊歷史版本。

先取得目前 Revision:

rev=$(etcdctl endpoint status -w json | \
  python3 -c "import sys,json; print(json.loads(sys.stdin.read())[0]['Status']['header']['revision'])")

執行 Compaction:

etcdctl compact "$rev"

Compaction 只會讓舊 Revision 不再可讀,並不一定會立刻縮小實際的 Backend Database 檔案。

如果要進一步回收碎片空間,可以再執行:

etcdctl defrag

https://ithelp.ithome.com.tw/upload/images/20260824/20181928TBn4cHG377.png

⚠️ Defrag 會造成短暫阻塞

生產環境如果是多 Member etcd Cluster,不要同時對所有 Member 執行 Defrag。

建議逐個 Member 進行,並先確認叢集健康狀態。

生產環境最佳實踐

💡 etcd 維運重點

  • 使用 SSD 或其他低延遲儲存
  • etcd Member 之間保持穩定、低延遲的網路
  • 定期建立 Snapshot,並實際驗證還原流程
  • 監控 DB Size、WAL fsync、Backend commit 與 Leader Election
  • 生產環境通常使用 3 或 5 個 etcd Member

小結

今天我們深入了 Kubernetes 的資料核心 —— etcd,從基本概念一路做到資料探索、Snapshot 備份與還原。

學到的東西 一句話總結
etcd Kubernetes Control Plane 用來持久化叢集狀態的重要 Key-Value Store
Raft 共識演算法 透過 Leader 選舉、Log Replication 與 Quorum 維持多節點一致性
奇數節點原則 etcd Cluster 通常採奇數 Member,3 或 5 個最常見
etcdctl 探索 可以直接查看 etcd 中的 Storage Key 與 Kubernetes 原始儲存內容
備份與還原 使用 etcdctl snapshot save 備份,再透過 etcdutl snapshot restore 還原
效能與維運 低延遲儲存、穩定網路、監控指標與適當的 Compaction / Defrag 都很重要

從 Day 27 的 CRD 與 Operator、Day 28 的 cert-manager,到今天的 etcd,我們已經把 Kubernetes API、Controller 與底層狀態儲存之間的關係串了起來。

明天就是系列的最後一天,我們會實戰 Kubernetes 叢集升級,使用 kubeadm 將 Day 01 建立的 v1.34 叢集升級到 v1.35,完整走過一次 Control Plane 與 Worker Node 的升級流程!


參考資源


上一篇
Day 28|cert-manager — 自動申請、管理與續約 Kubernetes TLS 憑證
下一篇
Day 30|Kubernetes 叢集升級 — 使用 kubeadm 從 v1.34 升到 v1.35
系列文
從零到 CKA:30 天掌握 Kubernetes 核心觀念與實作31
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言