據(jù)底座:從零部署單節(jié)點etcd全流程解析)
學K8S和真正動手搭K8S之間隔著一個經(jīng)常被忽略又極其關(guān)鍵的組件——etcd。我見過不少朋友聊Pod、Deployment頭頭是道但問一句“K8S把集群狀態(tài)到底存在哪”答案就開始含糊了。實際上K8S控制面的所有狀態(tài)節(jié)點的調(diào)度結(jié)果、Pod的實時狀態(tài)、ConfigMap和Secret的內(nèi)容全部以鍵值對形式存放在etcd里。etcd才是那個真正決定“你現(xiàn)在看到的集群長什么樣”的數(shù)據(jù)庫。這篇文章從K8S基礎(chǔ)架構(gòu)講起帶著你把它最關(guān)鍵的數(shù)據(jù)底座拆開看明白然后完整走一遍單節(jié)點etcd服務(wù)的部署流程。過程中會把Raft協(xié)議的通俗邏輯、配置文件里每個字段的含義、systemd托管方法、備份恢復(fù)手段都講清楚。適合正在搭實驗環(huán)境、或者想徹底搞懂K8S控制面組件之間如何協(xié)作的人。內(nèi)容全部基于我實際搭建和踩坑的經(jīng)驗不是照搬文檔。1. 先把K8S的大體結(jié)構(gòu)講透etcd到底坐在哪張椅子上1.1 控制面的四塊拼圖API Server、調(diào)度器、控制器、etcdK8S集群從邏輯上分成兩大部分控制面和工作節(jié)點。工作節(jié)點是真正跑業(yè)務(wù)容器的地方控制面負責做決策、管狀態(tài)??刂泼胬锏暮诵慕M件主要有四個API Server、Controller Manager、Scheduler以及一個獨立的分布式鍵值存儲etcd。我用一個類比來解釋這四者的關(guān)系把K8S當成一家公司API Server是前臺接待處所有外部請求、內(nèi)部組件之間的溝通都要經(jīng)過它Controller Manager是拿著規(guī)章制度做檢查的部門不停確?,F(xiàn)實狀態(tài)和期望狀態(tài)一致Scheduler是排班員負責把任務(wù)分配合適的人而etcd就是這家公司的檔案室所有決定、所有現(xiàn)場記錄都寫進檔案業(yè)務(wù)人員要了解現(xiàn)狀也去檔案室查。沒有檔案室整個公司所有決策都會失去依據(jù)。所以控制面正常運行的基本路徑是你通過kubectl向API Server提交一個期望狀態(tài)API Server把這個期望狀態(tài)寫入etcdScheduler從etcd讀到新任務(wù)并做調(diào)度決策Controller Manager通過watch機制監(jiān)聽狀態(tài)變化并持續(xù)調(diào)整。etcd一旦不可用API Server連讀寫都無法完成整個集群的控制功能直接癱瘓。這也是為什么etcd在K8S里地位如此之高。1.2 為什么K8S的數(shù)據(jù)存儲偏偏是一個鍵值庫有人可能會想K8S這么復(fù)雜的系統(tǒng)為什么不用MySQL這種傳統(tǒng)數(shù)據(jù)庫理解這個問題的關(guān)鍵在于K8S對數(shù)據(jù)存儲的需求非常特殊。首先需要強一致。API Server是最核心的組件所有控制器都通過它讀取狀態(tài)如果讀到的數(shù)據(jù)是過期的或者不一致的調(diào)度和控制器就可能做出錯誤決策。etcd基于Raft共識算法能保證寫入一旦返回成功后續(xù)任何節(jié)點都能讀到這個值這就是強一致性。其次還需要監(jiān)聽Watch能力Controller Manager和Scheduler不需要定期輪詢數(shù)據(jù)而是訂閱key的變化數(shù)據(jù)一變就立即收到通知。這是K8S能對資源變化做出秒級響應(yīng)的重要原因。再就是Lease租約機制節(jié)點心跳、Pod存活都依賴這個能力租約到期自動清理避免用復(fù)雜任務(wù)定期掃描。用表格對比一下更直觀能力etcdRedisMySQL一致性Raft強一致主從異步復(fù)制可能丟數(shù)據(jù)半同步或組復(fù)制可以做到但部署重變更通知原生Watch有Pub/Sub但消息不持久、語義不同需解析binlog實現(xiàn)復(fù)雜租約機制內(nèi)建Lease有TTL但精準續(xù)約能力沒有etcd完善需自己寫表、寫定時任務(wù)命令事務(wù)支持mini-transactionLua腳本強事務(wù)能力部署形態(tài)獨立小進程適合組件間協(xié)調(diào)獨立進程重運維成本高一句話總結(jié)etcd是專門為“分布式系統(tǒng)中的協(xié)調(diào)狀態(tài)”設(shè)計的產(chǎn)品K8S需要的能力它剛好都有而這幾個能力在通用數(shù)據(jù)庫上要么缺失要么需要大量額外開發(fā)。所以K8S選etcd不是偶然是設(shè)計定位決定的。1.3 單節(jié)點etcd什么時候夠用什么時候?qū)儆凇皼]辦法只能這么干”單節(jié)點etcd部署在我的日常里非常常見基本集中在三類場景本地開發(fā)學習、搭建最小化K8S實驗集群、邊緣或離線環(huán)境里只要一個控制面。在這些場景下單節(jié)點etcd完全夠用。K8S實驗環(huán)境不追求可用性只追求“能跑、能練、能觀察”。而生產(chǎn)環(huán)境的K8S集群etcd幾乎都會以三個節(jié)點起步因為單節(jié)點一旦故障整個集群的控制權(quán)就沒了。這個取舍本質(zhì)上是你愿意為“控制器掛一臺”承受多大損失。學習環(huán)境都能接受生產(chǎn)環(huán)境堅決不能接受。所以這篇文章里的單節(jié)點部署本身就是一種“實驗室方案”我會把其中的得與失講明白。如果你在真實生產(chǎn)環(huán)境照搬我把話放前面至少組三臺etcd這只是底線。2. 動手前必須搞清楚的etcd核心機制2.1 Raft協(xié)議講成人話會議記錄員和過半確認etcd內(nèi)部最重要的東西就是Raft協(xié)議它負責讓集群里多個節(jié)點保持一致。不想讀論文的話可以把它理解成一套“全員投票的會議記錄機制”。集群里會選出一個Leader叫負責人負責把大家的修改意見記成日志然后分發(fā)給每個成員。每個成員收到后確認“我記下了”當超過一半的成員都確認之后這次修改才真正生效。單節(jié)點etcd的quorum是1也就是只需要自己確認就算生效沒有任何網(wǎng)絡(luò)分裂問題寫路徑極短。這也是單節(jié)點etcd性能表現(xiàn)不錯的原因之一。這里有個常識節(jié)點數(shù)設(shè)計通常取奇數(shù)三個節(jié)點允許壞一個五個節(jié)點允許壞兩個。原因也很簡單過半確認要求“嚴格超過一半”兩個節(jié)點反而比一個節(jié)點更脆弱。所以生產(chǎn)環(huán)境一定是三五七這樣的奇數(shù)組合。理解了Raft的過半機制你就會明白etcd的強一致性不是玄學是靠日志復(fù)制和投票保證的。2.2 版本選擇與數(shù)據(jù)落盤規(guī)劃部署etcd之前先干兩件事選版本、選目錄。etcd目前主流版本是3.5分支也是K8S較新版本控制面通用的選擇。版本跨度不要太大太老的3.3或者太新的4.x在沒有明確兼容依據(jù)前都不要碰。以我的經(jīng)驗看K8S官方文檔里那張“每個K8S版本推薦使用的etcd版本對照表”最穩(wěn)妥跟著選就行。數(shù)據(jù)目錄建議放在獨立磁盤上有條件優(yōu)先用SSD。etcd本質(zhì)上是一個寫敏感的存儲組件磁盤IO延遲會直接影響寫響應(yīng)時間進而影響K8S資源提交的延遲。單獨劃一個 /var/lib/etcd 目錄是為了權(quán)限隔離獨立磁盤則是為了性能隔離避免其他業(yè)務(wù)日志把磁盤IO占滿之后整個K8S控制面跟著遭殃。單節(jié)點etcd雖然不需要應(yīng)對集群通信但數(shù)據(jù)目錄膨脹是必須考慮的問題。默認后端配額是2GB達到配額后etcd會進入只讀模式K8S也就沒法再創(chuàng)建新資源。這個問題我會在后面的常見問題章節(jié)里詳細記錄這里先記住存儲空間不是越大越安心你得有一套監(jiān)控和壓縮方案。2.3 端口、目錄和權(quán)限動手前先畫一張小地圖etcd占用兩個端口2379是客戶端通信端口K8S的API Server通過它讀寫數(shù)據(jù)2380是集群節(jié)點間通信端口單節(jié)點環(huán)境用不到但配置里必須保留。用一張小地圖記憶2379面向外部2380面向內(nèi)部。目錄規(guī)劃建議如下可執(zhí)行文件/usr/local/bin/etcd、etcdctl配置文件/etc/etcd/etcd.conf.yml數(shù)據(jù)目錄/var/lib/etcd日志交給systemd的journald統(tǒng)一管理權(quán)限方面我們專門建一個名為etcd的系統(tǒng)用戶給它的權(quán)限就是數(shù)據(jù)目錄的讀寫權(quán)。不要用root去跑etcd雖然能跑但一旦被攻破或者誤操作權(quán)限邊界完全不同。最小權(quán)限原則在這里同樣適用。3. 單節(jié)點etcd服務(wù)部署全過程實錄3.1 環(huán)境準備與二進制安裝這里以一臺干凈的Linux服務(wù)器為例systemd作為初始化系統(tǒng)。單節(jié)點etcd的資源要求不高2核4G起步完全夠用關(guān)鍵是磁盤別太慢。第一步創(chuàng)建系統(tǒng)用戶和目錄useradd --system --home /var/lib/etcd --shell /sbin/nologin etcd mkdir -p /var/lib/etcd /etc/etcd chown -R etcd:etcd /var/lib/etcd然后去etcd官方Release頁面下載對應(yīng)版本的Linux amd64壓縮包。命令示例ETCD_VERv3.5.9 wget https://github.com/etcd-io/etcd/releases/download/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz tar zxf etcd-${ETCD_VER}-linux-amd64.tar.gz cp etcd-${ETCD_VER}-linux-amd64/etcd /usr/local/bin/ cp etcd-${ETCD_VER}-linux-amd64/etcdctl /usr/local/bin/ etcd --version etcdctl version熟悉Linux的直接用這種做法簡單透明也方便腳本化和固化版本。用發(fā)行版?zhèn)}庫安裝雖然省事但倉庫里的版本往往偏舊跟K8S版本兼容性不一定對得上。我是偏好二進制方案的特別是在這種“我應(yīng)該精確知道跑在什么版本上”的組件上。下載如果比較慢可以找靠譜的鏡像加速但一定校驗壓縮包的sha256避免文件損壞或者篡改。3.2 寫配置文件每一個字段都值得看懂etcd從3.4開始推薦使用YAML格式配置。下面是單節(jié)點環(huán)境一份最簡配置name: etcd-single>