参考文档: Kubernetes版本升级实践
k8s 版本信息
版本号的含义
Kubernetes 版本表示为 x.y.z,其中 x 是主要版本,y 是次要版本,z 是补丁版本,遵循语义版本控制术语。有关更多信息,请参阅 Kubernetes 发布版本。
k8s 发行版与 github 分支的关系
简单来讲,kubernetes 项目存在3类分支(branch),分别为 master, release-X.Y, release-X.Y.Z。master 分支上的代码是最新的,每隔2周会生成一个发布版本(release),由新到旧以此为 master–>alpha–>beta–>Final release,这当中存在一些 cherrypicking 的规则,也就是说从一个分支上挑选一些必要 pull request 应用到另一个分支上。我们可以认为 X.Y.0 为稳定的版本,这个版本号意味着一个 Final release。一个 X.Y.0 版本会在 X.(Y-1).0 版本的3到4个月后出现。 X.Y.Z 为经过 cherrypick 后解决了必须的安全性漏洞、以及影响大量用户的无法解决的问题的补丁版本。 总体而言,我们一般关心 X.Y.0 (稳定版本),和 X.Y.Z(补丁版本) 的特性。
例如:
- v1.20.11: 1 为主要版本; 20 为次要版本; 11 为补丁版本
每个版本的支持时期
Kubernetes 项目维护最新三个次要版本的发布分支。结合上述一个 X.Y.0 版本会在 X.(Y-1).0 版本的3到4个月后出现的描述,也就是说1年前的版本就不再维护,每个次要版本的维护周期为9~12个月,就算有安全漏洞也不会有补丁版本。
新版本和旧版本有什么区别?
新版本与旧版本区别主要在于应用了社区中经过 cherrypick 挑选出来的PR以及修复了安全性漏洞、没有workaround(临时解决办法)的bug。
新版本对开发app调用k8s api接口有什么影响?
由于 k8s 本身是基于 api 为服务架构,k8s 系统内部也是通过互相调用 api 来运作的,总体而言 kubernetes api 在设计时遵循向上和向下兼容的原则。k8s的 api 是一个api的集合,称之为”API groups”。每一个 API group 维护着3个主要版本,分别是 GA,Beta,Alpha。 API的弃用只会通过在新的API group 启用的同时宣告旧 API group 将会弃用的方式来推进。GA 版本在宣告启用后将会向下兼容 12 个月或 3 个发行版。Beta 版本则为9个月或3个发行版。而 Alpha 则会立刻启用。这个遵循 kubernetes 版本的升级规则,也就是整体而言集群升级不支持跨度在 2个 Final release 发行版之上的操作。 每个发行版的 release note 中也有对API重大改动的描述。开发者们可以参阅其修改API。
版本升级注意事项
在 高可用(HA)集群 中, 多个
kube-apiserver实例小版本号最多差 1。- 例如: 最新的 kube-apiserver 版本号如果是 1.20,则受支持的 kube-apiserver 版本号包括 1.20 和 1.19
kubelet版本号不能高于 kube-apiserver,最多可以比 kube-apiserver 低两个小版本。- 例如: kube-apiserver 版本号如果是 1.20,受支持的的 kubelet 版本将包括 1.20、1.19 和 1.18
说明:如果 HA 集群中多个
kube-apiserver实例版本号不一致,相应的kubelet版本号可选范围也要减小。
如果 kube-apiserver 实例同时存在 1.20 和 1.19,kubelet 的受支持版本将是 1.19 和 1.18 (1.20 不再支持,因为它比 1.19 版本的 kube-apiserver 更新)
- 例如: kube-apiserver 版本号如果是 1.20,受支持的的 kubelet 版本将包括 1.20、1.19 和 1.18
kube-controller-manager、kube-scheduler和cloud-controller-manager版本不能高于 kube-apiserver 版本号。 最好它们的版本号与 kube-apiserver 保持一致,但允许比 kube-apiserver 低一个小版本(为了支持在线升级)- 例如: 如果 kube-apiserver 版本号为 1.20,kube-controller-manager、kube-scheduler 和 cloud-controller-manager 版本支持 1.20 和 1.19
kubectl可以比 kube-apiserver 高一个小版本,也可以低一个小版本。- 例如: 如果 kube-apiserver 当前是 1.20 版本,kubectl 则支持 1.21、1.20 和 1.19
如果 HA 集群中的多个 kube-apiserver 实例版本号不一致,相应的 kubectl 可用版本范围也会减小。
- 例如: 如果 kube-apiserver 当前是 1.20 版本,kubectl 则支持 1.21、1.20 和 1.19
组件升级次序
组件之间支持的版本偏差会影响组件升级的顺序。
kube-apiserver –> kube-controller-manager –> kube-scheduler –> cloud-controller-manager(安装了的话,未安装可忽略) –> kubelet –> kube-proxy
宏观升级流程
- 升级主master节点
- 升级其他master节点
- 升级node节点
微观升级步骤
- 先升级第一个主控制平面节点 Master 组件
- 再升级第一个主控制平面节点上的 Kubelet 和 kubectl
- 升级其他控制平面节点
- 升级Node节点
- 验证集群
升级 kubernetes 集群
升级之前注意事项
- 备份 etcd 数据库是最佳实践。
- 升级后,所有容器都会重启动,因为容器的hash值已更改。
- 由于版本的兼容性,只能从一个次要版本升级到另外一个次要版本,不能跳跃升级。
升级到 kubernetes v1.21.14
下载 kubernetes 安装包
1
wget https://dl.k8s.io/v1.21.14/kubernetes-server-linux-amd64.tar.gz
解压安装包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23tar xf kubernetes-server-linux-amd64.tar.gz
cd kubernetes/server/bin/
# ll
total 1075960
-rwxr-xr-x 1 root root 50847744 Jun 15 22:28 apiextensions-apiserver
-rwxr-xr-x 1 root root 44892160 Jun 15 22:28 kubeadm
-rwxr-xr-x 1 root root 48619520 Jun 15 22:28 kube-aggregator
-rwxr-xr-x 1 root root 122261504 Jun 15 22:28 kube-apiserver
-rw-r--r-- 1 root root 9 Jun 15 22:27 kube-apiserver.docker_tag
-rw------- 1 root root 127042560 Jun 15 22:27 kube-apiserver.tar
-rwxr-xr-x 1 root root 116461568 Jun 15 22:28 kube-controller-manager
-rw-r--r-- 1 root root 9 Jun 15 22:27 kube-controller-manager.docker_tag
-rw------- 1 root root 121242624 Jun 15 22:27 kube-controller-manager.tar
-rwxr-xr-x 1 root root 46686208 Jun 15 22:28 kubectl
-rwxr-xr-x 1 root root 55334056 Jun 15 22:28 kubectl-convert
-rwxr-xr-x 1 root root 118464048 Jun 15 22:28 kubelet
-rwxr-xr-x 1 root root 43376640 Jun 15 22:28 kube-proxy
-rw-r--r-- 1 root root 9 Jun 15 22:27 kube-proxy.docker_tag
-rw------- 1 root root 105378304 Jun 15 22:27 kube-proxy.tar
-rwxr-xr-x 1 root root 47378432 Jun 15 22:28 kube-scheduler
-rw-r--r-- 1 root root 9 Jun 15 22:27 kube-scheduler.docker_tag
-rw------- 1 root root 52159488 Jun 15 22:27 kube-scheduler.tar
-rwxr-xr-x 1 root root 1593344 Jun 15 22:28 mounter升级 kubectl 工具
1
2
3
4
5
6
7# 替换 kubectl 文件
\cp -rp kubectl /usr/local/bin/
# 查看 kubectl 客户端版本
kubectl version
Client Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.14", GitCommit:"0f77da5bd4809927e15d1658fb4aa8f13ad890a5", GitTreeState:"clean", BuildDate:"2022-06-15T14:17:29Z", GoVersion:"go1.16.15", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"20", GitVersion:"v1.20.11", GitCommit:"27522a29febbcc4badac257763044d0d90c11abd", GitTreeState:"clean", BuildDate:"2021-09-15T19:16:25Z", GoVersion:"go1.15.15", Compiler:"gc", Platform:"linux/amd64"}
升级 Master 组件
升级主 Master 节点的 kube-apiserver 组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20# 停止 kube-apiserver 服务
systemctl stop kube-apiserver
# 备份 kube-apiserver 组件
cp -rp /usr/local/kubernetes/bin/kube-apiserver /tmp/kube-apiserver.bak
# 替换 kube-apiserver 组件
\cp -rp kube-apiserver /usr/local/kubernetes/bin/
# 查看 kube-apiserver 文件版本
/usr/local/kubernetes/bin/kube-apiserver --version
# 启动 kube-apiserver 服务
systemctl daemon-reload && systemctl restart kube-apiserver.service
# 查看服务状态
systemctl status kube-apiserver.service
# 查看服务日志
journalctl -xef -u kube-apiserver.service升级主 Master 节点的 kube-controller-manager, kube-scheduler 组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23# 停止 kube-controller-manager 和 kube-scheduler 服务
systemctl stop kube-controller-manager.service kube-scheduler.service
# 备份 kube-controller-manager 和 kube-scheduler 文件
cp -rp /usr/local/kubernetes/bin/kube-controller-manager /tmp/kube-controller-manager.bak
cp -rp /usr/local/kubernetes/bin/kube-scheduler /tmp/kube-scheduler.bak
# 替换 kube-controller-manager 和 kube-scheduler 文件
\cp -rp kube-controller-manager kube-scheduler /usr/local/kubernetes/bin/
# 查看 kube-controller-manager 和 kube-scheduler 文件版本
/usr/local/kubernetes/bin/kube-controller-manager --version
/usr/local/kubernetes/bin/kube-scheduler --version
# 启动 kube-controller-manager 和 kube-scheduler 服务
systemctl daemon-reload && systemctl start kube-controller-manager kube-scheduler
# 查看服务状态
systemctl status kube-controller-manager kube-scheduler
# 查看服务日志
journalctl -xef -u kube-controller-manager
journalctl -xef -u kube-scheduler使用同样的方法升级其他 master 节点
1
2
3
4
5
6
7
8
9# 登录其他 master 节点,停止 master 组件服务
systemctl stop kube-apiserver kube-controller-manager kube-scheduler
# 拷贝文件到其他 master 节点
scp -rp kube-apiserver kube-controller-manager kube-scheduler root@k8s-sit-master02:/usr/local/kubernetes/bin/
scp -rp kube-apiserver kube-controller-manager kube-scheduler root@k8s-sit-master03:/usr/local/kubernetes/bin/
# 启动 Master 组件服务
systemctl start kube-apiserver kube-controller-manager kube-scheduler查看 master 组件状态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17# 查看服务状态
systemctl status kube-apiserver kube-controller-manager kube-scheduler
# 查看集群状态
# kubectl get cs
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
controller-manager Healthy ok
etcd-1 Healthy {"health":"true","reason":""}
etcd-2 Healthy {"health":"true","reason":""}
etcd-0 Healthy {"health":"true","reason":""}
# 查看集群版本
# kubectl version
Client Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.14", GitCommit:"0f77da5bd4809927e15d1658fb4aa8f13ad890a5", GitTreeState:"clean", BuildDate:"2022-06-15T14:17:29Z", GoVersion:"go1.16.15", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.14", GitCommit:"0f77da5bd4809927e15d1658fb4aa8f13ad890a5", GitTreeState:"clean", BuildDate:"2022-06-15T14:11:36Z", GoVersion:"go1.16.15", Compiler:"gc", Platform:"linux/amd64"}
升级 Worker 组件
升级 kube-proxy 组件
所有节点停止 kube-proxy 服务
1
systemctl stop kube-proxy
备份 kube-proxy 文件
1
cp -rp /usr/local/kubernetes/bin/kube-proxy /tmp/kube-proxy.bak
替换 kube-proxy 文件
1
2
3
4for i in k8s-sit-master01 k8s-sit-master02 k8s-sit-master03 k8s-sit-node01 k8s-sit-node02;do
ssh root@$i systemctl stop kube-proxy;
scp -rp kube-proxy root@$i:/usr/local/kubernetes/bin/;
done查看文件版本
1
/usr/local/kubernetes/bin/kube-proxy --version
启动 kube-proxy 服务
1
2
3
4
5
6
7systemctl start kube-proxy
# 查看服务状态
systemctl status kube-proxy
# 查看服务日志
journalctl -xef -u kube-proxy.service
升级 kubelet 组件
注意: 如果节点上部署了有状态服务,或者存在绑定节点运行的服务,比如 Elasticsearch 服务,不建议驱逐节点上的 Pod,建议直接停止 kubelet 服务,然后替换文件进行升级
将节点设置成不可调度状态
1
2
3
4
5
6
7
8
9
10# kubectl cordon k8s-sit-master01
node/k8s-sit-master01 cordoned
# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-sit-master01 Ready,SchedulingDisabled <none> 6d19h v1.20.11
k8s-sit-master02 Ready <none> 6d19h v1.20.11
k8s-sit-master03 Ready <none> 6d19h v1.20.11
k8s-sit-node01 Ready <none> 6d19h v1.20.11
k8s-sit-node02 Ready <none> 6d19h v1.20.11驱逐该节点上的 pod
1
2
3
4# kubectl drain k8s-sit-master01 --delete-emptydir-data --ignore-daemonsets --force
node/k8s-sit-master01 already cordoned
WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-qz4zl
node/k8s-sit-master01 drained停止节点上的 kubelet 服务
1
systemctl stop kubelet.service
备份 kubelet 文件
1
cp -rp /usr/local/kubernetes/bin/kubelet /tmp/kubelet.bak
替换 kubelet 组件
1
\cp -rp kubelet /usr/local/kubernetes/bin/
启动 kubelet 服务
1
systemctl start kubelet.service
查看节点状态
1
2
3
4
5
6
7
8
9systemctl status kubelet.service
# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-sit-master01 Ready,SchedulingDisabled <none> 6d19h v1.21.14
k8s-sit-master02 Ready <none> 6d19h v1.20.11
k8s-sit-master03 Ready <none> 6d19h v1.20.11
k8s-sit-node01 Ready <none> 6d19h v1.20.11
k8s-sit-node02 Ready <none> 6d19h v1.20.11恢复节点可调度状态
1
2# kubectl uncordon k8s-sit-master01
node/k8s-sit-master01 uncordoned再次确认节点状态
1
2
3
4
5
6
7# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-sit-master01 Ready <none> 6d19h v1.21.14
k8s-sit-master02 Ready <none> 6d19h v1.20.11
k8s-sit-master03 Ready <none> 6d19h v1.20.11
k8s-sit-node01 Ready <none> 6d19h v1.20.11
k8s-sit-node02 Ready <none> 6d19h v1.20.11使用同样的方式滚动更新其他 worker 节点,升级完后节点状态如下
1
2
3
4
5
6
7# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-sit-master01 Ready <none> 6d20h v1.21.14
k8s-sit-master02 Ready <none> 6d20h v1.21.14
k8s-sit-master03 Ready <none> 6d20h v1.21.14
k8s-sit-node01 Ready <none> 6d20h v1.21.14
k8s-sit-node02 Ready <none> 6d20h v1.21.14建议重启 calico 网络插件
1
2# kubectl rollout restart ds -n kube-system calico-node
daemonset.apps/calico-node restarted
升级 Calico 网络插件
官方文档: Upgrade Calico on Kubernetes
下载最新的 calico 资源清单文件,这里下载的是 v3.24.5
1
curl https://raw.githubusercontent.com/projectcalico/calico/v3.24.5/manifests/calico-etcd.yaml -O
参考部署 calico 文档修改文件
- 修改 calico-etcd 配置,添加 ETCD 节点信息以及证书
1
2
3
4
5
6
7
8
9sed -i 's#etcd_endpoints: "http://<ETCD_IP>:<ETCD_PORT>"#etcd_endpoints: "https://10.1.40.61:2379,https://10.1.40.62:2379,https://10.1.40.63:2379"#g' calico-etcd.yaml
ETCD_CA=`cat /usr/local/etcd/ssl/etcd-ca.pem | base64 | tr -d '\n'`
ETCD_CERT=`cat /usr/local/etcd/ssl/etcd.pem | base64 | tr -d '\n'`
ETCD_KEY=`cat /usr/local/etcd/ssl/etcd-key.pem | base64 | tr -d '\n'`
sed -i "s@# etcd-key: null@etcd-key: ${ETCD_KEY}@g; s@# etcd-cert: null@etcd-cert: ${ETCD_CERT}@g; s@# etcd-ca: null@etcd-ca: ${ETCD_CA}@g" calico-etcd.yaml
sed -i 's#etcd_ca: ""#etcd_ca: "/calico-secrets/etcd-ca"#g; s#etcd_cert: ""#etcd_cert: "/calico-secrets/etcd-cert"#g; s#etcd_key: "" #etcd_key: "/calico-secrets/etcd-key" #g' calico-etcd.yaml- 修改 calico 中 CIDR 的网段为 Pods 网段,即 172.16.0.0/16
1
sed -i "s@# - name: CALICO_IPV4POOL_CIDR@- name: CALICO_IPV4POOL_CIDR@g; s@# value: \"192.168.0.0/16\"@ value: \"172.16.0.0/16\"@g" calico-etcd.yaml
- 添加节点亲和性,使 calico 不调度到边缘节点上(可选,如果不是边缘集群可以忽略这一步)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28...
template:
metadata:
labels:
k8s-app: calico-node
spec:
nodeSelector:
kubernetes.io/os: linux
hostNetwork: true
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-role.kubernetes.io/edge
operator: DoesNotExist
- key: node-role.kubernetes.io/agent
operator: DoesNotExist
tolerations:
# Make sure calico-node gets scheduled on all nodes.
- effect: NoSchedule
operator: Exists
# Mark the pod as a critical add-on for rescheduling.
- key: CriticalAddonsOnly
operator: Exists
- effect: NoExecute
operator: Exists
...将 DaemonSet 副本控制器的升级策略改为 OnDelete
1
2
3
4
5
6
7
8
9
10
11
12...
spec:
selector:
matchLabels:
k8s-app: calico-node
updateStrategy:
type: OnDelete
template:
metadata:
labels:
k8s-app: calico-node
...执行以下命令创建资源
1
kubectl apply -f calico-etcd.yaml
手动删除 calico-node 节点上的 Pod,触发服务更新
1
kubectl delete pods -n kube-system calico-node-xxx
查看新的 pods 的镜像版本
1
2
3
4
5
6
7
8
9# kubectl get pods -n kube-system calico-node-q5clq -oyaml |grep image:
image: docker.io/calico/node:v3.24.5
image: docker.io/calico/cni:v3.24.5
image: docker.io/calico/node:v3.24.5
- image: calico/pod2daemon-flexvol:v3.15.5
- image: docker.io/calico/node:v3.24.5
- image: docker.io/calico/cni:v3.24.5
- image: docker.io/calico/node:v3.24.5
- image: calico/pod2daemon-flexvol:v3.15.5
