使用 Kubespray 基于 Ansible 在生产环境裸机部署高可用 Kubernetes 集群实战
使用 Kubespray 基于 Ansible 在生产环境裸机部署高可用 Kubernetes 集群实战
Kubespray 是 Kubernetes 官方 incubator 时代的自动化部署项目,它基于 Ansible Playbook 把「系统初始化 + Kubernetes 集群搭建」的全部步骤固化为一套可重复执行的任务,目标是开箱即用地提供 Production Ready 的 Kubernetes 部署方案。本篇将完整还原仓库文档 setup/cluster/kubespray.md 记录的实战流程:从裸机节点规划、环境准备、inventory 编写到一键部署与集群验证,并在此基础上结合本仓库中网络插件、DNS、高可用等模块的源码与配置证据,帮助你掌握一套不依赖公有云、可自行组合网络方案的集群交付方法。
Kubespray 是什么:以 Ansible 为骨架的集群部署方案
Kubespray 的核心思路是:用 Ansible Playbook 定义系统配置与 Kubernetes 集群部署的全部任务,从而把「在 N 台机器上搭建一套生产级集群」从手工操作变成可声明、可重放、可审计的自动化过程。它具备以下几个典型特点(见 setup/cluster/kubespray.md):
- 多环境支持:可部署在 AWS、GCE、Azure、OpenStack 以及裸机上;
- 高可用:支持部署 High Available(HA)Kubernetes 集群,即多个 Master、etcd 集群模式与 kube-apiserver 负载均衡;
- 可组合性(Composable):可自行选择 Network Plugin(flannel、calico、canal、weave)来部署,网络方案与集群骨架解耦;
- 多发行版支持:支持 CoreOS、Debian Jessie、Ubuntu 16.04、CentOS/RHEL 7 等主流 Linux 发行版。
在本仓库的部署体系中,Kubespray 与 kubeadm 一样被官方文档推荐用于「物理机或虚拟机」场景,见 setup/cluster/README.md 中的部署选型说明;完整的部署方法索引可参考 setup/index.md。本篇以 Kubespray 部署至裸机节点为例,文档记录的安装版本如下:
| 组件 | 版本 |
|---|---|
| Kubernetes | v1.7.3 |
| Etcd | v3.2.4 |
| Flannel | v0.8.0 |
| Docker | v17.04.0-ce |
上述版本对应仓库文档编写时的实测组合。实际使用时,建议以 Kubespray 当时支持的版本矩阵为准,并参考 setup/index.md 的「版本依赖」一节核对各组件兼容关系。
节点规划与部署架构
本次安装测试环境的操作系统为 Ubuntu 16.04 Server,共 4 台裸机节点,规划如下:
| IP Address | Role | CPU | Memory |
|---|---|---|---|
| 192.168.121.179 | master1 + deploy | 2 | 4G |
| 192.168.121.106 | node1 | 2 | 4G |
| 192.168.121.197 | node2 | 2 | 4G |
| 192.168.121.123 | node3 | 2 | 4G |
其中 master 为主要控制节点(kube-master),node 为工作节点(kube-node)。注意:部署节点(本例即 master1)同时承担了 Kubespray 控制端的角色,它需要能免密 SSH 到所有其他节点执行 Ansible 任务。
从部署后的系统组件看,这套架构最终会形成如 practice/ha.md 与 setup/cluster/README.md 所描述的高可用控制面要素:etcd 集群、kube-apiserver 负载均衡,以及 kube-controller-manager / kube-scheduler 的选主机制。Kubespray 的 HA 价值正在于把这些要素通过 Playbook 自动落盘到各节点上。
部署前的环境准备
Kubespray 通过 Ansible 管理所有节点,因此对基础设施有明确的先决条件。按原文档整理如下:
- 所有节点的网络之间可以互相通信;
- 部署节点(master1)对其他节点无需 SSH 密码即可登录(Ansible 通过 SSH 执行任务);
- 所有节点都拥有免密的 sudoer 权限(Ansible 需要在远端提权安装软件);
- 所有节点需要安装 Python(Ansible 依赖远端 Python 解释器执行模块);
- 所有节点需要把
/etc/hosts解析到所有主机,保证节点间主机名互认; - 修改所有节点的
/etc/resolv.conf,写入可用的 DNS 服务器:
$ echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf
- 部署节点(master1)安装 Ansible >= 2.3.0。
Ubuntu 16.04 安装 Ansible 的具体步骤(包含换用台湾镜像源加速与依赖安装):
$ sudo sed -i 's/us.archive.ubuntu.com/tw.archive.ubuntu.com/g' /etc/apt/sources.list
$ sudo apt-get install -y software-properties-common
$ sudo apt-add-repository -y ppa:ansible/ansible
$ sudo apt-get update && sudo apt-get install -y ansible git cowsay python-pip python-netaddr libssl-dev
其中 python-netaddr 是 Ansible 计算网络地址(如网段划分、IP 规划)时的依赖,cowsay 用于 Ansible 输出美化,git 用于拉取 Kubespray 仓库。
安装 Kubespray CLI 并准备部署信息
Kubespray 官方曾计划提供 Go 语言重写的 CLI 工具,但长期未更新,因此原文档明确推荐使用 pypi 版本安装 kubespray-cli:
$ sudo pip install -U kubespray
安装完成后,新增配置文件 ~/.kubespray.yml,写入 Kubespray 仓库地址与日志级别:
$ cat <<EOF> ~/.kubespray.yml
kubespray_git_repo: "https://github.com/kubernetes-incubator/kubespray.git"
# Logging options
loglevel: "info"
EOF
接着用 kubespray CLI 自动生成 inventory 文件。prepare 子命令按角色列出主机,把 master、etcd、node 的角色归属一次性声明出来:
$ kubespray prepare --masters master1 --etcds master1 --nodes node1 node2 node3
这里 --masters master1 指定控制节点、--etcds master1 指定 etcd 所在节点、--nodes node1 node2 node3 指定工作节点。
编写 inventory:Kubespray 的主机组模型
inventory 是 Kubespray 部署的核心输入,它用 Ansible inventory 语法把节点划分到不同角色组。kubespray prepare 生成的初始文件位于 ~/.kubespray/inventory/inventory.cfg,需要按实际环境补齐各主机的连接信息与 IP:
$ vim ~/.kubespray/inventory/inventory.cfg
[all]
master1 ansible_host=192.168.121.179 ansible_user=root ip=192.168.121.179
node1 ansible_host=192.168.121.106 ansible_user=root ip=192.168.121.106
node2 ansible_host=192.168.121.197 ansible_user=root ip=192.168.121.197
node3 ansible_host=192.168.121.123 ansible_user=root ip=192.168.121.123
[kube-master]
master1
[kube-node]
node1
node2
node3
[etcd]
master1
[k8s-cluster:children]
kube-node
kube-master
各主机行中,ansible_host 是 Ansible 实际 SSH 连接的地址,ansible_user 是登录用户(本例为 root),ip 是节点自身的内网 IP,用于后续组件间通信地址计算。
各组的含义:
[all]:全部节点清单;[kube-master]:运行 kube-apiserver、kube-controller-manager、kube-scheduler 的控制节点;[kube-node]:运行 kubelet、kube-proxy 等工作负载的节点;[etcd]:运行 etcd 存储集群的节点;[k8s-cluster:children]:由kube-node与kube-master聚合而成的集群组,用于把 Playbook 同时应用到两类角色。
也可以跳过
prepare,直接手工新建inventory来描述部署节点,组结构保持与上例一致即可。
作为对照,仓库中 extension/network/kuryr.md 记录了同一 CLI 在 CentOS 7.x + Calico 场景下的用法(kubespray prepare --masters master --etcds master --nodes node1 与 kubespray deploy --verbose -u root -k .ssh/id_rsa -n calico),其 inventory 中把 master 同时列入 [kube-master] 与 [kube-node],说明允许单节点兼任两种角色;这与原文档把 master 单独列为 SchedulingDisabled 控制节点的做法是两种不同的拓扑策略。
执行部署:一条命令拉起整个集群
inventory 就绪后,即可在部署节点上发起部署。原文档使用以下命令:
$ time kubespray deploy --verbose -u root -k .ssh/id_rsa -n flannel
Run kubernetes cluster deployment with the above command ? [Y/n]y
...
master1 : ok=368 changed=89 unreachable=0 failed=0
node1 : ok=305 changed=73 unreachable=0 failed=0
node2 : ok=276 changed=62 unreachable=0 failed=0
node3 : ok=276 changed=62 unreachable=0 failed=0
Kubernetes deployed successfully
命令参数说明:
--verbose:输出 Ansible 的详细执行日志,便于排错;-u root:SSH 登录远端节点的用户;-k .ssh/id_rsa:指定免密登录使用的私钥路径;-n flannel:选择网络插件,目前支持calico、flannel、weave与canal。
Ansible 完成后的统计行是判断部署结果的关键:ok 表示执行成功且无需变更的任务数、changed 表示发生变更的任务数、unreachable 表示无法连接的节点数、failed 表示失败的任务数。当所有节点 unreachable=0 failed=0 时,说明全部 Playbook 任务执行成功,末尾输出 Kubernetes deployed successfully 即部署完成。
网络插件选型:flannel / calico / canal / weave
-n 参数决定了集群的 Pod 网络方案,这是 Kubespray「可组合性」的体现。四种方案在本仓库中均有对应文档,可据此选型:
- flannel:通过给每台宿主机分配子网提供容器虚拟网络,基于 Linux TUN/TAP 以 UDP 封装 IP 包创建 overlay 网络,并借助 etcd 维护子网分配;支持
udp、vxlan、host-gw、aws-vpc、gce、ali-vpc等多种 Backend,其中host-gw直连路由方式仅适用于二层直接可达的网络(见 extension/network/flannel.md)。文档实测版本为 Flannel v0.8.0,其优点是配置安装简单,缺点是 VXLAN 模式对 zero-downtime restarts 支持不好; - calico:纯三层数据中心网络方案(无需 Overlay),每个计算节点利用 Linux Kernel 实现高效的 vRouter,通过 BGP 协议传播 workload 路由,小规模直连、大规模用 BGP Route Reflector;同时基于 iptables 提供多租户隔离与安全组等网络策略(见 extension/network/calico.md)。注意其控制平面设计要求物理网络为 L2 Fabric,且不支持 VRF 与多租户隔离;
- canal:flannel 与 calico 的组合方案,用 flannel 提供 overlay 数据面、用 calico 提供网络策略(仓库中 network/canal/index.md 仅有索引占位,具体机制可参考两篇父文档);
- weave:多主机容器网络方案,去中心化控制平面,各 host 的 wRouter 间建立 Full Mesh TCP 连接并通过 Gossip 同步控制信息,数据平面通过 UDP 封装实现 L2 Overlay,支持 user space 的 sleeve mode 与 kernel space 的 fastpath mode(见 extension/network/weave.md)。优点是去中心化、故障自动恢复、支持加密通信与 Multicast,缺点是 UDP 模式性能损失较大。
选型时还需与 Service 负载均衡机制配合考虑:Service 通过标签选取后端 Pod,kube-proxy 将服务 IP 负载均衡到这些 endpoints 上(见 concepts/objects/service.md),网络插件只负责 Pod 间与跨节点通信。
验证集群:确认控制面与系统组件全部就绪
Ansible 运行完毕且无错误后,即可在部署节点上使用 kubectl 验证集群。
查看版本信息
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"6", GitVersion:"v1.7.3+coreos.0", GitCommit:"9212f77ed8c169a0afa02e58dce87913c6387b3e", GitTreeState:"clean", BuildDate:"2017-04-04T00:32:53Z", GoVersion:"go1.8.3", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"6", GitVersion:"v1.7.3+coreos.0", GitCommit:"9212f77ed8c169a0afa02e58dce87913c6387b3e", GitTreeState:"clean", BuildDate:"2017-04-04T00:32:53Z", GoVersion:"go1.8.3", Compiler:"gc", Platform:"linux/amd64"}
Client 与 Server 版本一致(v1.7.3+coreos.0),说明 kube-apiserver 已正常提供服务。
查看节点状态
$ kubectl get node
NAME STATUS AGE VERSION
master1 Ready,SchedulingDisabled 11m v1.7.3+coreos.0
node1 Ready 11m v1.7.3+coreos.0
node2 Ready 11m v1.7.3+coreos.0
node3 Ready 11m v1.7.3+coreos.0
控制节点 master1 显示 Ready,SchedulingDisabled,即已就绪但默认不调度业务 Pod(与 setup/cluster/README.md 中「controller manager 和 scheduler 通过 --leader-elect=true 保证单一实例」的控制面设计一致);三个工作节点均 Ready。
查看系统组件 Pod
$ kubectl get po -n kube-system
NAME READY STATUS RESTARTS AGE
dnsmasq-975202658-6jj3n 1/1 Running 0 14m
dnsmasq-975202658-h4rn9 1/1 Running 0 14m
dnsmasq-autoscaler-2349860636-kfpx0 1/1 Running 0 14m
flannel-master1 1/1 Running 1 14m
flannel-node1 1/1 Running 1 14m
flannel-node2 1/1 Running 1 14m
flannel-node3 1/1 Running 1 14m
kube-apiserver-master1 1/1 Running 0 15m
kube-controller-manager-master1 1/1 Running 0 15m
kube-proxy-master1 1/1 Running 1 14m
kube-proxy-node1 1/1 Running 1 14m
kube-proxy-node2 1/1 Running 1 14m
kube-proxy-node3 1/1 Running 1 14m
kube-scheduler-master1 1/1 Running 0 15m
kubedns-1519522227-thmrh 3/3 Running 0 14m
kubedns-autoscaler-2999057513-tx14j 1/1 Running 0 14m
nginx-proxy-node1 1/1 Running 1 14m
nginx-proxy-node2 1/1 Running 1 14m
nginx-proxy-node3 1/1 Running 1 14m
从这份 kube-system 命名空间的 Pod 列表可以完整读出 Kubespray 的部署成果,逐一对应控制面组件:
- kube-apiserver / kube-controller-manager / kube-scheduler(master1):Kubernetes 控制面的三大件,全部
Running;三者通过 manifest 形式由 kubelet 拉起。若需自定义 apiserver 参数(如服务网段、admission control、RBAC 等),可参考仓库中 systemd 部署示例 manifests/systemd/kube-apiserver.service 与 etc/kubernetes/apiserver 中列举的--service-cluster-ip-range、--authorization-mode=RBAC、--admission-control、--apiserver-count=3、--event-ttl=1h等生产参数;kubelet 的启动参数形态见 manifests/systemd/kubelet.service; - kube-proxy(所有节点):每个节点一个,负责将 Service ClusterIP 负载均衡到后端 Pod endpoints;
- flannel(所有节点):即
-n flannel选择的网络插件,每个节点一个 DaemonSet 形态的 flanneld,负责维护本机子网与 VXLAN/路由转发。其运行后的 CNI 配置与/run/flannel/subnet.env形态可参考 extension/network/flannel.md; - kubedns + dnsmasq + kubedns-autoscaler:集群 DNS 服务链,kubedns 提供 Kubernetes 服务发现解析,dnsmasq 作缓存/转发层,autoscaler 按集群规模调整副本数。若集群升级到 CoreDNS,其资源请求与探针配置可参考仓库清单 manifests/kubedns/coredns.yaml(内含
errors、health、kubernetes、prometheus :9153、cache 30等 Corefile 插件配置); - nginx-proxy(node1-3):工作节点上的反向代理,为访问 kube-apiserver 提供本地端口代理,是 Kubespray 高可用访问链路的组成部分。
所有 Pod 均 Running 且无异常重启计数后,即可认定集群可用,可以开始部署业务应用。
后续运维要点
国内网络环境的镜像加速
Kubespray 部署过程需要拉取大量 Google Container Registry 镜像,在国内网络环境下常会遇到拉取失败或过慢的问题。可参考 appendix/mirrors.md 中记录的国内镜像方案:例如阿里云 registry.cn-hangzhou.aliyuncs.com/google_containers 镜像仓库、hub-mirror.c.163.com Docker Hub 镜像,以及开源社 Azure China 镜像代理等,在部署前把 Kubespray 变量中的镜像地址替换为可用镜像源。
高可用集群的底层保障
Kubespray 声称支持 HA 集群,其工程实质对应仓库 practice/ha.md 与 setup/cluster/README.md 描述的控制面高可用模型:
- etcd 集群模式:多台 etcd 节点组成集群(Kubespray 通过
[etcd]组声明),避免单点存储故障; - kube-apiserver 负载均衡:为多台 Master 的 apiserver 配置负载均衡(云平台 ELB 或 haproxy/lvs/nginx),nginx 场景建议
proxy_timeout: 10m,大规模集群注意调大--max-requests-inflight(默认 400); - kube-controller-manager / kube-scheduler 选主:启动时设置
--leader-elect=true,保证任何时刻只有一个实例在运行(如kube-scheduler --master=127.0.0.1:8080 --v=2 --leader-elect=true)。
常见排查思路
- 若 Ansible 统计出现
failed或unreachable,先核对 SSH 免密、sudo 免密与/etc/hosts解析三项前置条件,再以--verbose查看具体任务报错; - 若 Pod 状态非
Running,先看kubectl describe与kubectl logs,重点检查网络插件 Pod(flannel 等)是否完成 CNI 配置,以及 kube-dns/kubedns 是否因资源不足或镜像拉取失败而 Pending; - 若要更换网络插件,需在部署前通过
-n参数确定,部署后混用不同插件会破坏 Pod 网络一致性。
总结
通过 Kubespray,一条 kubespray deploy 命令即可把「系统配置、etcd 集群、控制面三大组件、网络插件、集群 DNS、节点代理」完整地交付到裸机节点上,配合 inventory 的角色分组与 -n 网络插件参数,能够在物理机与主流云平台上快速获得一套可组合、可复用的生产级 Kubernetes 集群。结合本仓库的 setup/cluster/kubespray.md、extension/network/flannel.md、extension/network/calico.md、extension/network/weave.md、practice/ha.md 等文档,可以针对具体场景(网络策略需求、云平台路由、高可用要求)定制出最适合自己的部署组合。