自从2020年2月23日 园子全站登船 之后,我们一边感叹“不上船不知道,一上船吓一跳” —— kubernetes 比 docker swarm 强大太多,一边有一个杞人忧天的担忧 —— 假如整个 kubernetes 集群宕机怎么办?

随着在船上的日子越来越长,随着对 kubernetes 越来越依赖,我们的杞人忧天也越来越难以挥去...。终于有一天,一个贬义的俗语让我们豁然开朗 —— “脚踏两只船”,如果只有1个集群,kubernetes 再怎么工业级标准,也无法让我们高枕无忧,唯有2个集群。于是,我们找到了自己的解忧之道 —— 再开一艘船。

再开一艘船的前提条件是再造一艘船,而造船的最佳方式显然是从现有的这艘船克隆出一艘新船。对应到我们的 kubernetes 集群是用阿里云 ecs 服务器自己搭建的场景,最佳方式就是用已有集群 master 服务器的阿里云 ecs 镜像创建新集群。

带着这个美好想法,我们开始动手造船 —— 克隆新 kubernetes 集群,但很快就遇到了残酷的现实。k8s天不怕地不怕,就怕名儿换(换IP地址或者主机名),而通过镜像创建的 master 服务器使用的是不同IP地址与主机名,虽然不改主机名不会给新集群带来问题,但是对命名控们来说这是无法接受的,于是修改新 master 的IP地址与主机名成为克隆的2个挑战。

经过努力,我们终于战胜了这2个挑战,成功克隆出了新集群,今天通过这篇博文分享一下主要操作步骤。

背景信息

  • 已有集群 master 主机名是 k8s-master0,IP地址是 10.0.1.81
  • 新集群 master 主机名是 kube-master0,IP地址是 10.0.9.171
  • 已有集群 kubernetes 版本是 1.17.0,新集群 kubernetes 版本是 1.20.2
  • master 服务器操作系统是 ubuntu 18.04

准备工作

  • 已有集群 master 服务器 k8s-master0 打快照,创建镜像,用镜像创建新服务器 kube-master0

修改IP地址

从 10.0.1.81 改为 10.0.9.171

1)将 /etc/kubernetes 目录中与IP地址关联的配置替换为新IP地址

涉及的配置文件

/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 启动命令添加参数

打开 /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 版本

这与克隆新集群没有关系,是我们在克隆过程中顺便升级,详见 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

参考资料:

Kubernetes 开船记-脚踏两只船:用 master 服务器镜像克隆出新集群的更多相关文章

  1. k8s 开船记-脚踏两只船:船儿还是旧的好,不翻船才是硬道理

    自从上次开始脚踏两只船(2个独立的k8s集群同时运行),园子暂时用奢侈的土豪方式过上了安稳的船上生活. 这种方式除了费钱之外,还带来一个问题,我们的集装箱自动装船系统(基于gitlab-ci的自动化部 ...

  2. k8s 开船记-全站登船:Powered by .NET Core on Kubernetes

    今天 18:30 左右,我们迈出了 kubernetes 航行的关键一步——全站登船,完成了全站应用从 docker swarm 集群向 k8s 集群的切换,以前所未有的决心与信心重新开起这艘巨轮,而 ...

  3. k8s 开船记-故障公告:自建 k8s 集群在阿里云上大翻船

    非常非常抱歉,新年上班第一天, 在今天阿里云上气候突变情况下,由于我们开船技术差,在今天 10:15~12:00 左右的访问高峰,我们竟然把船给开翻了,造成近2个小时整个博客站点无法访问,由此给您带来 ...

  4. 使用kubeadm安装kubernetes/部署前准备/flannel网络插件/镜像下载/

    本文内容参考<kuberneters进阶实战>/马哥的新书/推荐 部署前的准备 主机名称解析 分布式系统环境中的多主机通信通常基于主机名称进行,这在IP地址存在变化的可能性时为主机提供了固 ...

  5. Kubernetes安装配置(包括master和node)

    部署Kubernetes云计算平台,至少准备两台服务器,此处为4台,包括一台Docker仓库: Kubernetes Master节点:192.168.124.20 Kubernetes Node1节 ...

  6. k8s 开船记:升级为豪华邮轮(高可用集群)与遇到奇怪故障(dns解析异常)

    之前我们搭建的 k8s 集群只用了1台 master ,可用性不高,这两天开始搭建高可用集群,但由于之前用 kubeadm 命令创建集群时没有使用 --control-plane-endpoint 参 ...

  7. 【故障公告】k8s 开船记:增加控制舱(control-plane)造成的翻船

    春节期间我们更换了 kubernetes 生产集群,旧集群的 kubernetes 版本是 1.17.0,新集群版本是 1.23.3,新集群上部署了 dapr,最近准备将更多独立部署的服务器部署到 k ...

  8. 记一次ftp服务器搭建走过的坑

    记一次ftp服务器搭建走过的坑 1.安装 ①下载 wget https://security.appspot.com/downloads/vsftpd-3.0.3.tar.gz #要FQ ②解压 ta ...

  9. k8s 开船记-触礁:四涡轮发动机撞坏3个引发502故障

    (图片来自网络) 非常抱歉,这次开船触礁故障给您带来麻烦了,请您谅解. 在我们昨天发布 k8s 开船记首航博文后,有园友在评论中发来贺词——“泰坦尼克号出发了[狗头]”,借此吉言,今天船就触礁了,还好 ...

随机推荐

  1. js下 Day10、尺寸位置属性

    一.元素尺寸信息 元素.offsetWidth: 元素的外宽高 width + padding + border 元素.offsetHeight: 元素的外宽高 height + padding + ...

  2. [OI笔记]每周刷题记录

    一些题库: bzoj.uoj.luogu(洛谷).CF.loj.hdu.poj.51nod 下面是一些近期的做题记录 省选爆炸-然后大概就先这样了,要回去读一段时间文化课,如果文化课还不错的话也许还会 ...

  3. Maven大全

    Maven 命令 mvn clean compile -Dmaven.test.skip=true 编译代码,检查代码安全性 Maven 注解 用maven管理库依赖,有个好处就是连同库的依赖的全部j ...

  4. Log4j日志的级别

    log4j规定了默认的几个级别:ALL < trace < debug < info < warn < error < fatal  < OFF 1)级别之间 ...

  5. [数据库]000 - 🍳Sysbench 数据库压力测试工具

    000 - Sysbench 数据库压力测试工具 sysbench 是一个开源的.模块化的.跨平台的多线程性能测试工具,可以用来进行CPU.内存.磁盘I/O.线程.数据库的性能测试.目前支持的数据库有 ...

  6. 学习Promise异步编程

    JavaScript引擎建立在单线程事件循环的概念上.单线程( Single-threaded )意味着同一时刻只能执行一段代码.所以引擎无须留意那些"可能"运行的代码.代码会被放 ...

  7. 高效扩展工具让 VS Code 如虎添翼

    Codelf 变量命名神器 Star:10688 https://github.com/unbug/codelf 新建项目,变量,类,方法,接口都需要命名,一个好的命名可以一眼看出这个地方的功能,Co ...

  8. GC算法与回收策略

    算法: 标记-清理  :首先标记出需要回收的对象 ,然后统一回收待标记的对象. 缺点:易产生大量空间碎片,空间碎片太多导致程序在运行过程中产生大对象时 因为空间不足导致容易导致另一个垃圾收集动作 标记 ...

  9. Vue利用v-for渲染时表单信息出不来

    今天在写项目时,Controller的值已经传入到html,但是利用vue进行渲染的时候就是出不来, 原因如下: 注意,in 之前的空格.

  10. 常用的Git命令清单

    目录 名词解释 开卷必读 一. 新建代码库 二.配置 三. 忽略某个文件的改动 四. 增加/删除文件 五. 代码提交 六. 分支 七. 标签 八. 查看信息 九. 远程同步 十. 撤销 十一. Git ...