使用Static Pod 創建高可用外部etcd叢集:詳解步驟

更新於 發佈於 閱讀時間約 29 分鐘

從官網可以知道,我們在建立一組高可用的Kubernetes Cluster時,針對ETCD有二種做法,一種是與Master節點共用,另一種則是將ETCD再獨立出來三個節點成為一組Cluster來進行運作。

raw-image

本文將說明如何建置出外部的ETCD Cluster,並以Static Pod的方式運行與管理,最後再與Kubernetes cluster整合。

本文將說明內容如下述:

  1. 為什麼要建立外部ETCD?
  2. 為什麼用Static Pod方式?
  3. 實作
  4. Kubernetes cluster建置整合
  5. 結論

那就開始吧!!


1.為什麼要建立外部ETCD?

如果把ETCD獨立出來,架構就會變成如下圖所示:

kubeadm HA topology — external ETCD

kubeadm HA topology — external ETCD

這種架構是將Master與ETCD成員關係進行解構(decouples),優點是確保就算有任一master成員出現異常或是任一ETCD成員出現異常,這種架構可以有效降低上述任一種情況出現後的所造成的系統衝擊。

但這種架構的缺點是需要更多的節點(master+etcd=6)來實現,對於資源的要求較高,另外ETCD與Master之間是靠網路來通訊也可能會有風險。在規劃時需要將其考慮進去。


2.為什麼用Static Pod方式?

Static Pod指的是在Pod在指定的節點上運行,而且由Kubelet直接管理,不會透過apiserver,與一般的Pod(ex. deployment)管理方式不同。對於Kubernetes apiserver來說,static pod看的到但管不了。

那kubelet是怎麼管理Static Pod呢?

  • 負責在Static Pod崩潰後重啟
  • 重啟後的Static Pod會綁定到指定節點的Kubelet
  • kubelet會透過Kubernetes apiserver幫每個static pod自動再建立一個mirror pod

那為什麼我會用Static Pod的方式來建立external ETCD呢?

答案是為了符合ETCD原本在Kubernetes內的類型,怎麼說呢,以下是Kubernetes內常見的Static Pod:

  • etcd
  • kube-apiserver
  • kube-controller-manager
  • kube-scheduler

如同上述,如果使用的架構是堆疊型,那也就意味ETCD在Kubernetes內也是以Static Pod的方式運行,那今天將它們獨立出來,如果還是使用原本的型態運行,那對於之後的整合與管理就會比較一致與容易。


接下來就進行實作部分,以下說明如何在三台獨立的節點上以static pod的方式完成ETCD的建置。

3. 實作

(Step0). 開始前準備

#----------------------------------------------
# S3-1. 關閉swap (all nodes)
#----------------------------------------------
[etcdX]# swapoff -a && sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab/fstab
raw-image
#---------------------------------------------
# S3-2. 安裝iproute-tc (all nodes)
#---------------------------------------------
[etcdX]# yum install iproute-tc
[etcdX]# vim /etc/modules-load.d/k8s.conf
overlay
br_netfilter

[etcdX]# modprobe overlay
[etcdX]# modprobe br_netfilter

[etcdX]# vim /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1

[etcdX]# sysctl --system
raw-image

(Step1). 基本軟體安裝

#---------------------------------------------
# S3-3. 安裝runtime (all nodes)
#---------------------------------------------
[etcdX]# export VERSION=1.27
[etcdX]# curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo
[etcdX]# curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.repo https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$VERSION/CentOS_8/devel:kubic:libcontainers:stable:cri-o:$VERSION.repo
[etcdX]# yum install cri-o -y
[etcdX]# systemctl enable --now crio
[etcdX]# crio version
[etcdX]# yum list cri-o --showduplicates|sort -r > crio.version
raw-image
#---------------------------------------------
# S3-4. 安裝kubelet, kubeadm, kubectl (all nodes)
#---------------------------------------------
[etcdX]# vim /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg

[etcdX]# yum clean all ; yum repolist

[etcdX]# yum list kubelet --showduplicates|sort -r > kubelet.version
[etcdX]# yum list kubeadm --showduplicates|sort -r > kubeadm.version
[etcdX]# yum list kubectl --showduplicates|sort -r > kubectl.version

[etcdX]# yum install kubelet-1.27.6-0 kubeadm-1.27.6-0 kubectl-1.27.6-0
#---------------------------------------------
# S3-5. 建立systemd service (all nodes)
# 尚未要建立k8s cluster,用原本的kubelet.conf會無法啟動,建立新的服務啟動檔
#---------------------------------------------
[etcdX]# vim /etc/crio/crio.conf
=> cgroup_manager = "systemd"
[etcdX]# cat /etc/crio/crio.conf | grep cgroup_manager
[etcdX]# systemctl restart crio

[etcdX]# cat << EOF > /usr/lib/systemd/system/kubelet.service.d/20-etcd-service-manager.conf
[Service]
ExecStart=
ExecStart=/usr/bin/kubelet --address=127.0.0.1 --pod-manifest-path=/etc/kubernetes/manifests --cgroup-driver=systemd --runtime-request-timeout=15m --container-runtime-endpoint=unix:///var/run/crio/crio.sock
Restart=always
EOF

[etcdX]# systemctl daemon-reload
[etcdX]# systemctl restart kubelet

※ 此處要注意:

(1) 官網上的路徑已修改到/usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf => (kubeadm 1.13.5之後)(依照官網的方法將無法啟動kubelet)

(2) systemd要換成crio用的cgroup(kubelet預設值為cgroupfs) (/etc/crio/crio.conf)

#---------------------------------------------
# S3-6. 建立kubeadm config (all nodes)
#---------------------------------------------
[etcdX]# vim /root/kubeadm_setup.sh
#!/bin/bash
export HOST0=10.107.88.15
export HOST1=10.107.88.16
export HOST2=10.107.88.17

export NAME0="etcd01"
export NAME1="etcd02"
export NAME2="etcd03"

mkdir -p /tmp/${HOST0}/ /tmp/${HOST1}/ /tmp/${HOST2}/

HOSTS=(${HOST0} ${HOST1} ${HOST2})
NAMES=(${NAME0} ${NAME1} ${NAME2})

for i in "${!HOSTS[@]}"; do
HOST=${HOSTS[$i]}
NAME=${NAMES[$i]}

cat << EOF > /tmp/${HOST}/kubeadmcfg.yaml
---
apiVersion: "kubeadm.k8s.io/v1beta3"
kind: InitConfiguration
nodeRegistration:
name: ${NAME}
localAPIEndpoint:
advertiseAddress: ${HOST}
---
apiVersion: "kubeadm.k8s.io/v1beta3"
kind: ClusterConfiguration
etcd:
local:
serverCertSANs:
- "${HOST}"
peerCertSANs:
- "${HOST}"
extraArgs:
initial-cluster: ${NAMES[0]}=https://${HOSTS[0]}:2380,${NAMES[1]}=https://${HOSTS[1]}:2380,${NAMES[2]}=https://${HOSTS[2]}:2380
initial-cluster-state: new
name: ${NAME}
listen-peer-urls: https://${HOST}:2380
listen-client-urls: https://${HOST}:2379
advertise-client-urls: https://${HOST}:2379
initial-advertise-peer-urls: https://${HOST}:2380
EOF
done

[etcdX]# ./kubeadm_setup.sh
[etcdX]# tree /tmp/<etcd_ip>
raw-image
raw-image

(Step2). 建立Certificates

#------------------------------------------------
# S3-7. 產生CA (etcd01)
#------------------------------------------------
[etcdX]# kubeadm init phase certs etcd-ca
[etcdX]# tree /etc/kubernetes/pki/etcd/
ca.crt
ca.key
#------------------------------------------------
# S3-8. 為每個成員建立CA (etcd01)
#------------------------------------------------
[etcdX]# export HOST0=10.107.88.15
[etcdX]# export HOST1=10.107.88.16
[etcdX]# export HOST2=10.107.88.17
[etcdX]# kubeadm init phase certs etcd-server --config=/tmp/${HOST2}/kubeadmcfg.yaml
[etcdX]# kubeadm init phase certs etcd-peer --config=/tmp/${HOST2}/kubeadmcfg.yaml
[etcdX]# kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST2}/kubeadmcfg.yaml
[etcdX]# kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST2}/kubeadmcfg.yaml
[etcdX]# cp -R /etc/kubernetes/pki /tmp/${HOST2}/

# 刪除不可重複使用的CA
[etcdX]# find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete
[etcdX]# tree /etc/kubernetes/pki/etcd
/etc/kubernetes/pki/etcd
├── ca.crt
└── ca.key
(只剩下最早產生的CA)

[etcdX]# kubeadm init phase certs etcd-server --config=/tmp/${HOST1}/kubeadmcfg.yaml
[etcdX]# kubeadm init phase certs etcd-peer --config=/tmp/${HOST1}/kubeadmcfg.yaml
[etcdX]# kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST1}/kubeadmcfg.yaml
[etcdX]# kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST1}/kubeadmcfg.yaml
[etcdX]# cp -R /etc/kubernetes/pki /tmp/${HOST1}/
[etcdX]# find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete

[etcdX]# kubeadm init phase certs etcd-server --config=/tmp/${HOST0}/kubeadmcfg.yaml
[etcdX]# kubeadm init phase certs etcd-peer --config=/tmp/${HOST0}/kubeadmcfg.yaml
[etcdX]# kubeadm init phase certs etcd-healthcheck-client --config=/tmp/${HOST0}/kubeadmcfg.yaml
[etcdX]# kubeadm init phase certs apiserver-etcd-client --config=/tmp/${HOST0}/kubeadmcfg.yaml
=> HOST0因為是本機,不用cp

# 刪除不應該從HOST0複製的CA
[etcdX]# find /tmp/${HOST2} -name ca.key -type f -delete
[etcdX]# find /tmp/${HOST1} -name ca.key -type f -delete
raw-image
#------------------------------------------------
# S3-9. copy 到各主機 (etcd01)
#------------------------------------------------
[etcdX]# USER=root
[etcdX]# HOST=${HOST1}
[etcdX]# scp -r /tmp/${HOST}/* ${USER}@${HOST}:
[etcdX]# ssh ${USER}@${HOST}
[etcdX]# chown -R root:root pki
[etcdX]# mv pki /etc/kubernetes/
#------------------------------------------------
# S3-10. 確認 (在每台主機上確認路徑相同)
#------------------------------------------------
[etcdX]# tree /root
[etcdX]# tree /etc/kubernetes/pki

(Step3). 建立ETCD Cluster

#------------------------------------------------
# S3-11. 產生static pod manifest (etcd01/02/03)
#------------------------------------------------
[etcd01]# kubeadm init phase etcd local --config=/root/kubeadmcfg.yaml
[etcd02]# kubeadm init phase etcd local --config=/root/kubeadmcfg.yaml
[etcd03]# kubeadm init phase etcd local --config=/root/kubeadmcfg.yaml
raw-image
#-------------------------------------------------
# S3-12. etcdctl installation
#-------------------------------------------------
[etcdX]# ETCD_RELEASE=$(curl -s https://api.github.com/repos/etcd-io/etcd/releases/latest|grep tag_name | cut -d '"' -f 4)
[etcdX]# echo $ETCD_RELEASE
v3.5.9

[etcdX]# wget https://github.com/etcd-io/etcd/releases/download/${ETCD_RELEASE}/etcd-${ETCD_RELEASE}-linux-amd64.tar.gz
[etcdX]# tar zxvf etcd-v3.5.9-linux-amd64.tar.gz
[etcdX]# cd etcd-v3.5.9-linux-amd64
[etcdX]# ls -al
[etcdX]# cp -rp etcdctl /usr/local/bin
#------------------------------------------------
# S3-13. 確認etcd cluster
#------------------------------------------------
[etcdX]# ETCDCTL_API=3 etcdctl \
--cert /etc/kubernetes/pki/etcd/peer.crt \
--key /etc/kubernetes/pki/etcd/peer.key \
--cacert /etc/kubernetes/pki/etcd/ca.crt \
--endpoints https://10.107.88.15:2379 endpoint health

https://10.107.88.15:2379 is healthy: successfully committed proposal: took = 10.08693ms
https://10.107.88.16:2379 is healthy: successfully committed proposal: took = 10.912799ms
https://10.107.88.17:2379 is healthy: successfully committed proposal: took = 10.461484ms

4. Kubernetes cluster建置整合

#------------------------------------------
# S4-1. 複製任一台etcd的ca到master01
#------------------------------------------
[etcd]# scp -rp /etc/kubernetes/pki/etcd/ca.crt root@master01:/root/etcd-ca
[etcd]# scp -rp /etc/kubernetes/pki/apiserver-etcd-client.crt root@master01:/root/etcd-ca
[etcd]# scp -rp /etc/kubernetes/pki/apiserver-etcd-client.key root@master01:/root/etcd-ca
#------------------------------------------
# S4-2. 設定master01的kubeadm-config.yaml
#------------------------------------------
[root]# vim kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: stable
apiServer:
certSANs:
- "test.example.poc"
controlPlaneEndpoint: "10.107.88.9:6443"
etcd:
external:
endpoints:
- https://10.107.88.15:2379
- https://10.107.88.16:2379
- https://10.107.88.17:2379
caFile: /etc/kubernetes/pki/etcd/ca.crt
certFile: /etc/kubernetes/pki/apiserver-etcd-client.crt
keyFile: /etc/kubernetes/pki/apiserver-etcd-client.key
networking:
podSubnet: "10.244.0.0/16"
#------------------------------------------
# S4-3. master01初始化
#------------------------------------------
[root]# kubeadm init --config kubeadm-config.yaml --upload-certs
raw-image

5. 結論

以上就是將ETCD從Control-Plane獨立出來的做法,一般來說,大部分的情境較少用這種架構,大部分還是使用與Control-Plane整合在一起的堆疊型的架構,包含企業商用的解決方式(ex. OpenShift)也是使用堆疊型的ETCD,以下提供幾點堆疊vs獨立的比較如下:

raw-image
  • [Stacked]: 由於在同一個節點,所以apiserver與etcd之間只要用loopback就可以溝通,Read操作就可以不用再透過master,也不用透過TCP/IP網路就可以讀取到資料,速度與穩定度都可以滿足。
  • [External]: 必須透過TCP/IP網路溝通
  • [Stacked]: ETCD比較重視Disk i/o,如果在同一個節點運行,網路就不會變成傳輸的瓶頸。
  • [External]: 網路頻寬會直接影響整體服務效能。
  • [Stacked]: 當Control-Plane成員壞了一台,代表在同一台的ETCD也會無法提供服務
  • [External]: 就算Master/ETCD任一個成員壞了,也不會直接造成立即性的系統崩壞發生。
  • [Stacked]: 部署簡單,不需要額外資源.
  • [External]: 要另外部署,也有額外資源需求。

本文說明了如何建立External ETCD的做法並且整合進Kubernetes Cluster部署,並且簡單說明了二者的實用性上的差異提供給大家參考。

本文有點長,感謝看到現在的你。

你的鼓勵是我繼續分享的動力,下篇文章再見。


※ References:

留言
avatar-img
留言分享你的想法!
avatar-img
超健忘閒人的沙龍
15會員
40內容數
記錄IT社畜的自我學習筆記,如同專題名稱,主要是怕自已忘記自已做過什麼、學到什麼。索性就分享我自已在學習Kubernetes這條路上的各種測試、學習心得。
2024/05/08
本文將介紹如何在Gitlab上部署和註冊runner,以進行CI/CD測試。透過Docker-compose方式進行部署,同時注意安裝時的一些注意事項。建議學習者至少掌握一種以上的Pipeline工具,以滿足實務上的需求。
Thumbnail
2024/05/08
本文將介紹如何在Gitlab上部署和註冊runner,以進行CI/CD測試。透過Docker-compose方式進行部署,同時注意安裝時的一些注意事項。建議學習者至少掌握一種以上的Pipeline工具,以滿足實務上的需求。
Thumbnail
2024/04/19
上一篇說明了如何在Kubernetes上建立基本的MySQL standalone,並加入phpmyadmin(PMA)來進行圖形化的管理,本篇就再進階一步,實作MySQL replication架構(master-salve),並進行驗證是否成功。
Thumbnail
2024/04/19
上一篇說明了如何在Kubernetes上建立基本的MySQL standalone,並加入phpmyadmin(PMA)來進行圖形化的管理,本篇就再進階一步,實作MySQL replication架構(master-salve),並進行驗證是否成功。
Thumbnail
2024/04/09
本文記錄如何在Kubernetes環境下,部署Standalone架構的MySQL Database,並透過phpmyadmin進行管理。這篇文章將分成MySQL部署在K8S內的優勢、部署MySQL DB standalone、部署PhpMyAdmin (PMA)、結論四個部分進行說明與實作的流程。
Thumbnail
2024/04/09
本文記錄如何在Kubernetes環境下,部署Standalone架構的MySQL Database,並透過phpmyadmin進行管理。這篇文章將分成MySQL部署在K8S內的優勢、部署MySQL DB standalone、部署PhpMyAdmin (PMA)、結論四個部分進行說明與實作的流程。
Thumbnail
看更多
你可能也想看
Thumbnail
2025 vocus 推出最受矚目的活動之一——《開箱你的美好生活》,我們跟著創作者一起「開箱」各種故事、景點、餐廳、超值好物⋯⋯甚至那些讓人會心一笑的生活小廢物;這次活動不僅送出了許多獎勵,也反映了「內容有價」——創作不只是分享、紀錄,也能用各種不同形式變現、帶來實際收入。
Thumbnail
2025 vocus 推出最受矚目的活動之一——《開箱你的美好生活》,我們跟著創作者一起「開箱」各種故事、景點、餐廳、超值好物⋯⋯甚至那些讓人會心一笑的生活小廢物;這次活動不僅送出了許多獎勵,也反映了「內容有價」——創作不只是分享、紀錄,也能用各種不同形式變現、帶來實際收入。
Thumbnail
嗨!歡迎來到 vocus vocus 方格子是台灣最大的內容創作與知識變現平台,並且計畫持續拓展東南亞等等國際市場。我們致力於打造讓創作者能夠自由發表、累積影響力並獲得實質收益的創作生態圈!「創作至上」是我們的核心價值,我們致力於透過平台功能與服務,賦予創作者更多的可能。 vocus 平台匯聚了
Thumbnail
嗨!歡迎來到 vocus vocus 方格子是台灣最大的內容創作與知識變現平台,並且計畫持續拓展東南亞等等國際市場。我們致力於打造讓創作者能夠自由發表、累積影響力並獲得實質收益的創作生態圈!「創作至上」是我們的核心價值,我們致力於透過平台功能與服務,賦予創作者更多的可能。 vocus 平台匯聚了
Thumbnail
從官網可以知道,我們在建立一組高可用的Kubernetes Cluster時,針對ETCD有二種做法,一種是與Master節點共用,另一種則是將ETCD再獨立出來三個節點成為一組Cluster來進行運作。 本文將說明如何建置出外部的ETCD Cluster,並以Static Pod的方式運行與管理
Thumbnail
從官網可以知道,我們在建立一組高可用的Kubernetes Cluster時,針對ETCD有二種做法,一種是與Master節點共用,另一種則是將ETCD再獨立出來三個節點成為一組Cluster來進行運作。 本文將說明如何建置出外部的ETCD Cluster,並以Static Pod的方式運行與管理
Thumbnail
建立Kubernetes cluster時,ETCD 是必不可少的元件,事實上Kubernetes所有資料都會存進ETCD store中,如果要讓Kubernetes的運行效能更好,其中一種方法是在部署之前對ETCD的性能進行優化設計。
Thumbnail
建立Kubernetes cluster時,ETCD 是必不可少的元件,事實上Kubernetes所有資料都會存進ETCD store中,如果要讓Kubernetes的運行效能更好,其中一種方法是在部署之前對ETCD的性能進行優化設計。
Thumbnail
知道如何備份與還原ETCD才能確保當環境出現重大問題時,可以將你的環境回復回來,對於系統管理者來說,等於是救人一命。(認真來說其實也是救了你的主管一命)。
Thumbnail
知道如何備份與還原ETCD才能確保當環境出現重大問題時,可以將你的環境回復回來,對於系統管理者來說,等於是救人一命。(認真來說其實也是救了你的主管一命)。
Thumbnail
今天簡單演示如何在Kubernetes cluster利用local-path provider建構出storage class來提供應用程式進行資料的存放。
Thumbnail
今天簡單演示如何在Kubernetes cluster利用local-path provider建構出storage class來提供應用程式進行資料的存放。
Thumbnail
本篇將補完上一篇所提到關於StatefulSet的實作部份。
Thumbnail
本篇將補完上一篇所提到關於StatefulSet的實作部份。
Thumbnail
本篇將說明關於StatefulSet的基本概念
Thumbnail
本篇將說明關於StatefulSet的基本概念
Thumbnail
本文將說明關於Local volume 與hostPath二種類型的差異與一些注意事項。
Thumbnail
本文將說明關於Local volume 與hostPath二種類型的差異與一些注意事項。
Thumbnail
因為想要使用FQDN的方式連接到Kubernetes cluster內部的應用服務,加上早已使用Linux Bind為測試環境的主要DNS
Thumbnail
因為想要使用FQDN的方式連接到Kubernetes cluster內部的應用服務,加上早已使用Linux Bind為測試環境的主要DNS
Thumbnail
什麼是Kubernetes Service? 先來個官網的解說 A Kubernetes Service is an abstraction which defines a logical set of Pods and a policy by which to access them. 白話文就是
Thumbnail
什麼是Kubernetes Service? 先來個官網的解說 A Kubernetes Service is an abstraction which defines a logical set of Pods and a policy by which to access them. 白話文就是
Thumbnail
Kubernetes是現代應用程序開發和部署的重要技術,而Pod是Kubernetes中最小的部署單位。Pod是一個或多個container的集合,它們共享一個網路命名空間和一個網路接口。Pod不僅提供了一個簡單而強大的container環境,還可以用於實現多種container編排方案,例如負載平
Thumbnail
Kubernetes是現代應用程序開發和部署的重要技術,而Pod是Kubernetes中最小的部署單位。Pod是一個或多個container的集合,它們共享一個網路命名空間和一個網路接口。Pod不僅提供了一個簡單而強大的container環境,還可以用於實現多種container編排方案,例如負載平
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News