参考文档: 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