官方文档参考: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 的下载仓库
使用阿里云的镜像,参考文档:
- 老版本 v1.24-v1.29:https://developer.aliyun.com/mirror/kubernetes/
- 新版本 v1.28及以上:https://mirrors.aliyun.com/kubernetes-new/
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 {} \;
ShellScript3.3 禁止新 pod 调度到当前节点
# 禁止新 pod 调度到当前节点
kubectl cordon k8s-master-01-c-201
# 查看节点状态
kubectl get node
ShellScript3.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
ShellScript3.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 都将删除;
ShellScript3.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
ShellScript3.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
ShellScript3.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