🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付

前言

TRIAL&RetailAI Advent Calendar 2025的第一篇文章。

今天的主題是“Kubernetes 深度解析(etcd + Raft)”。我在開發中一直使用 Kubernetes(k8s)。希望更深入地了解 k8s,並再次從基本的事項開始整理 etcd 和 Raft 的相關內容。

自我介紹

目前在基礎系統部門工作,主要負責後端開發。
在2024年也寫過Advent Calendar 的文章,希望有機會能讓您看到。

k8s 是什麼

k8s 是自動管理容器的容器編排系統
其特點在於將應用程序保持在「聲明式(desired state)」的狀態。

k8s 解決的問題

  1. 伺服器與容器的自動配置
  2. 自動化擴展(增減)
  3. 故障自我修復
  4. 負載均衡
  5. 設定與機密資訊的管理

基本架構

螢幕截圖 2025-11-30 14.41.57.png
引用來源:Cluster Architecture

控制平面的角色

  • 定義並維持整個集群的 desired state(應有狀態)
  • 監控並調整 Node 和 Pod 的狀態
  • 決定 Pod 的調度位置
  • 將整個集群的設定和狀態儲存在 etcd 中
組件 角色
API 伺服器 所有操作的入口點 REST API。
排程器 決定 Pod 配置在哪個 Node 上。
控制器管理器 透過各控制器將集群狀態調整至 desired state。
etcd Kubernetes 唯一的資料儲存庫(儲存所有設定和狀態)。

工作節點的角色

  • 執行 Pod(應用容器)
  • 管理容器的生命週期
  • 控制 Pod 的網路通信
  • 向控制平面報告狀態
組件 角色
Kubelet 管理 Node 內的 Pod,並與 API Server 通信。
Kube-Proxy 透過服務實現負載均衡和網路控制。
容器執行環境 實際執行容器(containerd / CRI-O 等)。

etcd

k8s 用於儲存內部狀態的分散式 Key-Value 儲存系統
控制平面的所有設定與狀態均儲存在 etcd 中。
因此,當 etcd 停止運作時,Kubernetes 整體會失去功能。

etcd 示範

# 因為使用 Mac,透過 Homebrew 安裝 etcd
brew install etcd

# 確認安裝
which etcd

# 啟動 etcd
export ETCDCTL_API=3
etcd

# 寫入值
# 在另一個終端機執行以下命令
etcdctl put foo "hello etcd"
> OK

# 取得值
etcdctl get foo
> OK
> foo
> hello etcd

# 監控變更
# 在另一個終端機執行以下命令
etcdctl watch foo

# 在更另一個終端機執行以下命令
etcdctl put foo "new value"
> OK

# 在執行 etcdctl watch foo 的終端機中實時確認變更
> PUT
> foo
> new value

您應該能體會到 Kubernetes 控制平面的組件(如 API Server 等)如何對 etcd 進行 "PUT / GET / WATCH" 操作。

Raft

Raft 是 etcd、Consul、TiKV 和 Kubernetes(內部的 etcd)所使用的
分散式共識演算法。這樣可以產生強一致性

要點 說明
Leader 僅有一台 為了防止寫入衝突並保持一致性。
所有寫入皆由 Leader 處理 分散式系統將數據線性化(Linearizable)的基本原則。
過半數(Majority)持有日誌後才會提交 為了在多個節點故障的情況下仍能正確恢復。
Leader 死後會自動選舉 透過故障轉移實現高可用性,集群不會停止。
etcd 強一致性的基礎 etcd 的讀/寫為何是線性化的原因在於 Raft 的日誌複製和選舉。
角色 說明
Leader 處理所有寫入請求的唯一節點,並將日誌複製至 Follower。
Follower 接收來自 Leader 的日誌複製,並應用於狀態機。
Candidate 若 Follower 在一段時間內無法與 Leader 通信則可參加選舉。

Raft 示範

# 在三個終端機上分別執行以下命令
# 第一個終端機
etcd \
  --name n1 \
  --listen-peer-urls http://127.0.0.1:2380 \
  --listen-client-urls http://127.0.0.1:2379 \
  --advertise-client-urls http://127.0.0.1:2379 \
  --initial-advertise-peer-urls http://127.0.0.1:2380 \
  --initial-cluster-token etcd-cluster \
  --initial-cluster n1=http://127.0.0.1:2380,n2=http://127.0.0.1:2382,n3=http://127.0.0.1:2384 \
  --initial-cluster-state new

# 第二個終端機
etcd \
  --name n2 \
  --listen-peer-urls http://127.0.0.1:2382 \
  --listen-client-urls http://127.0.0.1:2377 \
  --advertise-client-urls http://127.0.0.1:2377 \
  --initial-advertise-peer-urls http://127.0.0.1:2382 \
  --initial-cluster-token etcd-cluster \
  --initial-cluster n1=http://127.0.0.1:2380,n2=http://127.0.0.1:2382,n3=http://127.0.0.1:2384 \
  --initial-cluster-state new

# 第三個終端機
etcd \
  --name n3 \
  --listen-peer-urls http://127.0.0.1:2384 \
  --listen-client-urls http://127.0.0.1:2378 \
  --advertise-client-urls http://127.0.0.1:2378 \
  --initial-advertise-peer-urls http://127.0.0.1:2384 \
  --initial-cluster-token etcd-cluster \
  --initial-cluster n1=http://127.0.0.1:2380,n2=http://127.0.0.1:2382,n3=http://127.0.0.1:2384 \
  --initial-cluster-state new

# 在三者中的一個終端機上確認
{"level":"info","ts":"2025-11-30T15:14:15.626738+0900","logger":"raft","caller":"[email protected]/raft.go:970","msg":"b71f75320dc06a6c became leader at term 2"}

# 關閉三者中的 Leader 的終端機
# 在另一個終端機上確認 Leader 變更
"level":"info","ts":"2025-11-30T15:24:09.243345+0900","logger":"raft","caller":"[email protected]/raft.go:912","msg":"9e85cc091d4d15bb became candidate at term 3"}
{"level":"info","ts":"2025-11-30T15:24:09.243374+0900","logger":"raft","caller":"[email protected]/raft.go:1064","msg":"9e85cc091d4d15bb [logterm: 2, index: 9] sent MsgVote request to 42b4c95db84f2660 at term 3"}
{"level":"info","ts":"2025-11-30T15:24:09.243410+0900","logger":"raft","caller":"[email protected]/raft.go:1064","msg":"9e85cc091d4d15bb [logterm: 2, index: 9] sent MsgVote request to b71f75320dc06a6c at term 3"}
{"level":"info","ts":"2025-11-30T15:24:09.257516+0900","logger":"raft","caller":"[email protected]/raft.go:1077","msg":"9e85cc091d4d15bb received MsgVoteResp from 9e85cc091d4d15bb at term 3"}
{"level":"info","ts":"2025-11-30T15:24:09.257597+0900","logger":"raft","caller":"[email protected]/raft.go:1693","msg":"9e85cc091d4d15bb has received 1 MsgVoteResp votes and 0 vote rejections"}
{"level":"info","ts":"2025-11-30T15:24:09.262962+0900","logger":"raft","caller":"[email protected]/raft.go:1077","msg":"9e85cc091d4d15bb received MsgVoteResp from 42b4c95db84f2660 at term 3"}
{"level":"info","ts":"2025-11-30T15:24:09.263028+0900","logger":"raft","caller":"[email protected]/raft.go:1693","msg":"9e85cc091d4d15bb has received 2 MsgVoteResp votes and 0 vote rejections"}
{"level":"info","ts":"2025-11-30T15:24:09.263059+0900","logger":"raft","caller":"[email protected]/raft.go:970","msg":"9e85cc091d4d15bb became leader at term 3"}
{"level":"info","ts":"2025-11-30T15:24:09.263086+0900","logger":"raft","caller":"[email protected]/node.go:370","msg":"raft.node: 9e85cc091d4d15bb elected leader 9e85cc091d4d15bb at term 3"}

我想您會體驗到 k8s 的 API Server 如何通過這個機制實現 100% 安全的狀態保存。

總結

控制平面(如 API Server 等)和 etcd 的關係是 Kubernetes 的基礎

  • API Server 保存所有狀態變更至 etcd
  • 工作節點(Kubelet)依據 etcd 的狀態運行

Kubernetes 的可靠性由 etcd 支撐

  • 唯一的資料儲存庫,儲存所有設定與狀態
  • etcd 停止後,控制平面整體會失去功能

etcd 的強一致性(線性化讀/寫)由 Raft 實現

  • Leader 作為所有寫入的中心管理者
  • 在過半數保持日誌時進行「提交」
  • 在 Leader 故障時,透過自動選舉快速恢復
  • 為了安全運行分散式系統的日誌複製 + 選舉演算法
  • 角色分為以下三種:
    • Leader
    • Follower
    • Candidate
  • 設計不會在節點故障或網路斷線時損壞資料

最後

下次由 @mizoguchi_ryosuke 帶來的主題是『從遺傳性和曼斯基學習的「○○決定論」陷阱:在生成 AI 中實踐誠實的分析』。

敬請期待!!

RetailAI 和 TRIAL 正在招募工程師。
我們處理 Kotlin、Flutter、Go、Python等多種語言。
有興趣的人可以透過以下方式了解或發送訊息給我們。


原文出處:https://qiita.com/Plath/items/6a07fbbda5b443b4079a


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝15   💬3   ❤️3
315
🥈
我愛JS
📝1   💬3   ❤️2
45
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付