自从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
参考资料: