Upgrade Kubernets From Binary to Kubeadm

记一次从二进制部署的 k8s 集群 到 kubeadm 部署的 k8s 迁移测试。
原有 k8s 集群为二进制形式部署,集群管理不太方便,准备在集群升级的机会,将集群部署方式改为 kubeadm部署,本文记录测试迁移的过程。

部署新的 master 集群 Link to heading

etcd 数据迁移 Link to heading

为了完全不影响原有集群的运行,将 etcd 也做迁移,新的 master 连接新的 etcd,不对老集群造成影响。
首先新建一个 etcd,并使用 etcd 的 make-mirror 功能将原有集群的 etcd 数据同步到新的etcd中。

# 新起一个 etcd,为了方便这里新建不带证书的 http 端口
docker run -d \
        --name etcd \
	--net host \
	-v /data/etcd:/var/lib/etcd \
	quay.io/coreos/etcd:v3.3.13 \
	etcd --listen-client-urls http://0.0.0.0:2379 --advertise-client-urls http://0.0.0.0:2379
#  迁移数据
export ETCDCTL_API=3
etcdctl --endpoints=https://etcd-ip:2379 --cert=/etc/kubernetes/ssl/etcd.pem --cacert=/etc/kubernetes/ssl/ca.pem --key=/etc/kubernetes/ssl/etcd-key.pem make-mirror http://destination-ip:2379

由于 kubeadm 会自动新建 dns,所以在新的 etcd 中,将导入过来的 kube-dns 相关数据手动删掉。

# 执行如下命令知道删掉所有 kube-dns 相关的key
echo  $(etcdctl get / --prefix --keys-only | grep 'kube-dns') | awk -F ' ' '{ print $1}' | xargs etcdctl del

新建 master 集群 Link to heading

使用 kubeadm 新建集群,要注意集群配置要和之前一致,如 serviceSubnet, netSubnet 等,并指定 etcd 为刚才新建的 etcd,以下为 kubeadm 配置文件(用的老版本配置,最新版本的 kubeadm 已经不支持)。

apiVersion: kubeadm.k8s.io/v1alpha1
kind: MasterConfiguration
api:
  advertiseAddress: 172.27.32.165
etcd:
  endpoints:
    - http://172.27.32.165:2379
networking:
  serviceSubnet: 10.254.0.0/16
  podSubnet: 172.41.0.0/16
kubernetesVersion: 1.10.13
imageRepository: harbor.guahao-inc.com/kubernetes
apiServerExtraArgs:
  insecure-bind-address: 172.27.32.165
kubeletConfiguration:
  baseConfig:
    clusterDNS:
    - 10.254.0.2
nodeName: 172.27.32.165
# kubelet.service 加上如下配置
Environment="KUBELET_EXTRA_ARGS=--pod-infra-container-image=harbor.guahao-inc.com/kubernetes/pause-amd64:3.1 --hostname-override=172.27.32.165"

kubeadm 配置文件中设置了nodeName,要同时在 kubelet 的 kubelet.service文件中加上 –hostname-override 参事,否则 kubelet 注册 apiserver 时会出现node forbidden 错误

# 使用配置文件新建 master 节点,目前所用 k8s 集群版本较老,不支持新版本docker,忽略docker版本校验
# 创建之前可以先 dryrun 进行校验,没问题再真正执行,dryrun 会将需要做的步骤模拟执行并输出,不会真正操作
kubeadm init --dry-run  --config kubeadm.yaml --ignore-preflight-errors=SystemVerification
kubeadm init --config kubeadm.yaml --ignore-preflight-errors=SystemVerification

完成后会提示新建成功,并提示后续操作命令,及node节点加入集群的命令。

# 配置 kubectl
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

# 加入集群的命令可以用 kubeadm 重新生成
kubeadm token create --print-join-command

此时已经建好新的 master 节点,并且使用 kubectl get no 可以看到原有集群的节点信息,但这时只是导过来的 etcd,实际上此时 master 节点并未控制 node 节点,node 节点的 kubelet 依然是注册到老的 master 节点,想要将原来的 node 节点迁移到新的 master 节点下,还需要逐台修改每台 node 节点的配置。

迁移 node 节点 Link to heading

迁移 node 节点要注意首先要备份原node节点的 /etc/kubernetes//var/lib/kubelet//etc/systemd/system/kubelet.service/etc/systemd/system/kubelet.service.d/文件及目录,以便出现异常时可以快速回滚恢复。
做好备份后,将当前节点kubeletkube-proxy停掉,并执行如下命令,由于节点上 kebelet 已经启动且已有 pod 在运行,需要加上 --ignore-preflight-errors=all 强制执行,主要是为了生成 kubelet 相关证书及配置文件,并重启 kubelet 注册到新的 master 节点的 apiserver,此时 --node-name 要指定和之前一样的节点名称,如果 kubelet.service 配置不正确的话,需要手动修改相关配置(参考 kubeadm 新建节点的配置)。

kubeadm join  --node-name 192.168.l96.31 172.27.32.165:6443 --token qfr5ff.sd7qn0tlx2a3kxtl --discovery-token-ca-cert-hash sha256:0f7175e3cf8e40d41983688aeb8e80153c2502cd375629379a5abb53f71bce0d --ignore-preflight-errors=all

成功的话,在新的 master 节点执行kubectl get no会能够看到迁移的节点已经变成 ready 状态。
若出现异常,将之前备份的目录和文件还原,并重启kubeletkube-proxy,即可恢复节点。


以上是经测试验证过的一种思路,但是在实际生产中,用这种方式进行迁移,还是会对在运行容器产生影响,若要应用到生产环境,还需更严谨详细的测试,并且此种方式的迁移风险较大,测试中遇到很多坑,应尽量避免。