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