Kubernetes的etcd多節點擴容實戰技巧

在《Kubernetes探祕-多master節點容錯部署》中介紹了經過部署多個主節點來提升Kubernetes的容錯能力。其中,最爲關鍵是存儲集羣控制數據的etcd服務必須在多個副節點間實時同步,而kube-apiserver經過keepalived進行IP主地址的切換。 在《Kubernetes探祕-etcd節點和實例擴容》中已經詳細介紹了etcd多節點擴容的步驟,但在實際操做中發現,必須要遵循必定的操做順序、注意細節,不然會致使擴容失敗,並且很容易形成整個etcd集羣沒法訪問。這裏將etcd集羣擴容的實際操做經驗整理出來分享。git

  • 注意:
    • 由於擴容過程當中,須要將原來的etcd庫刪除,會致使kubernetes集羣的master節點信息丟失
      • 所以在擴容以前,建議使用etcdctl snapshot命令進行備份。或者,另建etcd節點,將原來的數據傳送過去。
    • 若是出現「ID mismatch」等錯誤,整個etcd集羣將沒法鏈接,後續的member remove等操做都沒法進行,只能所有廢棄。
    • 能夠將/var/lib/etcd目錄和etcd容器實例所有刪除。重啓動kubelet服務後能夠恢復,可是裏面存儲的數據將會所有丟失。
  • 提示:

一、生成證書文件

所有使用https進行etcd集羣的鏈接,須要生成和配置證書,能夠參考《Kubernetes探祕-etcd節點和實例擴容》裏的方法,這些證書文件須要複製到每個節點的/etc/kubernetes/pki目錄下。須要所有使用固定IP地址,在Ubuntu 18.06中使用 Netplan進行配置(參考《Ubuntu 18.04設置靜態IP》),使用 sudo netplan apply讓其當即生效(須要稍等會兒配置完畢)。github

上傳目錄,示例:docker

sudo scp -r root@10.1.1.201:/etc/kubernetes/pki /etc/kubernetes

二、安裝Kubernetes主節點

2.1 安裝主節點

咱們首先安裝一個Kubernetes主節點,其它節點配置參數將從其衍生出來。參考:數據庫

準備工做完成後,使用下面的命令安裝Kubernetes的單實例Master節點。api

sudo kubeadm init --kubernetes-version=v1.13.1 --apiserver-advertise-address=10.1.1.199

由於個人機器上有多塊網卡,使用 --apiserver-advertise-address=10.1.1.199 指定apiserver的服務地址,這個地址也是keepalived的虛擬IP地址(須要提早安裝,參考《Keepalived快速使用》),將會在遇故障時在多個節點間自動漂移該主地址,使其它節點能夠訪問到。app

輸入 kubectl get pod --all-namespaces檢查該單實例集羣是否運行正常。工具

2.2 備份etcd數據庫

主節點已經安裝了一個etcd的實例,而且存放了集羣運行的最基礎參數。爲了防止etcd集羣擴容過程數據丟失,咱們將其備份。具體操做參見《Kubernetes的etcd數據查看和遷移》。須要注意的是,etcd api2和api3的備份和恢復方法不一樣,由於從Kubernetes 1.13.0開始已經使用API3,下面介紹的都是API3的方法。url

  • 建立snapshot
ETCDCTL_API=3 etcdctl --endpoints=https://[10.1.1.202]:2379 \
--cacert=/etc/kubernetes/pki/etcd-certs/ca.pem \
--cert=/etc/kubernetes/pki/etcd-certs/client.pem \
--key=/etc/kubernetes/pki/etcd-certs/client-key.pem \
snapshot save /home/supermap/openthings/etcd$(date +%Y%m%d_%H%M%S)_snapshot.db
  • 恢復snapshot restore:
ETCDCTL_API=3 etcdctl --endpoints=https://[10.1.1.199]:2379 \
--cacert=/etc/kubernetes/pki/etcd-certs/ca.pem \
--cert=/etc/kubernetes/pki/etcd-certs/client.pem \
--key=/etc/kubernetes/pki/etcd-certs/client-key.pem \
--data-dir=/var/lib/etcd \
--initial-advertise-peer-urls=https://10.1.1.199:2380 \
--initial-cluster=podc01=https://10.1.1.199:2380 \
--initial-cluster-token=etcd-cluster \
--name=podc01 \
snapshot restore /home/supermap/etcd_snapshot.db

上面的備份文件名能夠本身起,恢復時能對上就行。spa

2.3 更新主節點的etcd配置參數

  • 爲何須要更新?
    • 集羣apiserver使用地址爲10.1.1.199須要在多節點漂移,本地的etcd實例使用10.1.1.201固定地址。
    • 主節點etcd實例初始使用199地址,與最終的201不一致,這將自動生成兩個不一樣的etcd peerID,出現「peerID mismatch」錯誤,引發整個etcd集羣沒法訪問。
    • 10.1.1.199的PeerID已寫入/var/lib/etcd數據庫中,只能在etcd服務可用時經過服務接口member update修改。

包括:.net

  • /var/lib/etcd目錄下的數據,使用etcdctl member update命令來進行。
  • 以及修改/etc/kubernetes/manifests/etcd.yaml配置參數,由kubelet來加載運行etcd的實例。

首先,檢查etcd集羣的運行狀態:

ETCDCTL_API=3 etcdctl --endpoints=https://[10.1.1.199]:2379 \
--cacert=/etc/kubernetes/pki/etcd-certs/ca.pem \
--cert=/etc/kubernetes/pki/etcd-certs/client.pem \
--key=/etc/kubernetes/pki/etcd-certs/client-key.pem \
endpoint status -w table

而後,更新etcd實例的peer-urls:

ETCDCTL_API=3 etcdctl --cacert=/etc/kubernetes/pki/etcd-certs/ca.pem \
--cert=/etc/kubernetes/pki/etcd-certs/client.pem \
--key=/etc/kubernetes/pki/etcd-certs/client-key.pem \
--endpoints=https://[10.1.1.199]:2379 \
member update podc01 --peer-urls=https://10.1.1.201:2380

第三,修改etcd實例的client-urls。

  • 此時,中止kubelet服務。
sudo systemctl stop kubelet
  • 編輯/etc/kubernetes/manifests/etcd.yaml文件.
apiVersion: v1
kind: Pod
metadata:
  annotations:
    scheduler.alpha.kubernetes.io/critical-pod: ""
  creationTimestamp: null
  labels:
    component: etcd
    tier: control-plane
  name: etcd
  namespace: kube-system
spec:
  containers:
  - command:
    - etcd
    - --advertise-client-urls=https://10.1.1.201:2379
    - --cert-file=/etc/kubernetes/pki/etcd/server.pem
    - --client-cert-auth=true
    - --data-dir=/var/lib/etcd
    - --initial-advertise-peer-urls=https://10.1.1.201:2380
    - --initial-cluster=podc01=https://10.1.1.201:2380
    - --key-file=/etc/kubernetes/pki/etcd/server-key.pem
    - --listen-client-urls=https://127.0.0.1:2379,https://10.1.1.201:2379
    - --listen-peer-urls=https://10.1.1.201:2380
    - --name=podc01
    - --peer-cert-file=/etc/kubernetes/pki/etcd/peer1.pem
    - --peer-client-cert-auth=true
    - --peer-key-file=/etc/kubernetes/pki/etcd/peer1-key.pem
    - --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem
    - --snapshot-count=10000
    - --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem
    image: k8s.gcr.io/etcd:3.2.24
    imagePullPolicy: IfNotPresent
    livenessProbe:
      exec:
        command:
        - /bin/sh
        - -ec
        - ETCDCTL_API=3 etcdctl --endpoints=https://[127.0.0.1]:2379 --cacert=/etc/kubernetes/pki/etcd/ca.pem
          --cert=/etc/kubernetes/pki/etcd/client.pem --key=/etc/kubernetes/pki/etcd/client-key.pem
          get foo
      failureThreshold: 8
      initialDelaySeconds: 15
      timeoutSeconds: 15
    name: etcd
    resources: {}
    volumeMounts:
    - mountPath: /var/lib/etcd
      name: etcd-data
    - mountPath: /etc/kubernetes/pki/etcd
      name: etcd-certs
  hostNetwork: true
  priorityClassName: system-cluster-critical
  volumes:
  - hostPath:
      path: /etc/kubernetes/pki/etcd-certs
      type: DirectoryOrCreate
    name: etcd-certs
  - hostPath:
      path: /var/lib/etcd
      type: DirectoryOrCreate
    name: etcd-data
status: {}
  • 此時,重啓kubelet服務。
sudo systemctl start kubelet

檢查一下etcd的服務狀態:

ETCDCTL_API=3 etcdctl --endpoints=https://[10.1.1.201]:2379 --cacert=/etc/kubernetes/pki/etcd-certs/ca.pem --cert=/etc/kubernetes/pki/etcd-certs/client.pem --key=/etc/kubernetes/pki/etcd-certs/client-key.pem endpoint status -w table
  • 注意這裏的變化:--endpoints=https://[10.1.1.201]:2379,已經完成了地址切換。

2.4 修改 api-server.yaml

修改/etc/kubernetes/manifests/api-server.yaml文件,以下:

#    - --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
#    - --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
#    - --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
#    - --etcd-servers=https://127.0.0.1:2379

    - --etcd-cafile=/etc/kubernetes/pki/etcd-certs/ca.pem
    - --etcd-certfile=/etc/kubernetes/pki/etcd-certs/client.pem
    - --etcd-keyfile=/etc/kubernetes/pki/etcd-certs/client-key.pem
    - --etcd-servers=https://10.1.1.201:2379

將上面的新的etcd服務地址配置給kube-apiserver。

重啓 kubelet,以下:

#從新啓動kubelet服務。
sudo systemctl restart kubelet

#查看運行的容器實例。
docker ps

#查看全部運行的容器實例。
#包含已中止的,若是etcd啓動失敗退出,可經過該命令查看。
docker ps -a

#查看特定容器實例的日誌。
docker logs idxxxx

再次檢查etcd狀態:

ETCDCTL_API=3 etcdctl --endpoints=https://[10.1.1.201]:2379 \
--cacert=/etc/kubernetes/pki/etcd-certs/ca.pem \
--cert=/etc/kubernetes/pki/etcd-certs/client.pem \
--key=/etc/kubernetes/pki/etcd-certs/client-key.pem \
endpoint status -w table

檢查kubernetes集羣狀態(kubectl get pod --all-namespaces)。

2.5 注意事項

  • Kubernetes的kubeadm工具安裝的單節點etcd實例沒法直接擴展到集羣,須要修改配置參數。
  • 任什麼時候候(如下同)修改etcd文件時,都應該中止kubelet集羣,手工終止運行的etcd實例。
    • 不然,若是「髒」信息被寫入etcd數據庫,將致使etcd服務所有沒法訪問。
  • 在出現「ID mismatch」錯誤時:
    • 若是直接刪除/var/lib/etcd的內容,將丟失Kubernetes集羣的配置信息。
    • 即使etcd集羣運行成功,後續也沒法訪問K8s服務。
    • 能夠經過備份snapshot store來重置原始數據庫。

三、擴展etcd實例到多個節點

下面將節點逐個加入(etcd節點的IP地址必須在前面的證書生成時加入)。

我使用Kubernetes的kubelet來託管etcd的運行(也能夠部署爲獨立的系統服務,如使用systemd)。

3.1 添加爲k8s工做節點

使用kubeadm join加入新的節點(將會建立kubelet基礎服務,並且etcd節點和kubernetes節點同時可用)。在主節點獲取添加命令,以下:

#在主節點上執行

kubeadm token create --print-join-command

3.2 複製pki證書

直接將master節點的/etc/kubernetes/pki目錄複製到子節點。以下:

#在子節點上執行

sudo scp -r root@10.1.1.201:/etc/kubernetes/pki /etc/kubernetes/
  • 其中,etcd的證書放在/etc/kubernetes/pki/etc-certs中,在下面的etcd.yaml文件將按照此設置。

3.3 中止kubelet服務

命令爲:

sudo systemctl stop kubelet
  • 若是不是第一次啓動,使用docker ps查看etcd實例是否已經運行。
  • 若是已經有etcd實例運行,使用docker rm -f idxxx將該實例完全刪除。

3.4 添加節點到etcd集羣

使用etcdctl的member add命令添加節點:

#在子節點上執行,將子節點peer-urls添加到etcd集羣中。

ETCDCTL_API=3 etcdctl \
--cacert=/etc/kubernetes/pki/etcd-certs/ca.pem \
--cert=/etc/kubernetes/pki/etcd-certs/client.pem \
--key=/etc/kubernetes/pki/etcd-certs/client-key.pem \
--endpoints=https://[10.1.1.201]:2379 \
member add podc02 --peer-urls=https://10.1.1.202:2380

此時,etcdctl member list查當作員爲unstarted狀態。命令以下:

ETCDCTL_API=3 etcdctl --endpoints=https://[10.1.1.201]:2379 \
--cacert=/etc/kubernetes/pki/etcd-certs/ca.pem \
--cert=/etc/kubernetes/pki/etcd-certs/client.pem \
--key=/etc/kubernetes/pki/etcd-certs/client-key.pem \
member list -w table
  • 在編輯etcd.yaml過程當中,保持kubelet不要啓動(不然觸發etcd實例啓動,若是寫入錯誤數據到etcd集羣,將可能致使集羣沒法訪問)。

3.5 複製etcd.yaml

將etcd.yaml文件放入各個子節點的/etc/kubernetes/manifests目錄下,跟master節點同樣,而後sudo systemctl restart kubelet重啓kubelet服務,kubelet啓動時將會自動啓動/etc/kubernetes/manifests下的全部*.yaml實例爲靜態pod(靜態pod在Dashboard刪除時會刪除當前的運行實例,而後被kubelet自動重啓,不會永久刪除)。

  • 複製etcd.yaml文件,以下:
#在子節點上執行

sudo scp -r root@10.1.1.201:/etc/kubernetes/manifests/etcd.yaml /etc/kubernetes/manifests/
  • 編輯 etcd.conf 文件,以下:
sudo nano /etc/kubernetes/manifest/etcd.yaml
  • 內容以下:
#子節點podc02上的/etc/kubernetes/manifests/etcd.yaml

apiVersion: v1
kind: Pod
metadata:
  annotations:
    scheduler.alpha.kubernetes.io/critical-pod: ""
  creationTimestamp: null
  labels:
    component: etcd
    tier: control-plane
  name: etcd
  namespace: kube-system
spec:
  containers:
  - command:
    - etcd
    - --advertise-client-urls=https://10.1.1.202:2379
    - --cert-file=/etc/kubernetes/pki/etcd/server.pem
    - --client-cert-auth=true
    - --data-dir=/var/lib/etcd

    - --initial-advertise-peer-urls=https://10.1.1.202:2380
    - --initial-cluster=podc01=https://10.1.1.201:2380,podc02=https://10.1.1.202:2380
    - --initial-cluster-token=etcd-cluster
    - --initial-cluster-state=existing

    - --key-file=/etc/kubernetes/pki/etcd/server-key.pem
    - --listen-client-urls=https://127.0.0.1:2379,https://10.1.1.202:2379
    - --listen-peer-urls=https://10.1.1.202:2380

    - --name=podc02
    - --peer-cert-file=/etc/kubernetes/pki/etcd/peer2.pem
    - --peer-client-cert-auth=true
    - --peer-key-file=/etc/kubernetes/pki/etcd/peer2-key.pem
    - --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem
    - --snapshot-count=10000
    - --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem
    image: k8s.gcr.io/etcd:3.2.24
    imagePullPolicy: IfNotPresent
    livenessProbe:
      exec:
        command:
        - /bin/sh
        - -ec
        - ETCDCTL_API=3 etcdctl --endpoints=https://[127.0.0.1]:2379 --cacert=/etc/kubernetes/pki/etcd/ca.pem
          --cert=/etc/kubernetes/pki/etcd/client.pem --key=/etc/kubernetes/pki/etcd/client-key.pem
          get foo
      failureThreshold: 8
      initialDelaySeconds: 15
      timeoutSeconds: 15
    name: etcd
    resources: {}
    volumeMounts:
    - mountPath: /var/lib/etcd
      name: etcd-data
    - mountPath: /etc/kubernetes/pki/etcd
      name: etcd-certs
  hostNetwork: true
  priorityClassName: system-cluster-critical
  volumes:
  - hostPath:
      path: /etc/kubernetes/pki/etcd-certs
      type: DirectoryOrCreate
    name: etcd-certs
  - hostPath:
      path: /var/lib/etcd
      type: DirectoryOrCreate
    name: etcd-data
status: {}
  • 提示:
    • 修改的地方:
      • 修改:本地IP地址所有設爲10.1.1.202。
      • 修改:--name=podc02
      • 修改:--initial-cluster=podc01=https://10.1.1.201:2380,podc02=https://10.1.1.202:2380
      • 添加:initial-cluster-token=etcd-cluster、- --initial-cluster-state=existing兩個參數。
      • 修改:證書格式爲*.pem,cfssl生成的格式與kubernetes原始的有些不一樣,用法同樣。
      • 修改:host-path的證書目錄指向到/etc/kubernetes/pki/etcd-certs。
    • 仔細檢查設置參數是否有錯。

3.6 重啓kubelet服務

確認etcd參數正確,如今能夠啓動kubelet服務了。命令爲:

sudo systemctl start kubelet
  • 使用docker ps查看etcd實例是否已經運行。
  • 若是etcd實例未運行,使用docker ps -a查看未運行的etcd實例ID。
  • 使用命令 docker logs idxxx 查看etcd實例的日誌信息,根據信息修改etcd.yaml從新啓動kubelet。
    • 命令爲:sudo systemctl restart kubelet
  • ⚠️注意:該節點必須已有etcd的容器鏡像。

! 參照上面的3.1-3.6方法將全部etcd集羣子節點加入到集羣中(注意嚴格按照順序操做)。

3.7 查看etcd集羣信息

能夠在主機安裝etcd-client,而後etcdctl能夠直接鏈接到容器中的etcd服務。

查看etcd集羣成員列表:

# etcd cluster member list

echo ""
echo "============================="
echo "+ etcd cluster member list..."

ETCDCTL_API=3 etcdctl \
--cacert=/etc/kubernetes/pki/etcd-certs/ca.pem \
--cert=/etc/kubernetes/pki/etcd-certs/client.pem \
--key=/etc/kubernetes/pki/etcd-certs/client-key.pem \
member list -w table --endpoints=https://[10.1.1.201]:2379

輸出以下:

=============================
+ etcd cluster member list...
+------------------+---------+--------+-------------------------+-------------------------+
|        ID        | STATUS  |  NAME  |       PEER ADDRS        |      CLIENT ADDRS       |
+------------------+---------+--------+-------------------------+-------------------------+
|  741ead392743e35 | started | podc02 | https://10.1.1.202:2380 | https://10.1.1.202:2379 |
| 72077d56570df47f | started | podc01 | https://10.1.1.201:2380 | https://10.1.1.201:2379 |
| dfc70cacefa4fbbb | started | podc04 | https://10.1.1.204:2380 | https://10.1.1.204:2379 |
| e3ecb8f6d5866785 | started | podc03 | https://10.1.1.203:2380 | https://10.1.1.203:2379 |
+------------------+---------+--------+-------------------------+-------------------------+

查看etcd集羣成員狀態:

# member list, local

echo ""
echo "========================="
echo "+ etcd cluster status... "

ETCDCTL_API=3 etcdctl \
--cacert=/etc/kubernetes/pki/etcd-certs/ca.pem \
--cert=/etc/kubernetes/pki/etcd-certs/client.pem \
--key=/etc/kubernetes/pki/etcd-certs/client-key.pem \
--endpoints=https://[10.1.1.201]:2379,https://[10.1.1.202]:2379,https://[10.1.1.203]:2379,https://[10.1.1.204]:2379 \
endpoint status -w table

輸出以下:

=========================
+ etcd cluster status... 
+---------------------------+------------------+---------+---------+-----------+-----------+------------+
|         ENDPOINT          |        ID        | VERSION | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX |
+---------------------------+------------------+---------+---------+-----------+-----------+------------+
| https://[10.1.1.201]:2379 | 72077d56570df47f |  3.2.24 |  4.2 MB |      true |      1875 |     253980 |
| https://[10.1.1.202]:2379 |  741ead392743e35 |  3.2.24 |  4.2 MB |     false |      1875 |     253980 |
| https://[10.1.1.203]:2379 | e3ecb8f6d5866785 |  3.2.24 |  4.2 MB |     false |      1875 |     253980 |
| https://[10.1.1.204]:2379 | dfc70cacefa4fbbb |  3.2.24 |  4.2 MB |     false |      1875 |     253980 |
+---------------------------+------------------+---------+---------+-----------+-----------+------------+

3.8 修改etcd節點的api-server.yaml

修改/etc/kubernetes/manifests/api-server.yaml文件,以下:

#    - --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
#    - --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
#    - --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
#    - --etcd-servers=https://127.0.0.1:2379

    - --etcd-cafile=/etc/kubernetes/pki/etcd-certs/ca.pem
    - --etcd-certfile=/etc/kubernetes/pki/etcd-certs/client.pem
    - --etcd-keyfile=/etc/kubernetes/pki/etcd-certs/client-key.pem
    - --etcd-servers=https://10.1.1.201:2379

將上面的新的etcd服務地址配置給kube-apiserver。

⚠️提示:

  • etcd集羣要麼一個節點,要麼至少三個節點,能夠對一個節點失敗提供容錯。
  • etcd集羣若是隻有兩個節點,一個節點失敗時,整個集羣將沒法訪問,即便還有一個節點可用。

下一步:

  • 再配合keepalived的虛擬IP漂移功能,節點故障時主IP轉移到子節點上的apiserver服務,並使用本地的etcd實例訪問存儲。
  • 此時,主節點的狀態控制和調度功能在子節點上尚未,所以沒法使用。
  • 還須要對kube-control-manager和kube-scheduler進行多節點部署,實現狀態控制和調度功能的多節點遷移,便可完整實現容錯機制。

參考:

相關文章
相關標籤/搜索