在k8s集羣中使用了etcd做爲數據中心,在實際操做中遇到了一些坑。今天記錄一下,爲了之後更好操做。html
ETCD參數說明
- —data-dir 指定節點的數據存儲目錄,這些數據包括節點ID,集羣ID,集羣初始化配置,Snapshot文件,若未指定—wal-dir,還會存儲WAL文件;
- —wal-dir 指定節點的was文件的存儲目錄,若指定了該參數,wal文件會和其餘數據文件分開存儲。
- —name 節點名稱
- —initial-advertise-peer-urls 告知集羣其餘節點url.
- — listen-peer-urls 監聽URL,用於與其餘節點通信
- — advertise-client-urls 告知客戶端url, 也就是服務的url
- — initial-cluster-token 集羣的ID
- — initial-cluster 集羣中全部節點
節點遷移
在生產環境中,不可避免遇到機器硬件故障。當遇到硬件故障發生的時候,咱們須要快速恢復節點。ETCD集羣能夠作到在不丟失數據的,而且不改變節點ID的狀況下,遷移節點。
具體辦法是:node
- 1)中止待遷移節點上的etc進程;
- 2)將數據目錄打包複製到新的節點;
- 3)更新該節點對應集羣中peer url,讓其指向新的節點;
- 4)使用相同的配置,在新的節點上啓動etcd進程
-
etcd配置
-
node1
編輯etcd啓動腳本
/usr/local/etcd/start.sh
nginx/usr/local/etcd/etcd -name niub1 -debug \ -initial-advertise-peer-urls http://niub-etcd-1:2380 \ -listen-peer-urls http://niub-etcd-1:2380 \ -listen-client-urls http://niub-etcd-1:2379,http://127.0.0.1:2379 \ -advertise-client-urls http://niub-etcd-1:2379 \ -initial-cluster-token etcd-cluster-1 \ -initial-cluster niub1=http://niub-etcd-1:2380,niub2=http://niub-etcd-2:2380,niub3=http://niub-etcd-3:2380 \ -initial-cluster-state new >> /niub/etcd_log/etcd.log 2>&1 &
node2
編輯etcd啓動腳本
/usr/local/etcd/start.sh
web/usr/local/etcd/etcd -name niub2 -debug \ -initial-advertise-peer-urls http://niub-etcd-2:2380 \ -listen-peer-urls http://niub-etcd-2:2380 \ -listen-client-urls http://niub-etcd-2:2379,http://127.0.0.1:2379 \ -advertise-client-urls http://niub-etcd-2:2379 \ -initial-cluster-token etcd-cluster-1 \ -initial-cluster niub1=http://niub-etcd-1:2380,niub2=http://niub-etcd-2:2380,niub3=http://niub-etcd-3:2380 \ -initial-cluster-state new >> /niub/etcd_log/etcd.log 2>&1 &
node3
編輯etcd啓動腳本
/usr/local/etcd/start.sh
sql/usr/local/etcd/etcd -name niub3 -debug \ -initial-advertise-peer-urls http://niub-etcd-3:2380 \ -listen-peer-urls http://niub-etcd-3:2380 \ -listen-client-urls http://niub-etcd-3:2379,http://127.0.0.1:2379 \ -advertise-client-urls http://niub-etcd-3:2379 \ -initial-cluster-token etcd-cluster-1 \ -initial-cluster niub1=http://niub-etcd-1:2380,niub2=http://niub-etcd-2:2380,niub3=http://niub-etcd-3:2380 \ -initial-cluster-state new >> /niub/etcd_log/etcd.log 2>&1 &
防火牆
在這3臺node服務器開放237九、2380端口,命令:docker
iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 2379 -j ACCEPT iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 2380 -j ACCEPT
haproxy配置
haproxy配置過程略 編輯
/etc/haproxy/haproxy.cfg
文件,增長:shellfrontend etcd bind 10.10.0.14:2379 mode tcp option tcplog default_backend etcd log 127.0.0.1 local3 backend etcd balance roundrobin fullconn 1024 server etcd1 10.10.0.11:2379 check port 2379 inter 300 fall 3 server etcd2 10.10.0.12:2379 check port 2379 inter 300 fall 3 server etcd3 10.10.0.13:2379 check port 2379 inter 300 fall 3
檢查etcd服務運行狀態
使用curl訪問:json
curl http://10.10.0.14:2379/v2/members
返回如下結果爲正常(3個節點):api
{
"members": [ { "id": "1f890e0c67371d24", "name": "niub1", "peerURLs": [ "http://niub-etcd-1:2380" ], "clientURLs": [ "http://niub-etcd-1:2379" ] }, { "id": "b952ccccefdd8a93", "name": "niub3", "peerURLs": [ "http://niub-etcd-3:2380" ], "clientURLs": [ "http://niub-etcd-3:2379" ] }, { "id": "d6dbdb24d5bfc20f", "name": "niub2", "peerURLs": [ "http://niub-etcd-2:2380" ], "clientURLs": [ "http://niub-etcd-2:2379" ] } ] }
etcd備份
使用etcd自帶命令etcdctl
進行etc備份,腳本以下:
#!/bin/bash date_time=`date +%Y%m%d` etcdctl backup --data-dir /usr/local/etcd/niub3.etcd/ --backup-dir /niub/etcd_backup/${date_time} find /niub/etcd_backup/ -ctime +7 -exec rm -r {} \;
etcdctl操做
更新一個節點
若是你想更新一個節點的 IP(peerURLS),首先你須要知道那個節點的 ID。你能夠列出全部節點,找出對應節點的 ID。
$ etcdctl member list 6e3bd23ae5f1eae0: name=node2 peerURLs=http://localhost:23802 clientURLs=http://127.0.0.1:23792 924e2e83e93f2560: name=node3 peerURLs=http://localhost:23803 clientURLs=http://127.0.0.1:23793 a8266ecf031671f3: name=node1 peerURLs=http://localhost:23801 clientURLs=http://127.0.0.1:23791
在本例中,咱們假設要更新 ID 爲 a8266ecf031671f3
的節點的 peerURLs 爲:http://10.0.1.10:2380
$ etcdctl member update a8266ecf031671f3 http://10.0.1.10:2380 Updated member with ID a8266ecf031671f3 in cluster
刪除一個節點
假設咱們要刪除 ID 爲 a8266ecf031671f3
的節點
$ etcdctl member remove a8266ecf031671f3
Removed member a8266ecf031671f3 from cluster
執行完後,目標節點會自動中止服務,而且打印一行日誌:
etcd: this member has been permanently removed from the cluster. Exiting.
若是刪除的是 leader
節點,則須要耗費額外的時間從新選舉 leader
。
增長一個新的節點
增長一個新的節點分爲兩步:
-
經過
etcdctl
或對應的 API 註冊新節點 -
使用恰當的參數啓動新節點
先看第一步,假設咱們要新加的節點取名爲 infra3, peerURLs
是 http://10.0.1.13:2380
$ etcdctl member add infra3 http://10.0.1.13:2380 added member 9bf1b35fc7761a23 to cluster ETCD_NAME="infra3" ETCD_INITIAL_CLUSTER="infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380,infra3=http://10.0.1.13:2380" ETCD_INITIAL_CLUSTER_STATE=existing
etcdctl
在註冊完新節點後,會返回一段提示,包含3個環境變量。而後在第二部啓動新節點的時候,帶上這3個環境變量便可。
$ export ETCD_NAME="infra3" $ export ETCD_INITIAL_CLUSTER="infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380,infra3=http://10.0.1.13:2380" $ export ETCD_INITIAL_CLUSTER_STATE=existing $ etcd -listen-client-urls http://10.0.1.13:2379 -advertise-client-urls http://10.0.1.13:2379 -listen-peer-urls http://10.0.1.13:2380 -initial-advertise-peer-urls http://10.0.1.13:2380 -data-dir %data_dir%
這樣,新節點就會運行起來而且加入到已有的集羣中了。
值得注意的是,若是原先的集羣只有1個節點,在新節點成功啓動以前,新集羣並不能正確的造成。由於原先的單節點集羣沒法完成leader
的選舉。
直到新節點啓動完,和原先的節點創建鏈接之後,新集羣才能正確造成。
服務故障恢復
在使用etcd集羣的過程當中,有時會出現少許主機故障,這時咱們須要對集羣進行維護。然而,在現實狀況下,還可能遇到因爲嚴重的設備 或網絡的故障,致使超過半數的節點沒法正常工做。
在etcd集羣沒法提供正常的服務,咱們須要用到一些備份和數據恢復的手段。etcd背後的raft,保證了集羣的數據的一致性與穩定性。因此咱們對etcd的恢復,更多的是恢復etcd的節點服務,並還原用戶數據。
首先,從剩餘的正常節點中選擇一個正常的成員節點, 使用 etcdctl backup
命令備份etcd數據。
$ ./etcdctl backup --data-dir /var/lib/etcd -backup-dir /tmp/etcd_backup $ tar -zcxf backup.etcd.tar.gz /tmp/etcd_backup
這個命令會將節點中的用戶數據所有寫入到指定的備份目錄中,可是節點ID,集羣ID等信息將會丟失, 並在恢復到目的節點時被從新。這樣主要是防止原先的節點意外從新加入新的節點集羣而致使數據混亂。
而後將Etcd數據恢復到新的集羣的任意一個節點上, 使用 --force-new-cluster
參數啓動Etcd服務。這個參數會重置集羣ID和集羣的全部成員信息,其中節點的監聽地址會被重置爲localhost:2379, 表示集羣中只有一個節點。
$ tar -zxvf backup.etcd.tar.gz -C /var/lib/etcd $ etcd --data-dir=/var/lib/etcd --force-new-cluster ...
啓動完成單節點的etcd,能夠先對數據的完整性進行驗證, 確認無誤後再經過Etcd API修改節點的監聽地址,讓它監聽節點的外部IP地址,爲增長其餘節點作準備。例如:
用etcd命令找到當前節點的ID。
$ etcdctl member list 98f0c6bf64240842: name=cd-2 peerURLs=http://127.0.0.1:2580 clientURLs=http://127.0.0.1:2579
因爲etcdctl不具有修改爲員節點參數的功能, 下面的操做要使用API來完成。
$ curl http://127.0.0.1:2579/v2/members/98f0c6bf64240842 -XPUT \ -H "Content-Type:application/json" -d '{"peerURLs":["http://127.0.0.1:2580"]}'
注意,在Etcd文檔中, 建議首先將集羣恢復到一個臨時的目錄中,從臨時目錄啓動etcd,驗證新的數據正確完整後,中止etcd,在將數據恢復到正常的目錄中。
最後,在完成第一個成員節點的啓動後,能夠經過集羣擴展的方法使用 etcdctl member add
命令添加其餘成員節點進來。
擴展etcd集羣
在集羣中的任何一臺etcd節點上執行命令,將新節點註冊到集羣:
1
|
curl http:
//127
.0.0.1:2379
/v2/members
-XPOST -H
"Content-Type: application/json"
-d
'{"peerURLs": ["http://192.168.73.172:2380"]}'
|
在新節點上啓動etcd容器,注意-initial-cluster-state參數爲existing
1
2
3
4
5
6
7
8
9
10
11
|
/usr/local/etcd/etcd \ -name etcd03 \
-advertise-client-urls http:
//192
.168.73.150:2379,http:
//192
.168.73.150:4001 \
-listen-client-urls http:
//0
.0.0.0:2379 \
-initial-advertise-peer-urls http:
//192
.168.73.150:2380 \
-listen-peer-urls http:
//0
.0.0.0:2380 \
-initial-cluster-token etcd-cluster \
-initial-cluster
"etcd01=http://192.168.73.140:2380,etcd02=http://192.168.73.137:2380,etcd03=http://192.168.73.150:2380"
\
-initial-cluster-state existing
|
任意節點執行健康檢查:
1
2
3
4
|
[root@docker01 ~]
# etcdctl cluster-health
member 2bd5fcc327f74dd5 is healthy: got healthy result from http:
//192
.168.73.140:2379
member c8a9cac165026b12 is healthy: got healthy result from http:
//192
.168.73.137:2379
cluster is healthy
|
Etcd數據遷移
數據遷移
在 gzns-inf-platform53.gzns.baidu.com 機器上運行着一個 etcd 服務器,其 data-dir 爲 /var/lib/etcd/。咱們要以 /var/lib/etcd 中的數據爲基礎,搭建一個包含三個節點的高可用的 etcd 集羣,三個節點的主機名分別爲:
gzns-inf-platform53.gzns.baidu.com
gzns-inf-platform56.gzns.baidu.com
gzns-inf-platform60.gzns.baidu.com
初始化一個新的集羣
咱們先分別在上述三個節點上建立 /home/work/etcd/data-dir/ 文件夾看成 etcd 集羣每一個節點的數據存放目錄。而後以 gzns-inf-platform60.gzns.baidu.com 節點爲起點建立一個單節點的 etcd 集羣,啓動腳本 force-start-etcd.sh 以下:
#!/bin/bash
# Don't start it unless etcd cluster has a heavily crash !
../bin/etcd --name etcd2 --data-dir /home/work/etcd/data-dir --advertise-client-urls http://gzns-inf-platform60.gzns.baidu.com:2379,http://gzns-inf-platform60.gzns.baidu.com:4001 --listen-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001 --initial-advertise-peer-urls http://gzns-inf-platform60.gzns.baidu.com:2380 --listen-peer-urls http://0.0.0.0:2380 --initial-cluster-token etcd-cluster-1 --initial-cluster etcd2=http://gzns-inf-platform60.gzns.baidu.com:2380 --force-new-cluster > ./log/etcd.log 2>&1
這一步的 --force-new-cluster 很重要,多是爲了抹除舊 etcd 的一些屬性信息,從而能成功的建立一個單節點 etcd 的集羣。
這時候經過
etcdctl member list
查看 peerURLs 指向的是否是 http://gzns-inf-platform60.gzns.baidu.com:2380
? 若是不是,須要更新這個 etcd 的 peerURLs 的指向,不然這樣在加入新的節點時會失敗的。
咱們手動更新這個 etcd 的 peerURLs 指向
etcdctl member update ce2a822cea30bfca http://gzns-inf-platform60.gzns.baidu.com:2380
添加etcd1成員
而後添加 gzns-inf-platform56.gzns.baidu.com 節點上的 etcd1 成員
etcdctl member add etcd1 http://gzns-inf-platform56.gzns.baidu.com:2380
注意要先添加 etcd1 成員後,再在 gzns-inf-platform56.gzns 機器上啓動這個 etcd1 成員
這時候咱們登錄上 gzns-inf-platform56.gzns.baidu.com 機器上啓動這個 etcd1 實例,啓動腳本 force-start-etcd.sh 以下:
#!/bin/bash
# Don't start it unless etcd cluster has a heavily crash !
../bin/etcd --name etcd1 --data-dir /home/work/etcd/data-dir --advertise-client-urls http://gzns-inf-platform56.gzns.baidu.com:2379,http://gzns-inf-platform56.gzns.baidu.com:4001 --listen-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001 --initial-advertise-peer-urls http://gzns-inf-platform56.gzns.baidu.com:2380 --listen-peer-urls http://0.0.0.0:2380 --initial-cluster-token etcd-cluster-1 --initial-cluster etcd2=http://gzns-inf-platform60.gzns.baidu.com:2380,etcd1=http://gzns-inf-platform56.gzns.baidu.com:2380 --initial-cluster-state existing > ./log/etcd.log 2>&1
注意在這個節點上咱們先把 data-dir 文件夾中的數據刪除(若是有內容的狀況下),而後設置 --initial-cluster和 --initial-cluster-state。
添加 etcd0 成員
這時候咱們能夠經過
etcdctl member list
觀察到咱們新加入的節點了,而後咱們再以相似的步驟添加第三個節點 gzns-inf-platform53.gzns.baidu.com上 的 etcd0 實例
etcdctl member add etcd0 http://gzns-inf-platform53.gzns.baidu.com:2380
而後登錄到 gzns-inf-platform53.gzns.baidu.com 機器上啓動 etcd0 這個實例,啓動腳本 force-start-etcd.sh 以下:
#!/bin/bash
# Don't start it unless etcd cluster has a heavily crash !
../bin/etcd --name etcd0 --data-dir /home/work/etcd/data-dir --advertise-client-urls http://gzns-inf-platform53.gzns.baidu.com:2379,http://gzns-inf-platform53.gzns.baidu.com:4001 --listen-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001 --initial-advertise-peer-urls http://gzns-inf-platform53.gzns.baidu.com:2380 --listen-peer-urls http://0.0.0.0:2380 --initial-cluster-token etcd-cluster-1 --initial-cluster etcd2=http://gzns-inf-platform60.gzns.baidu.com:2380,etcd1=http://gzns-inf-platform56.gzns.baidu.com:2380,etcd0=http://gzns-inf-platform53.gzns.baidu.com:2380 --initial-cluster-state existing > ./log/etcd.log 2>&1
過程同加入 etcd1 的過程類似,這樣咱們就能夠把單節點的 etcd 數據遷移到一個包含三個 etcd 實例組成的集羣上了。
大致思路
先經過 --force-new-cluster 強行拉起一個 etcd 集羣,抹除了原有 data-dir 中原有集羣的屬性信息(內部猜想),而後經過加入新成員的方式擴展這個集羣到指定的數目。
高可用etcd集羣方式(可選擇)
上面數據遷移的過程通常是在緊急的狀態下才會進行的操做,這時候可能 etcd 已經停掉了,或者節點不可用了。在通常狀況下如何搭建一個高可用的 etcd 集羣呢,目前採用的方法是用 supervise 來監控每一個節點的 etcd 進程。
在數據遷移的過程當中,咱們已經搭建好了一個包含三個節點的 etcd 集羣了,這時候咱們對其作一些改變,使用supervise 從新拉起這些進程。
首先登錄到 gzns-inf-platform60.gzns.baidu.com 節點上,kill 掉 etcd 進程,編寫 etcd 的啓動腳本 start-etcd.sh,其中 start-etcd.sh 的內容以下:
#!/bin/bash
../bin/etcd --name etcd2 --data-dir /home/work/etcd/data-dir --advertise-client-urls http://gzns-inf-platform60.gzns.baidu.com:2379,http://gzns-inf-platform60.gzns.baidu.com:4001 --listen-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001 --initial-advertise-peer-urls http://gzns-inf-platform60.gzns.baidu.com:2380 --listen-peer-urls http://0.0.0.0:2380 --initial-cluster-token etcd-cluster-1 --initial-cluster etcd2=http://gzns-inf-platform60.gzns.baidu.com:2380,etcd1=http://gzns-inf-platform56.gzns.baidu.com:2380,etcd0=http://gzns-inf-platform53.gzns.baidu.com:2380 --initial-cluster-state existing > ./log/etcd.log 2>&1
而後使用 supervise 執行 start-etcd.sh 這個腳本,使用 supervise 啓動 start-etcd.sh 的啓動腳本 etcd_control 以下:
#!/bin/sh
if [ $# -ne 1 ]; then
echo "$0: start|stop"
fi
work_path=`dirname $0`
cd ${work_path}
work_path=`pwd`
supervise=${work_path}/supervise/bin/supervise64.etcd
mkdir -p ${work_path}/supervise/status/etcd
case "$1" in
start)
killall etcd supervise64.etcd
${supervise} -f "sh ./start-etcd.sh" \
-F ${work_path}/supervise/conf/supervise.conf \
-p ${work_path}/supervise/status/etcd
echo "START etcd daemon ok!"
;;
stop)
killall etcd supervise64.etcd
if [ $? -ne 0 ]
then
echo "STOP etcd daemon failed!"
exit 1
fi
echo "STOP etcd daemon ok!"
這裏爲何不直接用 supervise 執行 etcd 這個命令呢,反而以一個 start-etcd.sh 腳本的形式啓動這個 etcd 呢?緣由在於咱們須要將 etcd 的輸出信息重定向到文件中,
若是直接在 supervise 的 command 進行重定向,將發生錯誤。
分別登錄到如下兩臺機器
- gzns-inf-platform56.gzns.baidu.com
- gzns-inf-platform53.gzns.baidu.com
上進行一樣的操做,注意要針對每一個節點的不一樣修改對應的etcd name 和 peerURLs 等。
常見問題
一、etcd 讀取已有的 data-dir 數據而啓動失敗,經常表現爲cluster id not match什麼的
可能緣由是新啓動的 etcd 屬性與以前的不一樣,能夠嘗 --force-new-cluster 選項的形式啓動一個新的集羣
二、etcd 集羣搭建完成後,經過 kubectl get pods 等一些操做發生錯誤的狀況
目前解決辦法是重啓一下 apiserver 進程
三、仍是 etcd啓動失敗的錯誤,大多數狀況下都是與data-dir 有關係,data-dir 中記錄的信息與 etcd啓動的選項所標識的信息不太匹配形成的
若是能經過修改啓動參數解決這類錯誤就最好不過的了,很是狀況下的解決辦法:
- 一種解決辦法是刪除data-dir文件
- 一種方法是複製其餘節點的data-dir中的內容,以此爲基礎上以 --force-new-cluster 的形式強行拉起一個,而後以添加新成員的方式恢復這個集羣,這是目前的幾種解決辦法