etcd 集羣運維實踐

etcd 是 Kubernetes 集羣的數據核心,最嚴重的狀況是,當 etcd 出問題完全沒法恢復的時候,解決問題的辦法可能只有從新搭建一個環境。所以圍繞 etcd 相關的運維知識就比較重要,etcd 能夠容器化部署,也能夠在宿主機自行搭建,如下內容是通用的。
集羣的備份和恢復html

添加備份linux

#!/bin/bash
IP=123.123.123.123
BACKUP_DIR=/alauda/etcd_bak/
mkdir -p $BACKUP_DIR
export ETCDCTL_API=3
etcdctl --endpoints=http://$IP:2379 snapshot save $BACKUP/snap-$(date +%Y%m%d%H%M).db
# 備份一個節點的數據就能夠恢復,實踐中,爲了防止定時任務配置的節點異常沒有生成備份,建議多加幾個

恢復集羣git

#!/bin/bash

# 使用 etcdctl snapshot restore 生成各個節點的數據

# 比較關鍵的變量是
# --data-dir 須要是實際 etcd 運行時的數據目錄
# --name  --initial-advertise-peer-urls  須要用各個節點的配置
# --initial-cluster  initial-cluster-token 須要和原集羣一致

ETCD_1=10.1.0.5
ETCD_2=10.1.0.6
ETCD_3=10.1.0.7

for i in ETCD_1 ETCD_2 ETCD_3
do

export ETCDCTL_API=3
etcdctl snapshot restore snapshot.db \
--data-dir=/var/lib/etcd \
--name $i \
--initial-cluster ${ETCD_1}=http://${ETCD_1}:2380,${ETCD_2}=http://${ETCD_2}:2380,${ETCD_3}=http://${ETCD_3}:2380 \
--initial-cluster-token k8s_etcd_token \
--initial-advertise-peer-urls http://$i:2380 && \
mv /var/lib/etcd/ etcd_$i

done

# 把 etcd_10.1.0.5 複製到 10.1.0.5節點,覆蓋/var/lib/etcd(同--data-dir路徑)
# 其餘節點依次類推

用 etcd 自動建立的 SnapDb 恢復github

#!/bin/bash 
export ETCDCTL_API=3
etcdctl snapshot restore snapshot.db \
--skip-hash-check \
--data-dir=/var/lib/etcd \
--name 10.1.0.5 \
--initial-cluster 10.1.0.5=http://10.1.0.5:2380,10.1.0.6=http://10.1.0.6:2380,10.1.0.7=http://10.1.0.7:2380 \
--initial-cluster-token k8s_etcd_token \
--initial-advertise-peer-urls http://10.1.0.5:2380

# 也是全部節點都須要生成本身的數據目錄,參考上一條
# 和上一條命令惟一的差異是多了  --skip-hash-check  (跳過完整性校驗)
# 這種方式不能確保 100% 可恢復,建議仍是本身加備份
# 一般恢復後須要作一下數據壓縮和碎片整理,可參考相應章節

踩過的坑
[ 3.0.14 版 etcd restore 功能不可用 ] https://github.com/etcd-io/et...shell

使用更新的 etcd 便可。json

總結:恢復就是要拿 DB 去把 etcd 的數據生成一份,用同一個節點的,能夠保證除了 restore 時候指定的參數外,全部數據都同樣。這就是用一份 DB,操做三次(或者5次)的緣由。
集羣的擴容——從 1 到 3
執行添加vim

#!/bin/bash
export ETCDCTL_API=2
etcdctl --endpoints=http://10.1.0.6:2379 member add 10.1.0.6 http://10.1.0.6:2380
etcdctl --endpoints=http://10.1.0.7:2379 member add 10.1.0.7 http://10.1.0.7:2380

# ETCD_NAME="etcd_10.1.0.6" 
# ETCD_INITIAL_CLUSTER="10.1.0.6=http://10.1.0.6:2380,10.1.0.5=http://10.1.0.5:2380"
# ETCD_INITIAL_CLUSTER_STATE="existing"

準備添加的節點 etcd 參數配置api

#!/bin/bash
/usr/local/bin/etcd 
--data-dir=/data.etcd 
--name 10.1.0.6
--initial-advertise-peer-urls http://10.1.0.6:2380 
--listen-peer-urls http://10.1.0.6:2380 
--advertise-client-urls http://10.1.0.6:2379 
--listen-client-urls http://10.1.0.6:2379 
--initial-cluster 10.1.0.6=http://10.1.0.6:2380,10.1.0.5=http://10.1.0.5:2380
--initial-cluster-state exsiting
--initial-cluster-token k8s_etcd_token

# --initial-cluster 集羣全部節點的 name=ip:peer_url
# --initial-cluster-state exsiting 告訴 etcd 本身歸屬一個已存在的集羣,不要自立門戶

踩過的坑
從 1 到 3 期間,會通過集羣是兩節點的狀態,這時候可能集羣的表現就像掛了,endpoint status 這些命令都不能用,因此咱們須要用 member add 先把集羣擴到三節點,而後再依次啓動 etcd 實例,這樣作就能確保 etcd 就是健康的。bash

從 3 到更多,其實仍是 member add 啦,就放心搞吧。
集羣加證書
生成證書微信

curl -s -L -o /usr/bin/cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
curl -s -L -o /usr/bin/cfssljson https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
chmod +x /usr/bin/{cfssl,cfssljson}
cd /etc/kubernetes/pki/etcd

#  cat ca-config.json
{
"signing": {
"default": {
  "expiry": "100000h"
},
"profiles": {
  "server": {
    "usages": ["signing", "key encipherment", "server auth", "client auth"],
    "expiry": "100000h"
  },
  "client": {
    "usages": ["signing", "key encipherment", "server auth", "client auth"],
    "expiry": "100000h"
  }
}
}
} 

#  cat ca-csr.json
{
"CN": "etcd",
"key": {
"algo": "rsa",
"size": 4096
},
"names": [
{
  "C": "CN",
  "L": "Beijing",
  "O": "Alauda",
  "OU": "PaaS",
  "ST": "Beijing"
}
]
} 

#  cat server-csr.json
{
"CN": "etcd-server",
"hosts": [
"localhost",
"0.0.0.0",
"127.0.0.1",
"全部master 節點ip ",
"全部master 節點ip ",
"全部master 節點ip "
],
"key": {
"algo": "rsa",
"size": 4096
},
"names": [
{
  "C": "CN",
  "L": "Beijing",
  "O": "Alauda",
  "OU": "PaaS",
  "ST": "Beijing"
}
]
} 

# cat client-csr.json

{
"CN": "etcd-client",
"hosts": [
""
],
"key": {
"algo": "rsa",
"size": 4096
},
"names": [
{
  "C": "CN",
  "L": "Beijing",
  "O": "Alauda",
  "OU": "PaaS",
  "ST": "Beijing"
}
]
} 

cd /etc/kubernetes/pki/etcd

cfssl gencert -initca ca-csr.json | cfssljson -bare ca

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server server-csr.json | cfssljson -bare server

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client client-csr.json | cfssljson -bare client

參考連接:https://lihaoquan.me/2017/3/29 ... .html

首先更新節點的peer-urls

export ETCDCTL_API=3
etcdctl --endpoints=http://x.x.x.x:2379 member list
#  1111111111  ..........
#  2222222222  ..........
#  3333333333  ..........
etcdctl --endpoints=http://172.30.0.123:2379 member update 1111111111 --peer-urls=https://x.x.x.x:2380
# 執行三次把三個節點的peer-urls都改爲https

修改配置

#  vim /etc/kubernetes/main*/etcd.yaml

#  etcd啓動命令部分修改 http 爲 https,啓動狀態改爲 existing
- --advertise-client-urls=https://x.x.x.x:2379
- --initial-advertise-peer-urls=https://x.x.x.x:2380
- --initial-cluster=xxx=https://x.x.x.x:2380,xxx=https://x.x.x.x:2380,xxx=https://x.x.x.x:2380
- --listen-client-urls=https://x.x.x.x:2379
- --listen-peer-urls=https://x.x.x.x:2380
- --initial-cluster-state=existing

#  etcd 啓動命令部分插入
- --cert-file=/etc/kubernetes/pki/etcd/server.pem
- --key-file=/etc/kubernetes/pki/etcd/server-key.pem
- --peer-cert-file=/etc/kubernetes/pki/etcd/server.pem
- --peer-key-file=/etc/kubernetes/pki/etcd/server-key.pem
- --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem
- --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem
- --peer-client-cert-auth=true
- --client-cert-auth=true

#  檢索hostPath在其後插入
- hostPath:
  path: /etc/kubernetes/pki/etcd
  type: DirectoryOrCreate
name: etcd-certs

#  檢索mountPath在其後插入
- mountPath: /etc/kubernetes/pki/etcd
  name: etcd-certs

#  vim /etc/kubernetes/main*/kube-apiserver.yaml
#  apiserver 啓動部分插入,修改 http 爲https
- --etcd-cafile=/etc/kubernetes/pki/etcd/ca.pem
- --etcd-certfile=/etc/kubernetes/pki/etcd/client.pem
- --etcd-keyfile=/etc/kubernetes/pki/etcd/client-key.pem
- --etcd-servers=https://x.x.x.x:2379,https://x.x.x.x:2379,https://x.x.x.x:2379

總結下就是,先準備一套證書。而後修改 etcd 內部通訊地址爲https,這時候etcd日誌會報錯(能夠忽略),而後用etcd --帶證書的參數啓動,把全部連接etcd的地方都用上證書,便可。
遇到的坑
[ etcd 加證書後,apiserver 的健康檢查仍是 http 請求,etcd 會一直刷日誌 ] https://github.com/etcd-io/et...
2018-02-06 12:41:06.905234 I | embed: rejected connection from "127.0.0.1:35574" (error "EOF", ServerName "")

解決辦法:直接去掉 apiserver 的健康檢查,或者把默認的檢查命令換成 curl(apiserver 的鏡像裏應該沒有 curl,若是是剛需的話本身從新 build 一下吧)
集羣升級
已是 v3 的的集羣不須要太多的配置,保留數據目錄,替換鏡像(或者二進制)便可;

v2 到 v3 的升級須要一個 merge 的操做,我並無實際的實踐過,也不太推薦這樣作。
集羣狀態檢查
其實上述全部步驟都須要這些命令的輔助——

#!/bin/bash
# 若是證書的話,去掉--cert --key --cacert 便可
# --endpoints= 須要寫了幾個節點的url,endpoint status就輸出幾條信息

export ETCDCTL_API=3

etcdctl \
--endpoints=https://x.x.x.x:2379 \ 
--cert=/etc/kubernetes/pki/etcd/client.pem \
--key=/etc/kubernetes/pki/etcd/client-key.pem \
--cacert=/etc/kubernetes/pki/etcd/ca.pem \
endpoint status -w table

etcdctl --endpoints=xxxx endpoint health

etcdctl --endpoints=xxxx member list

kubectl get cs

數據操做(刪除、壓縮、碎片整理)
刪除

ETCDCTL_API=2 etcdctl rm --recursive            # v2 的 api 能夠這樣刪除一個「目錄」
ETCDCTL_API=3 etcdctl --endpoints=xxx del /xxxxx --prefix # v3 的版本

# 帶證書的話,參考上一條添加 --cert --key --cacert 便可

遇到的坑:在一個客戶環境裏發現 Kubernetes 集羣裏的 「事件」 超級多,就是 kubectl describe xxx 看到的 events 部分信息,數據太大致使 etcd 跑的很累,咱們就用這樣的方式刪掉沒用的這些數據。
碎片整理
ETCDCTL_API=3 etcdctl --endpoints=xx:xx,xx:xx,xx:xx defrag
ETCDCTL_API=3 etcdctl --endpoints=xx:xx,xx:xx,xx:xx endpoint status # 看數據量

壓縮

ETCDCTL_API=3 etcdctl --endpoints=xx:xx,xx:xx,xx:xx compact

# 這個在只有 K8s 用的 etcd 集羣裏做用不太大,可能具體場景我沒遇到
# 可參考這個文檔
# https://www.cnblogs.com/davygeek/p/8524477.html
# 不過跑一下不礙事

etcd --auto-compaction-retention=1

# 添加這個參數讓 etcd 運行時本身去作壓縮

常見問題
etcd 對時間很依賴,因此集羣裏的節點時間必定要同步
磁盤空間不足,若是磁盤是被 etcd 本身吃完了,就須要考慮壓縮和刪數據啦
加證書後全部請求就都要帶證書了,要不會提示 context deadline exceeded
作各個操做時 etcd 啓動參數裏標明節點狀態的要當心,不然須要從新作一遍前面的步驟很麻煩

日誌收集
etcd 的日誌暫時只支持 syslog 和 stdout 兩種——https://github.com/etcd-io/et...

etcd 的日誌在排查故障時頗有用,若是咱們用宿主機來部署 etcd,日誌能夠經過 systemd 檢索到,但 kubeadm 方式啓動的 etcd 在容器重啓後就會丟失全部歷史。咱們能夠用如下的方案來作——
shell 的重定向

etcd --xxxx --xxxx   >  /var/log/etcd.log 
# 配合 logratate 來作日誌切割
# 將日誌經過 volume 掛載到宿主機

supervisor
supervisor 從容器剛開始流行時,就是保持服務持續運行頗有效的工具。
sidecar 容器(後續我在 GitHub 上補充一個例子,github.com/jing2uo)
Sidecar 能夠簡單理解爲一個 Pod 裏有多個容器(好比 kubedns)他們彼此能夠看到對方的進程,所以咱們能夠用傳統的 strace 來捕捉 etcd 進程的輸出,而後在 Sidecar 這個容器裏和 shell 重定向同樣操做。
strace -e trace=write -s 200 -f -p 1

Kubeadm 1.13 部署的集羣
最近咱們測試 Kubernetes 1.13 集羣時發現了一些有趣的改變,詐一看咱們上面的命令就無法用了——

https://kubernetes.io/docs/set ... logy/

區分了 Stacked etcd topology 和 External etcd topology,官方的連接了這個圖很形象——
B70D000C-83B2-4B9C-A612-53925238D0DA.png

這種模式下的 etcd 集羣,最明顯的差異是容器內 etcd 的initial-cluster 啓動參數只有本身的 IP,會有點懵掛了我這該怎麼去恢復。其實基本原理沒有變,Kubeadm 藏了個 ConfigMap,啓動參數被放在了這裏——

kubectl get cm  etcdcfg -n kube-system -o yaml

etcd:
  local:
    serverCertSANs:
    - "192.168.8.21"
    peerCertSANs:
    - "192.168.8.21"
    extraArgs:
      initial-cluster: 192.168.8.21=https://192.168.8.21:2380,192.168.8.22=https://192.168.8.22:2380,192.168.8.20=https://192.168.8.20:2380
      initial-cluster-state: new
      name: 192.168.8.21
      listen-peer-urls: https://192.168.8.21:2380
      listen-client-urls: https://192.168.8.21:2379
      advertise-client-urls: https://192.168.8.21:2379
      initial-advertise-peer-urls: https://192.168.8.21:2380

Q&A
Q:請問 etcd 監控和告警如何作的?告警項都有哪些?
A:告警要看用的什麼監控吧,和 Kubernetes 配套比較常見的是普羅米修思和 Grafana 了。告警項我沒有具體配過,能夠關注的點是:endpoint status -w table 裏能夠看到數據量,endpoints health 看到健康狀態,還有內存使用這些,具體能夠參考普羅米修思的 exporter 是怎麼作的。
Q:使用 Kubeadm 部署高可用集羣是否是至關於先部署三個獨立的單點 Master,最後靠 etcd 添加節點操做把數據打通?
A:不是,Kubeadm 部署會在最開始就先建一個 etcd 集羣,apiserver 啓動以前就須要準備好 etcd,不然 apiserver 起不了,集羣之間就無法通訊。能夠嘗試手動搭一下集羣,不用 Kubeadm,一個個把組件開起來,以後對Kubernetes的組件關係會理解更好的。
Q:etcd 跨機房高可用如何保證呢?管理 etcd 有好的 UI 工具推薦麼?
A:etcd 對時間和網絡要求很高,因此跨機房的網絡很差的話性能不好,光在那邊選請輸入連接描述舉去了。我分享忘了提一個 etcd 的 mirror,能夠去參考下作法。跨機房的話,我以爲高速網絡是個前提吧,不過還沒作過。UI 工具沒找過,都是命令行操做來着。
Q:Kubeadm 啓動的集羣內 etcd節 點,kubectl 操做 etcd 的備份恢復有嘗試過嗎?
A:沒有用 kubectl 去處理過 etcd 的備份恢復。etcd 的恢復依賴用 SnapDb 生成數據目錄,把 etcd 進程丟進容器裏,相似的操做避免不了,還有啓動的狀態須要修改。kubeadm 啓動的 etcd 能夠經過 kubectl 查詢和 exec,可是數據操做應該不能夠,好比恢復 etcd ing 時,沒法鏈接 etcd,kubectl 還怎麼工做?
Q:kubeadm-ha 啓動 3 個 Master,有 3 個 etcd 節點,怎麼跟集羣外的 3 個 etcd 作集羣,作成 3 Master 6 etcd?
A:能夠參考文檔裏的擴容部分,只要保證 etcd 的參數正確,即便一個集羣一部分容器化,一部分宿主機,都是能夠的(固然不建議這麼作)。能夠先用 kubeadm 搭一個集羣,而後用擴容的方式把其餘三個節點加進來,或者在 kubeadm 操做以前,先搭一個 etcd 集羣。而後 kubeadm 調用它就能夠。
Q:有沒有試過 Kubeadm 的滾動升級,etcd 版本變動,各 Master 機分別重啓,數據同步是否有異常等等?
A:作過。Kubeadm 的滾動升級公司內部有從 1.7 一步步升級到 1.十一、1.12 的文檔,或多或少有一點小坑,不過今天主題是 etcd 因此沒提這部分。各個 Master 分別重啓後數據的一致咱們測試時沒問題,還有比較極端的是直接把三 Master 停機一天,再啓動後也能恢復。
以上內容根據2019年1月3日晚微信羣分享內容整理。分享人郭靖,靈雀雲運維開發工程師,有大規模集羣運維經驗,對自動化迷之熱衷,精通Ansible,HashiCorp工具集,容器和Kubernetes鼓搗了三年,喜歡用Python和Go寫小工具,DevOps推崇及踐行者,近期關注和期待OpsMop。DockOne每週都會組織定向的技術分享,歡迎感興趣的同窗加微信:liyingjiesd,進羣參與,您有想聽的話題或者想分享的話題均可以給咱們留言。

相關文章
相關標籤/搜索