从 1.35.8 到 1.36.4 — 同一节点,新版本
目标
用 kubespray v2.32.0 搭建 Kubernetes 1.35.8 集群并部署工作负载,然后把 inventory 中的版本改为 1.36.4,
用 upgrade-cluster.yml 向上升一格。把升级前后拍成对照照片,用证据说明哪些变了、哪些保持不变。
为什么重要
Kubernetes 大约每四个月发布一个次版本,过了支持期就不再提供安全补丁。所以升级不是做一次就完的事,而是定期工作。 kubespray 把升级与安装一样,当作声明来处理——修改 inventory 中的版本,然后运行 playbook。不过有顺序:不跳过次版本, 不跳过 kubespray 标签,对每个节点执行 cordon → drain → 升级 → uncordon。如果只有一个节点,drain 期间工作负载会停止,你也会在本实验中亲眼看到。 安装和升级加起来要等待约 13 分钟。如果时间不够,请延长会话。
步骤
- 在
/opt/ks/kubespray中运行ansible-playbook -i /root/ks/inventory/lab/inventory.ini cluster.yml,把完整输出保存到/root/ks/logs/cluster-1.log(约 7 分钟)。inventory 的 kube_version 是 1.35.8。结束后,API 服务器的版本必须是 v1.35.8。 - 在 default 命名空间中创建 Deployment
web(镜像registry.k8s.io/e2e-test-images/agnhost:2.59,参数netexec --http-port=8080,副本数 2),使两个 Pod 都变为 Ready。然后在/root/ks/upgrade/before.json中写入server_version、kubelet_version、etcd_version(etcd --version的版本)、coredns_image(coredns Deployment 的镜像)、node_uid、web_pod_uids(web Pod 的 UID 排序后的数组)。 - 把
/root/ks/inventory/lab/group_vars/k8s_cluster/k8s-cluster.yml中的kube_version改为 1.36.4。不要用-e传入,而是修改文件。ansible-inventory --host node1必须返回 1.36.4。 - 在
/opt/ks/kubespray中运行ansible-playbook -i /root/ks/inventory/lab/inventory.ini upgrade-cluster.yml,把完整输出保存到/root/ks/logs/upgrade.log(约 6 分钟)。PLAY RECAP 必须是failed=0,API 服务器和 kubelet 都必须是 v1.36.4,/etc/kubernetes/kubeadm-config.yaml中的 kubernetesVersion 也必须是 v1.36.4。 - 用与第 2 步相同的字段写入
/root/ks/upgrade/after.json。然后在/root/ks/upgrade/diff.json中以布尔值写入same_node(节点 UID 是否保持不变)、web_pods_recreated(web Pod 的 UID 是否全部改变了)、etcd_changed(etcd 版本是否改变了)、coredns_changed(coredns 镜像是否改变了)。 - 在
/root/ks/logs/upgrade.log中找出 upgrade/pre-upgrade 和 post-upgrade role 的任务,在/root/ks/upgrade/drain.json中写入cordon_changed、drain_changed、uncordon_changed(分别是 “Cordon node”、“Drain node”、“Uncordon node” 任务是否产生了 changed,布尔值)、drain_sec(“Drain node” 任务所用的秒数,TASKS RECAP 中的值四舍五入后的整数,不在列表中则为 0)、node_schedulable_now(当前节点的 spec.unschedulable 是否不为真,布尔值)。 - 在
/root/ks/upgrade/next.json中写入running(当前 API 服务器的版本)、max_supported(这个 kubespray 版本能够安装的最高 Kubernetes 版本,校验和列表的第一个键)、needs_new_kubespray(要升级到下一个次版本,是否必须先把 kubespray 升级到下一个标签,布尔值)。
参考
- kubespray v2.32.0 位于
/opt/ks/kubespray,inventory 位于/root/ks/inventory/lab/inventory.ini(kube_version 1.35.8),均已准备好。 - 常见错误:只用
-e kube_version=1.36.4升级而保持 inventory 不变。下一个人会用写着旧版本的 inventory 来运行 cluster.yml。 - 常见错误:升级中途失败之后,没有发现节点仍处于 cordon 状态。请确认
kubectl get node中的 SchedulingDisabled。 - 文档:Kubespray — Upgrading Kubernetes · Kubernetes — Version Skew Policy · Kubernetes — Upgrading kubeadm clusters
搭建低一格的版本(1.35.8)
在 /opt/ks/kubespray 中运行 ansible-playbook -i /root/ks/inventory/lab/inventory.ini cluster.yml,把完整输出保存到 /root/ks/logs/cluster-1.log(约 7 分钟)。inventory 的 kube_version 是 1.35.8。结束后,API 服务器的版本必须是 v1.35.8。
要练习升级,必须先有低一格的版本。这个 kubespray 版本的默认值是 1.36.4,所以如果不在 inventory 中写下 1.35.8,一开始就会安装 1.36.4。
升级之前的对照照片
在 default 命名空间中创建 Deployment web(镜像 registry.k8s.io/e2e-test-images/agnhost:2.59,参数 netexec --http-port=8080,副本数 2),使两个 Pod 都变为 Ready。然后在 /root/ks/upgrade/before.json 中写入 server_version、kubelet_version、etcd_version(etcd --version 的版本)、coredns_image(coredns Deployment 的镜像)、node_uid、web_pod_uids(web Pod 的 UID 排序后的数组)。
要说明升级之后哪些变了、哪些保持不变,必须先留下升级之前的值。etcd 不是 Pod,而是主机服务,所以不用 kubectl,而是用二进制文件来询问版本。评分器会通过版本号来核对这份记录是否写在升级之前。
版本要在 inventory 中升级
把 /root/ks/inventory/lab/group_vars/k8s_cluster/k8s-cluster.yml 中的 kube_version 改为 1.36.4。不要用 -e 传入,而是修改文件。ansible-inventory --host node1 必须返回 1.36.4。
kubespray 升级文档要求,如果在 inventory 中写了版本,就在运行 upgrade-cluster.yml 之前修改这个值。如果只用 -e 升级,inventory 中仍然保留旧版本,下次有人用这个 inventory 运行 cluster.yml 时,就会从集群与 inventory 不一致的状态开始。
upgrade-cluster.yml
在 /opt/ks/kubespray 中运行 ansible-playbook -i /root/ks/inventory/lab/inventory.ini upgrade-cluster.yml,把完整输出保存到 /root/ks/logs/upgrade.log(约 6 分钟)。PLAY RECAP 必须是 failed=0,API 服务器和 kubelet 都必须是 v1.36.4,/etc/kubernetes/kubeadm-config.yaml 中的 kubernetesVersion 也必须是 v1.36.4。
upgrade-cluster.yml 是只用于已经存在的集群的 playbook,对每个节点执行 cordon → drain → 升级 → uncordon。如果只有一个节点,在 drain 期间 Pod 无处可去,会暂时处于 Pending——这意味着单节点集群的升级就是停机时间。等待期间,请跟着日志中的 PLAY 标题看一看。
升级之后的对照照片
用与第 2 步相同的字段写入 /root/ks/upgrade/after.json。然后在 /root/ks/upgrade/diff.json 中以布尔值写入 same_node(节点 UID 是否保持不变)、web_pods_recreated(web Pod 的 UID 是否全部改变了)、etcd_changed(etcd 版本是否改变了)、coredns_changed(coredns 镜像是否改变了)。
把 Kubernetes 向上升一格,并不意味着所有组件都会跟着升级。kubespray 按 Kubernetes 次版本对应的表(etcd_supported_versions、coredns_supported_versions)来选择 etcd 和 CoreDNS 的版本。如果两个版本在表中指向同一个值,就保持不变。
通过日志读取 drain
在 /root/ks/logs/upgrade.log 中找出 upgrade/pre-upgrade 和 post-upgrade role 的任务,在 /root/ks/upgrade/drain.json 中写入 cordon_changed、drain_changed、uncordon_changed(分别是 “Cordon node”、“Drain node”、“Uncordon node” 任务是否产生了 changed,布尔值)、drain_sec(“Drain node” 任务所用的秒数,TASKS RECAP 中的值四舍五入后的整数,不在列表中则为 0)、node_schedulable_now(当前节点的 spec.unschedulable 是否不为真,布尔值)。
profile_tasks 的 TASKS RECAP 列表中只会出现耗时较长的任务。如果 drain 不在列表中,就说明它很快就结束了。升级中途失败时,节点可能保持 cordon 状态,所以需要养成在结束之后确认 unschedulable 的习惯。
下一格从哪里来
在 /root/ks/upgrade/next.json 中写入 running(当前 API 服务器的版本)、max_supported(这个 kubespray 版本能够安装的最高 Kubernetes 版本,校验和列表的第一个键)、needs_new_kubespray(要升级到下一个次版本,是否必须先把 kubespray 升级到下一个标签,布尔值)。
kubespray 在每个标签中用校验和固定其所接受的版本。如果当前版本已经位于列表的最顶端,就无法再用这个 kubespray 继续升级,必须按照文档“多次升级”一节,把 kubespray 标签一格一格地升级,然后运行 upgrade-cluster.yml。不支持跳过标签。