k8s 升级方案

官方文档参考:https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade

1. 注意事项

  • 升级前做好数据备份,例如 etcd 数据等。
  • 不要跨两个大版本进行升级,可能会存在不兼容。
  • 跨多个版本的可以逐个版本依次进行升级。
  • 升级前要在测试环境进行充分的演练,充分考虑到回滚方案(事先将回滚动作制作成脚本,方便生产环境遇到问题时快速响应)

2. 升级方案

对于线上环境,升级 k8s 需要做到不中断当前业务容器的灰度升级,常见方案有如下两种:

  • 蓝绿方式:仿照现有k8s集群,部署一套新环境,在新环境里部署指定版本的 k8s,然后把业务应用也部署到新环境,然后将流量切换到新环境。
  • 滚动升级:在高可用的集群环境可以先逐个更新 master 上的 k8s 服务版本,再逐个更新 Node 上的k8s 服务版本。

考虑到成本等因素,一般不会采用方案一,因此下面我们来看一下方案二的详细步骤。

3. 升级详细步骤

3.1 配置新版本 k8s 的下载仓库

使用阿里云的镜像,参考文档:

3.2 数据备份并隔离流量

备份准备升级节点上的数据,并将转发到该节点的流量隔离。

etcdctl 的官网下载地址:https://github.com/etcd-io/etcd/releases

etcd 数据库备份:

# 把当前节点的 etcd 数据导出为快照
ETCDCTL_API=3 etcdctl --endpoints=https://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 snapshot save etcdbackupfile.db


# 恢复数据
mv /var/lib/etcd /var/lib/etcd_bak
mkdir /var/lib/etcd

ETCDCTL_API=3 etcdutl --endpoints=https://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 snapshot restore etcdbackupfile.db --data-dir=/var/lib/etcd
ShellScript

备份脚本:

# vim /var/lib/etcd_db_bak/etcd_backup.sh

#!/bin/bash


# 备份目录
backup_dir="/var/lib/etcd_db_bak"

# 时间戳
DATE=`date +"%Y%m%d%H%M"`

# 判断目录是否存在,不在则创建
if [ ! -d $backup_dir ];then
   mkdir $backup_dir
fi

# 执行数据库备份
ETCDCTL_API=3 etcdctl --endpoints=https://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 snapshot save $backup_dir/etcdbackupfile_$DATE.db
ShellScript

设置定时任务

crontab -e

30 18 * * *  /var/lib/etcd_db_bak/etcd_backup.sh
50 23 * * *  find /var/lib/etcd_db_bak/ -mtime +5 -name "*.db" -exec rm -rf {} \;
ShellScript

3.3 禁止新 pod 调度到当前节点

# 禁止新 pod 调度到当前节点
kubectl cordon k8s-master-01-c-201

# 查看节点状态
kubectl get node
ShellScript

3.4 对关键服务创建 PDB 保护策略

建议一个关键的不可中断服务通常应该至少两副本,但实际情况可能不会这么规范,因此我们可以添加 PDB 策略来对一些关键服务进行硬性限制,加了之后再去 drain 排空的时候,如果存在一些受 PDB 保护的应用,则会 drain 失败,此时会硬性要求你先扩容副本,因为你已经 cordon 过了,所以再启新副本一定是在新节点上。

PDB 示例:

vim pdb-test.yaml

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: coredns-pdb
spec:
  selector:
    matchLabels:
      k8s-app: coredns
  minAvailable: 1
ShellScript

3.5 drain 驱逐业务 pod

kubectl drain k8s-master-01-c-201 --delete-local-data --ignore-daemonsets --force

# 参数说明:
--delete-local-data  # 删除本地数据(关键数据要提前备份好),即使 emptyDir也将删除(新版本不再支持该选型)
--ignore-daemonsets  # 忽略 DeamonSet,否则 DeamonSet被删除后,仍会自动重建
--force  # 不加 force 参数只会删除该 node节点上的 ReplicationController, ReplicaSet, DaemonSet,StatefulSet or Job,加上后所有 pod 都将删除;
ShellScript

3.6 升级当前 master 节点上的软件

# 升级 kubeadm
sudo yum install -y kubeadm-'1.31.0-*' --disableexcludes=kubernetes
# 验证下载操作正常,并且 kubeadm 版本正确
kubeadm version
# 验证升级计划
sudo kubeadm upgrade plan
# 如果报错 CoreDNS 版本不支持,可以使用以下参数忽略错误
sudo kubeadm upgrade plan --ignore-preflight-errors=CoreDNSUnsupportedPlugins,CoreDNSMigration

# kubeadm 更新计划会打印出目前能支持到的版本,由于我们当前安装的 kubeadm 工具是 v1.31.0版本,后续也必须保持统一版本
sudo kubeadm upgrade apply v1.31.0
sudo kubeadm upgrade apply v1.31.0 --ignore-preflight-errors=CoreDNSUnsupportedPlugins,CoreDNSMigration

# ubuntu:
sudo apt-mark unhold kubeadm && sudo apt-get update && sudo apt-get install -y kubeadm='1.31.0-*' && sudo apt-mark hold kubeadm
kubeadm version
sudo kubeadm upgrade plan
sudo kubeadm upgrade apply v1.31.0
ShellScript

升级 kubelet 和 kubectl

sudo yum install -y kubelet-'1.31.0-*' kubectl-'1.31.0-*' --disableexcludes=kubernetes

sudo apt-mark unhold kubelet kubectl && sudo apt-get update && sudo apt-get install -y kubelet='1.31.0-*' kubectl='1.31.0-*' && sudo apt-mark hold kubelet kubectl

# 重启 kubelet
sudo systemctl daemon-reload
sudo systemctl restart kubelet

# 解除不可调度状态
kubectl uncordon k8s-master-01-c-201

# 最后在其他 master 执行
sudo kubeadm upgrade node
ShellScript

3.7 其他 master 节点升级

3.1~3.5 步骤相同,3.6 步骤如下:

# 升级 kubeadm
sudo yum install -y kubeadm-'1.31.0-*' --disableexcludes=kubernetes
# 验证下载操作正常,并且 kubeadm 版本正确
kubeadm version
sudo kubeadm upgrade node



# ubuntu:
sudo apt-mark unhold kubeadm && sudo apt-get update && sudo apt-get install -y kubeadm='1.31.0-*' && sudo apt-mark hold kubeadm
kubeadm version
sudo kubeadm upgrade node



# 最后升级 kubelet 和 kubectl 同 3.6 
ShellScript

3.8 node 节点升级

# 前面同 3.1~3.5 步骤
# centos:
# 升级 kubeadm
sudo yum install -y kubeadm-'1.31.0-*' --disableexcludes=kubernetes
sudo kubeadm upgrade node

# 升级 kubelet 和 kubectl
sudo yum install -y kubelet-'1.31.0-*' kubectl-'1.31.0-*' --disableexcludes=kubernetes
# 重启 kubelet
sudo systemctl daemon-reload
sudo systemctl restart kubelet
# 解除不可调度状态
kubectl uncordon k8s-node-01-c-211


# ubuntu:
sudo apt-mark unhold kubeadm && sudo apt-get update && sudo apt-get install -y kubeadm='1.31.0-*' && sudo apt-mark hold kubeadm
sudo kubeadm upgrade node

sudo apt-mark unhold kubelet kubectl && sudo apt-get update && sudo apt-get install -y kubelet='1.31.0-*' kubectl='1.31.0-*' && sudo apt-mark hold kubelet kubectl

sudo systemctl daemon-reload
sudo systemctl restart kubelet

kubectl uncordon k8s-node-01-c-211
ShellScript