基于Kubeadm与Ansible的Kubernetes集群自动化部署实战
1. 项目概述一个基于 Kubeadm 和 Ansible 的“开箱即用”Kubernetes 集群部署方案如果你正在寻找一种方法能够快速、可靠地在自己的物理机、虚拟机甚至云主机上部署一个功能完整的生产级 Kubernetes 集群并且厌倦了手动执行kubeadm init后还要去折腾网络插件、Ingress、监控、存储等一系列“周边”组件那么这个名为kubeadm-playbook的 Ansible 项目很可能就是你需要的“瑞士军刀”。我接触 Kubernetes 运维多年从早期的手动二进制部署到各种自动化方案都尝试过深知在“裸金属”或自有基础设施上搭建一个“五脏俱全”的 K8s 平台有多繁琐。这个项目的核心价值在于它没有重新发明轮子而是巧妙地扮演了一个“最佳实践集成者”的角色将官方工具、社区图表和经过验证的配置粘合在一起形成了一套标准化的、可重复的部署流程。简单来说kubeadm-playbook是一个 Ansible 剧本集合它的目标非常明确从一台刚装好 Linux 的裸机开始通过一条命令得到一个包含了网络、Ingress、Dashboard、监控可选、持久化存储可选等核心组件的、立即可用的 Kubernetes 集群。它严格遵循 KISSKeep It Simple, Stupid原则所有 Kubernetes 核心服务的安装都通过唯一的官方工具kubeadm完成确保了与社区发展同步也最大程度地减少了项目的维护负担。正如其作者所言kubeadm越强大这个项目本身就会越轻量。1.1 核心需求解析为什么我们需要这样的项目在 Minikube 或 Kind 之外搭建一个自管理的、功能完备的 Kubernetes 集群长期以来对许多团队来说都是一个挑战。虽然kubeadm极大地简化了 K8s 核心的安装但它只是一个起点。一个生产可用的平台还需要容器网络接口CNI如 Calico、Flannel 或 Weave Net这是 Pod 间通信的基础。Ingress 控制器如 Nginx Ingress Controller这是外部流量进入集群内部服务的标准入口。可视化仪表盘如 Kubernetes Dashboard提供集群资源的图形化视图。指标收集与监控如 Metrics Server用于 HPA和 PrometheusGrafana 栈。持久化存储如 vSphere、Ceph通过 Rook或 NFS 的 StorageClass这是有状态应用的基础。企业级特性如通过 HTTP 代理访问外网、使用内部私有镜像仓库等。手动部署上述每一个组件都涉及大量的 YAML 文件、Helm 命令和配置调优容易出错且难以版本化管理。kubeadm-playbook的出现正是为了解决这个“最后一公里”的问题。它将所有这些步骤编码成 Ansible 任务通过变量文件进行集中配置使得集群的部署和重建变得像运行一个脚本一样简单。特别值得一提的是它对“混合环境”的支持非常友好无论是 Ubuntu/Debian 还是 CentOS/RHEL 系列无论是单节点开发环境还是多主高可用生产集群都能通过同一套代码和不同的库存文件来适配。1.2 项目定位与核心理念这个项目将自己定位为一个“Kubernetes 集群平台”安装器而不仅仅是“Kubernetes”安装器。其核心理念可以概括为以下几点纯粹性坚决以kubeadm为唯一的核心安装工具避免引入非官方的、复杂的安装流程确保与上游 Kubernetes 的兼容性和可维护性。完整性不仅安装 K8s 核心还通过 Helm 一键部署一系列经过挑选的、常用的“平台级”插件形成一个立即可用的基础平台。最佳实践导向在架构上引导用户采用良好的实践例如在资源允许的情况下将节点区分为控制平面节点、基础设施节点运行 Ingress、监控等和计算节点实现资源隔离和更清晰的管理。企业就绪原生支持 HTTP 代理和私有 Docker 镜像仓库这是许多企业内部网络环境的刚需。灵活性与可扩展性通过 Ansible 标签系统可以灵活地执行部分任务如仅添加节点、仅重置集群、仅安装插件并且所有 Helm 图表都可以通过配置文件轻松地启用、禁用或定制。2. 架构设计与核心组件选型解析理解一个自动化工具的架构是有效使用它的前提。kubeadm-playbook的架构设计清晰地反映了其“集成而非创造”的哲学整个流程可以被看作一个精心编排的管道每个阶段都有明确的输入、处理和输出。2.1 整体工作流程与阶段划分项目的核心入口是site.yml这个主剧本。一次完整的集群部署或重置其逻辑流程大致如下重置与清理阶段--tags reset这是可选的但在重新安装集群时至关重要。它会安全地清理现有环境包括卸载所有已部署的 Helm 图表、排空并移除节点、清理持久卷、执行kubeadm reset、删除相关的网络接口和挂载点。这个阶段确保了安装起点的一致性避免了旧配置的残留影响。通用准备阶段role: common在所有目标机器上执行基础环境准备。这是项目“贴心”的体现它不止于 K8s还向下管理了容器运行时环境。内核参数调优自动设置net.bridge.bridge-nf-call-iptables1等 Kubernetes 要求的核心参数并确保它们持久化。容器运行时安装与配置如果docker_setup变量启用它会自动安装 Docker 并配置为使用overlay2存储驱动对 CentOS 7.4 和 Ubuntu 均有效。它也支持containerd的配置。时间同步安装并配置 NTP/Chrony确保集群所有节点时间一致这是分布式系统稳定运行的基础。软件源配置添加 Kubernetes 官方或镜像的 YUM/APT 仓库。Kubernetes 核心安装阶段这是kubeadm发挥作用的阶段。主节点初始化role: master在第一台主节点上执行kubeadm init并生成加入集群所需的令牌和命令。剧本会处理所有必要的参数如 Pod 网段、服务网段、API Server 证书 SAN 等。节点加入role: node在工作节点上执行kubeadm join将它们纳入集群。高可用主节点可选对于多主架构项目支持两种方式基于keepalived的虚拟 IPVIP和外部硬件负载均衡器。对于 K8s 1.14它直接利用kubeadm内置的 HA 支持对于更早的版本它集成了社区方案来实现高可用。集群网络与插件部署阶段role: post_deploy核心 K8s 启动后立即部署使集群“可用”的组件。CNI 网络插件根据配置安装 Flannel、Calico 或 Weave Net 等解决 Pod 网络问题。Helm 安装部署 Helm CLI 及其服务端组件 Tillerv2版本或直接配置 Helm v3。核心插件 via Helm这是项目的亮点。它通过 Helm 图表从官方仓库直接安装一系列插件包括Nginx Ingress Controller作为集群的流量入口。Kubernetes Dashboard提供 Web 管理界面。Metrics Server为 Horizontal Pod Autoscaler (HPA) 提供资源指标。用户自定义图表通过addons.yml配置文件可以声明式地添加任意其他 Helm 图表。持久化存储集成阶段可选根据配置自动化部署存储解决方案。vSphere Cloud Provider如果提供了 vCenter 的认证信息会自动创建对应的 StorageClass实现动态卷供应。Rook/Ceph部署 Rook Operator在集群内创建和管理 Ceph 存储集群。NFS创建基于 NFS 的 StorageClass需手动准备 NFS 服务器。健康检查与信息输出阶段--tags cluster_sanity最后剧本会检查所有节点是否就绪所有核心 Pod 是否运行正常并打印出集群的访问信息例如 Dashboard 的访问地址和 Token。2.2 关键组件选型背后的思考项目在每一个组件上的选择都体现了实用主义和社区主流导向。为什么坚持使用 Kubeadmkubeadm是 Kubernetes SIG Cluster Lifecycle 维护的官方集群引导工具。选择它意味着官方背书与同步更新每个 K8s 版本发布时kubeadm都会同步更新确保安装方法是最新且受支持的。自托管Self-hosted从 1.8 版本左右开始kubeadm默认将控制平面组件如 kube-apiserver、kube-controller-manager以静态 Pod 的形式运行这使得控制平面本身也受 Kubernetes 管理升级和恢复更为优雅。简洁透明kubeadm的职责清晰——引导集群。它不管理节点生命周期、不提供云提供商集成这使得它比 Kops、Kubespray 等全生命周期管理工具更轻量也更符合本项目“做胶水”的定位。为什么用 Helm 管理插件早期 Kubernetes 插件的安装依赖大量零散的 YAML 文件管理和升级极其困难。Helm 作为“Kubernetes 的包管理器”完美地解决了这个问题。标准化与复用每个 Helm 图表Chart都是一个预配置的应用程序包包含了所有依赖资源定义。参数化配置通过values.yaml文件可以轻松定制插件的配置而无需修改原始模板。kubeadm-playbook将各个插件的配置集中在了group_vars/all/addons.yaml中管理起来一目了然。生命周期管理Helm 提供了安装、升级、回滚和卸载的全套命令大大简化了插件的运维。网络与存储方案的选择项目没有绑定某一种特定的 CNI 或存储方案而是提供了选项。默认可能配置了 Flannel因为简单稳定但你可以轻松切换到 Calico提供网络策略或 Weave。存储方面它重点支持了企业环境中常见的 vSphere 和开源的 Rook/Ceph体现了其“企业友好”和“生产就绪”的设计目标。注意项目明确表示不处理 Kubernetes 版本升级。这是因为kubeadm upgrade命令本身已经足够清晰和简单例如kubeadm upgrade plan和kubeadm upgrade apply围绕它做自动化封装带来的收益有限且可能引入风险。升级操作建议参照官方文档手动进行。3. 实战部署从零开始构建一个高可用 Kubernetes 集群理论说得再多不如亲手操作一遍。下面我将以一个典型的场景为例在 3 台 CentOS 7.9 虚拟机上部署一个高可用多主的 Kubernetes 1.26 集群并集成 Nginx Ingress、Dashboard 和 Rook/Ceph 存储。3.1 环境准备与规划硬件/虚拟机规划节点1 (master-01): 2 CPU, 4GB RAM, 50GB Disk, IP: 192.168.1.101节点2 (master-02): 2 CPU, 4GB RAM, 50GB Disk, IP: 192.168.1.102节点3 (worker-01): 4 CPU, 8GB RAM, 100GB Disk, IP: 192.168.1.103负载均衡器/VIP: 192.168.1.100 (我们将使用keepalived实现 VIP)Ansible 控制机: 可以是你本地电脑也可以是其中一台虚拟机需能 SSH 到所有节点。软件前提所有节点安装 CentOS 7.9 Minimal。配置主机名和/etc/hosts解析或使用 DNS。所有节点间 SSH 免密登录Ansible 所需。Ansible 控制机上安装 Ansible 2.9。集群规划Pod 网络 CIDR:10.244.0.0/16(Flannel 默认)Service 网络 CIDR:10.96.0.0/12集群域名:k8s.example.comIngress 域名通配符:*.apps.k8s.example.com- 指向 VIP192.168.1.1003.2 配置详解与实操步骤第一步获取项目并配置清单# 在 Ansible 控制机操作 git clone https://github.com/ReSearchITEng/kubeadm-playbook.git cd kubeadm-playbook cp hosts.example hosts编辑hosts文件这是 Ansible 的库存文件定义了集群结构。[primary-master] master-01 ansible_host192.168.1.101 ansible_userroot [secondary-masters] master-02 ansible_host192.168.1.102 ansible_userroot [nodes] worker-01 ansible_host192.168.1.103 ansible_userroot # 定义 k8s-cluster 组包含所有节点 [k8s-cluster:children] primary-master secondary-masters nodes # 定义 etcd 集群高可用时需要通常与主节点重叠 [etcd:children] primary-master secondary-masters这里的关键是primary-master组它是执行kubeadm init的初始主节点。secondary-masters是后续加入的高可用主节点。第二步定制化变量配置这是项目的核心配置所在所有魔法都藏在group_vars/all/目录下。我们需要修改几个关键文件。group_vars/all/main.yaml(或创建temp.yaml覆盖):# 基础配置 KUBERNETES_VERSION: 1.26.0 CORP_DNS_DOMAIN: example.com CLUSTER_DNS_DOMAIN: k8s.example.com # 网络配置 POD_NETWORK_CIDR: 10.244.0.0/16 SERVICE_CIDR: 10.96.0.0/12 # 高可用配置 - 使用 keepalived VIP MASTER_HA_ENABLED: true MASTER_HA_VIP: 192.168.1.100 MASTER_HA_VIP_INTERFACE: eth0 # 请根据实际情况修改网卡名 MASTER_HA_METHOD: vip # 可选 vip 或 loadbalancer # 容器运行时 - 让 playbook 自动安装 Docker docker_setup: true CONTAINER_RUNTIME: docker # 内核模块 kernel_modules_setup: true # 其他 ntp_enabled: truegroup_vars/all/addons.yaml:# 启用核心插件 install_helm: true install_ingress: true install_dashboard: true install_metrics_server: true # Ingress 配置 - 使用通配符域名 ingress_controller: enabled: true type: nginx helm_release_name: nginx-ingress helm_chart_repo: https://kubernetes.github.io/ingress-nginx helm_chart_name: ingress-nginx helm_chart_version: 4.5.2 values: controller: service: type: NodePort # 或 LoadBalancer 如果云环境支持 nodePorts: http: 30080 https: 30443 hostNetwork: false publishService: enabled: true extraArgs: default-ssl-certificate: default/example-com-tls # 可选配置默认证书 tcp: {} udp: {} # Dashboard 配置 dashboard: enabled: true helm_release_name: kubernetes-dashboard helm_chart_repo: https://kubernetes.github.io/dashboard/ helm_chart_name: kubernetes-dashboard helm_chart_version: 6.0.0 values: protocolHttp: true service: type: NodePort nodePort: 30444 ingress: enabled: true hosts: - dashboard.apps.k8s.example.com annotations: nginx.ingress.kubernetes.io/ssl-redirect: false tls: [] # 启用 Rook/Ceph 存储 rook_ceph_enabled: true # 注意需要在节点上准备未使用的磁盘或目录例如 /storage/rookgroup_vars/all/network.yaml:# 选择 CNI 网络插件 NETWORK_TYPE: flannel # 可选 flannel, calico, weave # Flannel 配置 flannel: version: v0.22.0 # 如果使用非默认的 Pod 网段需要配置 Flannel 的 backend 类型和网络 # backend: vxlan # network: {{ POD_NETWORK_CIDR }}第三步执行部署在运行前建议先进行 Ansible 的连通性测试和语法检查ansible -i hosts all -m ping ansible-playbook -i hosts site.yml --syntax-check如果一切正常开始完整的集群部署。这是一个耗时过程建议使用screen或tmux。ansible-playbook -i hosts site.yml这个命令会依次执行所有阶段重置如果之前有、准备系统、安装 Docker、安装 kubeadm、初始化主节点、加入其他节点、部署网络插件、安装 Helm 和所有配置的插件。第四步验证与访问部署完成后剧本会输出关键信息。你也可以手动检查# 在主节点上执行 kubectl get nodes -o wide kubectl get pods --all-namespaces访问 Dashboard获取访问令牌kubectl -n kubernetes-dashboard create token admin-user注意需要先创建具有适当权限的 ServiceAccount剧本可能已创建具体查看addons.yaml中 dashboard 的配置通过 Ingress 访问http://dashboard.apps.k8s.example.com(需配置 DNS 或本地 hosts 将域名指向 VIP192.168.1.100)或通过 NodePort 直接访问https://任一节点IP:304443.3 企业级特性配置代理与私有仓库在企业内网环境中直接访问互联网可能受限。kubeadm-playbook对此有很好的支持。配置 HTTP 代理在group_vars/all/main.yaml中设置http_proxy: http://proxy.corp.com:3128 https_proxy: http://proxy.corp.com:3128 no_proxy: localhost,127.0.0.1,.corp.example.com,10.0.0.0/8,192.168.0.0/16剧本会自动为 Docker、YUM/APT 和 kubelet 配置这些代理。配置私有 Docker 镜像仓库许多企业会搭建 Nexus、Harbor 等私有仓库并代理 Docker Hub、Quay.io 等公共仓库。# 在 group_vars/all/main.yaml 中 use_private_registry: true private_registry_url: registry.corp.example.com:5000 # 可选为特定仓库配置镜像前缀映射 private_registry_mirrors: - prefix: docker.io mirror: registry.corp.example.com:5000/dockerhub - prefix: quay.io mirror: registry.corp.example.com:5000/quay - prefix: registry.k8s.io mirror: registry.corp.example.com:5000/k8s剧本会相应配置 Docker 的registry-mirrors和insecure-registries如果使用 HTTP并在拉取镜像时使用私有仓库地址。实操心得在配置私有仓库时务必确保所有需要的镜像包括 kube-apiserver、pause、CNI 插件等都已经同步或可以拉取到私有仓库中。kubeadm在init和join时会预拉取镜像如果失败会导致集群安装卡住。可以提前在节点上手动执行kubeadm config images pull --image-repositoryregistry.corp.example.com:5000/k8s进行测试。4. 运维操作、问题排查与深度技巧部署只是开始日常运维和故障排查才是重头戏。kubeadm-playbook通过 Ansible 标签系统提供了强大的针对性操作能力。4.1 常用运维操作指南1. 仅添加新的工作节点这是最常见的扩容操作。假设你要新增worker-02(192.168.1.104)。编辑hosts文件在[nodes]组下添加新节点并确保[primary-master]和[secondary-masters]组保持不变或为空如果不想操作它们。运行ansible-playbook -i hosts only_nodes_only_install.yml --tags node这个命令只会对新节点执行安装步骤不会影响现有集群。2. 安全移除一个节点如果需要下线worker-01。编辑hosts文件只保留[primary-master]和要移除的节点worker-01。运行ansible-playbook -i hosts site.yml --tags node_reset这个标签下的任务会先执行kubectl drain排空节点上的 Pod然后执行kubectl delete node和kubeadm reset最后清理节点。3. 仅更新或重新部署插件如果你修改了addons.yaml中的配置想更新 Ingress Controller。确保hosts文件包含所有主节点因为 Helm 通常运行在主节点上。运行ansible-playbook -i hosts site.yml --tags post_deploy这会运行所有post_deploy阶段的任务包括 Helm 的更新。更精细的控制可以通过 Helm 本身的命令进行。4. 执行集群健康检查ansible-playbook -i hosts site.yml --tags cluster_sanity这个任务不会做任何修改只会检查节点状态、核心 Pod 状态并打印出集群的访问信息非常适合用于监控或安装后的验证。4.2 常见问题排查实录即使有自动化工具在复杂的系统环境中问题依然可能出现。以下是我在多次使用中遇到的一些典型问题及解决方法。问题一kubeadm init失败提示cgroup driver不一致。现象在kubeadm init阶段日志显示 kubelet 无法启动错误信息提到detected “cgroupfs” as the Docker cgroup driver, but “systemd” is the cgroup driver。根因Docker 默认使用cgroupfs作为 Cgroup 驱动而kubeadm在较新版本中默认期望systemd。解决这正是kubeadm-playbook的common角色要解决的问题之一。它会在安装 Docker 后自动配置/etc/docker/daemon.json将 Cgroup 驱动改为systemd并重启 Docker。如果问题仍出现检查group_vars/all/main.yaml中docker_setup: true是否启用并手动验证节点上的/etc/docker/daemon.json文件内容。问题二Pod 网络插件如 Flannel安装后节点仍处于NotReady状态。现象kubectl get nodes显示节点状态为NotReadykubectl describe node node-name显示网络插件相关的错误。排查步骤检查 Pod 状态kubectl get pods -n kube-system | grep flannel(或 calico/weave)。查看 Pod 是否处于Running状态。查看 Pod 日志kubectl logs -n kube-system flannel-pod-name。常见原因网卡选择错误Flannel 默认选择第一块网卡eth0。如果节点有多块网卡或者网卡名不是eth0例如 Cloud-init 后的ens192Flannel 会绑定到错误的接口。需要在group_vars/all/network.yaml中为 Flannel 指定网卡flannel: values: |- { daemonSet: { podAnnotations: { flannel.alpha.coreos.com/public-ip: {{ ansible_default_ipv4.address }} } }, args: [--iface{{ ansible_default_ipv4.alias }}] }Pod 网段冲突POD_NETWORK_CIDR如10.244.0.0/16必须与现有物理网络不重叠。防火墙/安全组确保节点间 UDP 8472 端口Flannel VXLAN或相应的 Calico/Weave 端口是开放的。问题三Helm 安装插件失败提示Error: failed to download或connection refused。现象在post_deploy阶段任务卡在 Helm repo add 或 helm install。排查网络连通性在 Ansible 控制机上尝试curl -v https://kubernetes.github.io/ingress-nginx。如果企业有代理确保group_vars/all/main.yaml中的http_proxy配置正确并且 Ansible 控制机本身也配置了代理环境变量export http_proxy...。Helm 版本兼容性项目可能默认使用 Helm v2需要 Tiller但新版本图表可能要求 Helm v3。检查group_vars/all/addons.yaml中install_helm相关的版本配置。目前社区已全面转向 Helm v3建议在配置中明确使用 Helm v3。私有仓库认证如果使用的是内部 Helm 仓库需要确保已通过helm repo add --username ... --password ...正确添加这部分可能需要扩展 playbook 或手动执行。问题四使用 VIP 的高可用集群kubeadm join其他主节点失败。现象第一个主节点初始化成功但第二个主节点加入时kubeadm join命令报错无法连接到 API Server。排查检查 VIP 连通性在第二个主节点上ping 192.168.1.100(VIP) 和curl -k https://192.168.1.100:6443。必须能通。检查keepalived状态在第一个主节点上systemctl status keepalived和ip addr show查看 VIP 是否绑定在正确的网卡上。确保keepalived配置正确并且虚拟路由器 ID (virtual_router_id) 在同一个子网内是唯一的。检查kubeadm init配置第一个主节点初始化时--control-plane-endpoint参数必须设置为 VIP 地址和端口如192.168.1.100:6443。检查group_vars/all/main.yaml中MASTER_HA_VIP的配置是否正确传递给了kubeadm。证书 SAN确保 API Server 的证书包含了 VIP 地址。kubeadm-playbook应该会自动处理这一点但可以检查/etc/kubernetes/pki/apiserver.crt的 Subject Alternative Names 字段。4.3 高级技巧与最佳实践利用 Ansible Tags 进行金丝雀部署当你要对生产集群进行变更时比如升级某个插件可以先在一个非关键节点或单独的测试集群上使用相同的 playbook 和 tags 进行演练。例如ansible-playbook -i hosts_test site.yml --tags post_deploy --limit test-node。将配置代码化并纳入版本控制group_vars/all/目录下的所有 YAML 文件就是你集群的“基础设施即代码”定义。务必将其放入 Git 仓库管理。每次变更都通过提交记录可以轻松回滚和审计。为不同环境创建不同的库存和变量文件你可以创建inventory/prod/、inventory/staging/目录里面分别放置hosts文件和group_vars/。通过-i inventory/prod/来指定环境。变量覆盖可以使用 Ansible 的-e extra_vars.yaml参数。处理节点污点和标签项目鼓励区分 master、infra、compute 节点。你可以在hosts文件中为不同组定义变量来自动为节点打上标签和污点。[infra] infra-01 ansible_host... [infra:vars] node_labels{node-role.kubernetes.io/infra: } node_taintsnode-role.kubernetes.io/infra:NoSchedule然后在部署 Ingress、Prometheus 等基础设施 Pod 时通过 Helm 的nodeSelector和tolerations配置将它们调度到infra节点上。持久化存储的预配置对于 Rook/Ceph剧本假设节点上有空闲磁盘或目录。在生产中更安全的做法是提前准备好裸设备如/dev/sdb或独立的存储节点。可以通过 Ansible 的parted、lvm模块在 playbook 中自动化准备或者单独编写预处理剧本。安全加固剧本安装的 Dashboard 默认可能配置了较宽松的权限。生产环境中务必通过addons.yaml严格限制 Dashboard 的 ServiceAccount 权限。启用并配置 Ingress 的 TLS 加密。考虑集成 OIDC/LDAP 等外部身份认证如项目路线图中提到的 KeyCloak而不是使用静态 Token。这个项目就像一个精心设计的乐高套装提供了所有标准的、高质量的零件kubeadm, Helm charts, 最佳实践配置和清晰的说明书Ansible playbooks。它没有试图封装一切而是把组合和定制的权力留给了你。通过深入理解其架构、熟练运用变量配置和标签系统你就能用它快速搭建出稳定、合规且易于维护的 Kubernetes 基础平台从而将更多精力投入到上层的应用开发和业务价值交付中。