自從2020年2月23日 園子全站登船 以後,咱們一邊感嘆「不上船不知道,一上船嚇一跳」 —— kubernetes 比 docker swarm 強大太多,一邊有一個杞人憂天的擔心 —— 假如整個 kubernetes 集羣宕機怎麼辦?html
隨着在船上的日子愈來愈長,隨着對 kubernetes 愈來愈依賴,咱們的杞人憂天也愈來愈難以揮去...。終於有一天,一個貶義的俗語讓咱們豁然開朗 —— 「腳踏兩隻船」,若是隻有1個集羣,kubernetes 再怎麼工業級標準,也沒法讓咱們高枕無憂,惟有2個集羣。因而,咱們找到了本身的解憂之道 —— 再開一艘船。node
再開一艘船的前提條件是再造一艘船,而造船的最佳方式顯然是從現有的這艘船克隆出一艘新船。對應到咱們的 kubernetes 集羣是用阿里雲 ecs 服務器本身搭建的場景,最佳方式就是用已有集羣 master 服務器的阿里雲 ecs 鏡像建立新集羣。git
帶着這個美好想法,咱們開始動手造船 —— 克隆新 kubernetes 集羣,但很快就遇到了殘酷的現實。k8s天不怕地不怕,就怕名兒換(換IP地址或者主機名),而經過鏡像建立的 master 服務器使用的是不一樣IP地址與主機名,雖然不改主機名不會給新集羣帶來問題,可是對命名控們來講這是沒法接受的,因而修改新 master 的IP地址與主機名成爲克隆的2個挑戰。github
通過努力,咱們終於打敗了這2個挑戰,成功克隆出了新集羣,今天經過這篇博文分享一下主要操做步驟。docker
k8s-master0
,IP地址是 10.0.1.81
kube-master0
,IP地址是 10.0.9.171
從 10.0.1.81 改成 10.0.9.171數據庫
1)將 /etc/kubernetes 目錄中與IP地址關聯的配置替換爲新IP地址ubuntu
涉及的配置文件api
/etc/kubernetes/kubelet.conf /etc/kubernetes/manifests/etcd.yaml /etc/kubernetes/manifests/kube-apiserver.yaml
經過下面的命令快速完成修改服務器
oldip=10.0.1.81 newip=10.0.9.171 cd /etc/kubernetes find . -type f | xargs sed -i "s/$oldip/$newip/"
2)給 etcd 啓動命令添加參數app
打開 /etc/kubernetes/manifests/etcd.yaml
,給command
添加
--initial-cluster-state=new --force-new-cluster
注:不太肯定該步驟是否必需,當時第一次修改IP以後集羣老是沒法正常運行,加了上面的參數才解決,集羣正常運行才能進行第4步的操做。
3)經過 iptables 將舊 IP 地址映射到新 IP 地址
iptables -t nat -A OUTPUT -d 10.0.1.81 -j DNAT --to-destination 10.0.9.171
4)修改集羣中與舊IP地址相關的配置
經過下面的命令重啓集羣使以前的修改生效,恢復集羣的基本運行,能夠執行 kubectl 命令
systemctl daemon-reload && systemctl restart kubelet && systemctl restart docker
替換 kubeadm-config ConfigMap 中的舊IP地址配置
kubectl -n kube-system edit cm kubeadm-config %s/10.0.1.81/10.0.9.171
5)從新生成 etcd-server 證書(這個證書與IP地址關聯)
cd /etc/kubernetes/pki/etcd rm server.crt server.key kubeadm init phase certs etcd-server
6)更新當前用戶的 .kube/config
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
7)去掉在第2步給 etcd 啓動命令添加的參數
# --initial-cluster-state=new # --force-new-cluster
8)重啓 kubelet 與 docker 服務使修改生效
systemctl daemon-reload && systemctl restart kubelet && systemctl restart docker
9)新集羣恢復正常運行
NAME STATUS ROLES AGE VERSION k8s-master0 Ready master 376d v1.17.0
注:這時 master 的主機名還沒修改
這與克隆新集羣沒有關係,是咱們在克隆過程當中順便升級,詳見 Kubernetes 升級過程記錄:從 1.17.0 升級至最新版 1.20.2
從 k8s-master0 改成 kube-master0
1)將宿主機 hostname 修改成 kube-master0
hostnamectl set-hostname kube-master0
2)替換 /etc/kubernetes/manifests 中與主機名相關的配置
oldhost=k8s-master0 newhost=kube-master0 cd /etc/kubernetes/manifests find . -type f | xargs sed -i "s/$oldhost/$newhost/"
3)導出集羣中 k8s-master0 的 node 配置文件
kubectl get node k8s-master0 -o yaml > kube-master0.yml
4)將配置文件中的 k8s-master0 替換爲 kube-master0
sed -i "s/k8s-master0/kube-master0/" kube-master0.yml
5)經過 etcdctl 命令從 etcd 數據庫中刪除 /registry/minions/k8s-master0
docker exec -it $(docker ps -f name=etcd_etcd -q) /bin/sh etcdctl --endpoints 127.0.0.1:2379 --cacert /etc/kubernetes/pki/etcd/ca.crt --cert /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key /registry/minions/k8s-master0
運行上面的刪除命令後,k8s-master0 就會從 kubectl get nodes 的輸出列表中消失。
6)用以前導出並修改的 node 配置文件部署 kube-master0
kubectl apply -f kube-master0.yml
部署後 kube-master0 出現中 kubectl get nodes 的輸出列表中,但處於 NotReady 狀態
$ kubectl get nodes NAME STATUS ROLES AGE VERSION kube-master0 NotReady control-plane,master 21h v1.20.2
在這個地方折騰了很多時間,其實問題很簡單,kubelet 使用的證書是與主機名綁定的,修改主機名後證書失效了。
7)從新生成 kubelet 使用的證書
查看 /etc/kubernetes/kubelet.conf
users: - name: default-auth user: client-certificate: /var/lib/kubelet/pki/kubelet-client-current.pem client-key: /var/lib/kubelet/pki/kubelet-client-current.pem
用 openssl 命令查看證書綁定的 common name (CN)
$ openssl x509 -noout -subject -in kubelet-client-current.pem subject=O = system:nodes, CN = system:node:k8s-master0
證書綁定的是舊主機名,須要針對新主機名從新生成證書
kubeadm init phase kubeconfig kubelet
運行上面的命令從新生成證書後,/etc/kubernetes/kubelet.conf 中 users 部分變成下面的內容:
users: - name: system:node:kube-master0 user: client-certificate-data: ***... client-key-data: ***...
重啓 kubelet
systemctl restart kubelet
kubelet 重啓後,kube-master0 就進入了 Ready 狀態
$ kubectl get nodes NAME STATUS ROLES AGE VERSION kube-master0 Ready control-plane,master 18h v1.20.2
到此,修改IP地址與主機名已成功完成。
生成 node 加入集羣的命令
$ kubeadm token create --print-join-command
經過生成的 join 命令加入新的 node
kubeadm join k8s-api:6443 --token ***** --discovery-token-ca-cert-hash *****
刪除全部舊的 NotReady 狀態的 node
kubectl delete node $(kubectl get nodes | grep NotReady | cut -d " " -f1)
克隆出的新船啓航!
NAME STATUS ROLES AGE VERSION kube-master0 Ready control-plane,master 21h v1.20.2 kube-node1 Ready <none> 7d17h v1.20.2 kube-node2 Ready <none> 6d16h v1.20.2 kube-node3 Ready <none> 5d19h v1.20.2
參考資料: