如何通过Ansible更新运行中K8s集群的daemon.json并重启Docker且不中断集群
Kubernetes集群滚动更新Docker配置操作方案
你的思路是对的,要避免集群不可用必须走逐节点滚动操作的流程,配合Ansible的串行执行配置可以完全实现无感知变更,具体实现如下:
前置检查(操作前必须完成)
- 确认所有核心业务Pod配置了≥2的副本数,禁止单副本业务直接执行变更
- 提前配置对应业务的
PodDisruptionBudget,明确允许同时中断的Pod数量,避免驱逐过程中业务副本数低于最低可用标准 - 提前验证你要更新的
daemon.json配置合法性,本地先执行docker daemon --validate -c 待更新的daemon.json确认无语法错误 - 确认当前所有节点状态为
Ready,集群没有正在进行的升级、备份等其他变更任务
Ansible Playbook 实现
核心配置是加serial: 1,强制Ansible一次只操作一个节点,所有步骤在当前节点执行成功后才会处理下一个节点,参考Playbook如下:
--- - name: 滚动更新集群节点Docker配置并重启服务 hosts: k8s_nodes # 替换成你的节点inventory分组 serial: 1 # 核心配置:单次仅操作1个节点 gather_facts: yes tasks: # 第一步:标记节点为不可调度,避免新Pod调度上来 - name: Cordon当前节点 command: kubectl cordon {{ inventory_hostname }} delegate_to: "{{ groups['kube_control_plane'][0] }}" # 委派到第一个控制面节点执行kubectl命令,也可以根据你的权限配置调整 # 第二步:排空节点上的业务Pod - name: Drain当前节点,驱逐非DaemonSet的业务Pod command: kubectl drain {{ inventory_hostname }} --ignore-daemonsets --delete-emptydir-data --force --grace-period=30 delegate_to: "{{ groups['kube_control_plane'][0] }}" register: drain_result until: drain_result is succeeded retries: 5 delay: 10 # 第三步:更新daemon.json配置 - name: 更新/etc/docker/daemon.json配置 template: # 如果你用静态文件可以换成copy模块 src: templates/daemon.json.j2 # 替换成你的配置模板路径 dest: /etc/docker/daemon.json owner: root group: root mode: '0644' # 第四步:验证Docker配置合法性,配置错误直接终止流程 - name: 验证Docker配置合法性 command: docker daemon --validate -c /etc/docker/daemon.json register: docker_validate_result failed_when: docker_validate_result.rc != 0 # 第五步:重启Docker服务 - name: 重载systemd配置并重启Docker systemd: name: docker state: restarted daemon_reload: yes # 第六步:验证Docker和Kubelet状态正常 - name: 验证Docker服务运行正常 command: systemctl is-active docker register: docker_status failed_when: docker_status.stdout != 'active' - name: 验证Kubelet服务运行正常 command: systemctl is-active kubelet register: kubelet_status failed_when: kubelet_status.stdout != 'active' # 第七步:等待节点重新注册到集群,状态恢复为Ready - name: 等待节点状态恢复为Ready command: kubectl get node {{ inventory_hostname }} -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}' delegate_to: "{{ groups['kube_control_plane'][0] }}" register: node_ready_status until: node_ready_status.stdout == 'True' retries: 10 delay: 10 # 第八步:取消节点不可调度标记,恢复Pod调度 - name: Uncordon当前节点,恢复调度 command: kubectl uncordon {{ inventory_hostname }} delegate_to: "{{ groups['kube_control_plane'][0] }}" # 第九步:等待节点上Pod恢复正常后再处理下一个节点 - name: 等待节点上所有Pod状态正常 shell: kubectl get pods --all-namespaces --field-selector spec.nodeName={{ inventory_hostname }} | grep -v -E 'Running|Completed' | wc -l delegate_to: "{{ groups['kube_control_plane'][0] }}" register: pod_running_status until: pod_running_status.stdout == '0' retries: 10 delay: 10
注意事项
- 如果是操作控制面节点,需要保证操作前至少2个控制面节点处于健康状态,操作完成后额外验证etcd集群状态正常,避免etcd选主失败
- 操作过程中任意节点执行失败,Ansible会自动终止整个流程,排查完对应节点问题后再重新执行即可,不要强制跳过错误
- 如果集群节点跨可用区部署,可以调整
serial为每个可用区的节点数,按可用区批量操作,进一步降低故障风险
内容的提问来源于stack exchange,提问作者Josh Schubert
相关产品推荐
相关产品推荐

