ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

二进制方式部署高可用K8s集群的一键脚本设计与实践

二进制方式部署高可用K8s集群的一键脚本设计与实践 简介这是一套面向云原生初学者与运维工程师的二进制高可用Kubernetes集群部署工具集专为降低k8s底层原理学习门槛而设计解决手动部署etcd、apiserver、kubelet等核心组件流程繁琐、易出错的痛点。资源共13个文件包含4个Shell脚本覆盖ETCD初始化、主从节点部署、VIP配置及集群安装、2个压缩包含k8s服务端与Docker二进制分发包、2个CNI网络插件YAMLCalico与CoreDNS、1个详细README说明文档以及CFSSL系列证书工具总大小398.89MB。已有1574人学习下载适合希望深入理解k8s控制平面组件协作机制、掌握证书签发与高可用架构搭建的学习者。开箱即用的一键脚本大幅简化了证书生成、服务启停、节点准入等关键步骤同时保留完整配置逻辑便于调试、定制与故障复现。 先交代个背景——去年帮客户搭生产环境K8s集群客户提了一个很硬的要求不用kubeadm全部用二进制方式部署控制面。理由其实很实际一是他们对组件版本和参数有严格的管控要求kubeadm封装掉了太多细节出了问题不好排查二是部署环境基本是内网离线状态kubeadm拉镜像那一步就够折腾的。那段日子我一边敲命令一边琢磨这套流程从生成证书到启动组件来回十几台机器重复操作太容易出错了。不如把这套流程固化成脚本于是就有了今天要聊的东西二进制高可用k8s集群一键部署脚本。这个项目解决的核心痛点是把二进制部署K8s从“手工操作两三天”压缩到“一条命令跑完基础环境”同时保证集群架构是高可用的不是单点玩票。它适合三类人第一类是运维工程师需要在生产环境搭建可控性强的K8s集群第二类是刚学K8s想彻底搞懂组件原理的开发者二进制部署是最好的学习路径第三类是内网离线环境交付项目的实施人员这脚本能帮你省掉大量重复劳动。1. 为什么偏要用二进制部署高可用K8s集群1.1 二进制方案和kubeadm的本质差异很多人刚接触K8s时基本都是用kubeadm一键初始化。kubeadm确实好用它把证书生成、组件编排、控制面自举这些复杂工作全部封装了新手能在半小时内拉起一个集群。但“好用”的另一面是“黑盒”——kubeadm把kube-scheduler、kube-controller-manager、etcd都做成了Static Pod跑在容器里配置文件分散在/etc/kubernetes/manifests下面你很难直观看到每个组件到底是怎么被拉起来的。二进制部署的思路完全不同。我们直接从官方或编译好的二进制包里拿到kube-apiserver、kube-controller-manager、kube-scheduler、kubelet、kube-proxy这些可执行文件放到/usr/local/bin目录下然后用systemd去管理它们。每个组件启动时用了什么参数、监听哪个端口、证书挂在哪个路径全都清清楚楚。这种差异带来的实际收益有三个层面可控性每个组件是独立的systemd服务可以单独重启、查看日志、调整启动参数不用把整个K8s集群重启一遍。轻量性控制面组件不跑在容器里省掉了一层容器运行时依赖故障排查时不需要先搞清楚容器是否正常。离线友好二进制包下载一次就可以内网分发不需要像kubeadm那样依赖镜像仓库。但这是有代价的。二进制部署的证书体系、组件启动参数、高可用配置全部要手工搞定其中任何一个环节配错了集群都起不来。脚本的意义就是把这份复杂度封装起来。1.2 高可用到底解决了什么问题K8s控制面有四个关键角色etcd存储、kube-apiserver入口、kube-controller-manager控制器、kube-scheduler调度器。如果不做高可用这几组件都部署在一台机器上那这台机器一挂整个集群就失联了。高可用方案的核心思路是多副本 负载均衡 故障转移。先说apiserver。它是无状态的多个apiserver实例可以同时对外提供服务前面加一层负载均衡把流量分发到各个实例即可。再说controller-manager和scheduler它们是有状态的选主逻辑同一时刻只能有一个活跃实例其他实例处于待命状态通过--leader-elect参数开启选举主节点挂了备用节点自动接管。最麻烦的是etcd它是强一致的分布式存储需要奇数个节点构成etcd集群通过Raft协议保证数据一致性。我在脚本里默认按三台Master、至少一台Worker来设计。三台Master刚好满足etcd集群奇数节点要求。如果要极致省机器也可以把etcd单独拆出去放在独立节点上但中小规模场景通常不用拆。1.3 什么时候不必用这种方案坦白讲并不是所有场景都适合二进制部署。如果你的集群规模不大、团队K8s经验也一般kubeadm其实是更稳妥的选择。RKE2也值得关注它是Rancher推出的K8s发行版把etcd、控制面组件都封装成了静态Pod自带证书管理和升级工具操作体验比纯二进制好很多算是一个中间方案。我个人建议的选型标准是生产环境、有专职运维、对组件参数有强管控需求 → 二进制部署中小团队、希望快速交付且后续升级方便 → RKE2或kubeadm离线内网环境、需要完全掌控安装包和版本 → 二进制部署只是学习测试、想快速跑起来 → kubeadm这个脚本不是为了替代kubeadm而是给需要二进制方案的人省掉重复劳动。2. 高可用集群架构设计与组件规划2.1 拓扑结构与网络规划写脚本之前第一件事是把架构图画清楚。我用的方案是三台Master节点承载控制面组件Worker节点若干通过VIP虚拟IP负载均衡器暴露apiserver地址。整个集群的流量路径是这样的kubelet和kube-proxy访问apiserver时统一走VIP地址VIP由keepalived绑定在其中一台Master上后端的haproxy会把流量转发到三台Master的apiserver端口默认6443。当持有VIP的Master宕机keepalived通过VRRP协议自动把VIP漂移到另外一台Master。在IP规划上我建议单独留一段IP给K8s内部使用比如Pod网段10.244.0.0/16、Service网段10.96.0.0/12。这两个网段不能和物理机/服务器网段冲突务必提前规划好。etcd节点则直接使用Master节点的物理IP因为etcd集群节点之间需要固定地址互访。实战中我踩过一个坑IP网段规划不合理导致集群内部网络冲突。比如Service网段选用了和公司内部其他系统相同的192.168.x.x跨系统访问时出现莫名的路由问题。Docker的默认网桥也占用了172.17.0.1如果再和Pod网段重叠那问题就更难排查了。2.2 证书体系的搭建思路二进制部署K8s最令人头大的部分就是证书体系。K8s内部几乎所有组件之间的通信都是TLS加密的需要一套完整的CA体系和签发流程。这里的关键点是要区分两个独立的CAetcd CA和kubernetes CA。etcd CA负责签发etcd集群内部节点之间通信的证书kubernetes CA负责签发apiserver、kubelet、kubectl等组件之间的通信证书。两套CA相互独立不能混用。以kubernetes CA为例需要签发的证书至少包括apiserver证书需要包含所有apiserver节点的IP、VIP地址、Service网段第一个IP通常是10.96.0.1以及kubernetes.default.svc.cluster.local这个域名kubelet证书每个节点一个用于kubelet与apiserver通信controller-manager证书、scheduler证书、admin用户证书签发证书用的工具主要是cfssl或openssl我在脚本中用的是cfssl因为它能通过JSON文件定义证书策略生成逻辑清晰适合脚本化批量处理。这里要特别提醒apiserver的证书SAN列表一定要把VIP地址和Service的ClusterIP加进去否则kubectl通过VIP访问apiserver时会报证书校验错误。2.3 核心组件选型与版本组合组件版本组合是部署前必须确定的事情。K8s版本和etcd版本之间有兼容性要求不同版本的kubelet和apiserver版本不能相差超过一个minor版本否则可能出现通信协议不兼容。我当前在脚本中默认使用的组合是组件版本说明kube-apiserverv1.28.2K8s控制面核心kube-controller-managerv1.28.2控制器管理kube-schedulerv1.28.2调度器kubeletv1.28.2节点代理kube-proxyv1.28.2服务代理etcdv3.5.9分布式存储haproxy2.6负载均衡keepalived2.2VIP漂移CFSSL1.6.4证书签发工具这里有个细节很多人会忽略如果使用systemd管理组件服务文件的Restart策略要配置正确例如Restarton-failure、RestartSec10s避免组件异常退出后不自动拉起。还有kubelet是K8s集群的底座kubelet没起来节点永远都是NotReady所以kubelet的systemd服务级别建议设置为multi-user.target而不是network-online.target避免网络初始化顺序问题。3. 一键部署脚本的结构设计与实现3.1 脚本的目标与设计原则动手写脚本前我给自己定了几条设计原则确保脚本不是一次性玩具而是可持续维护的工程产物配置驱动集群的基本信息不硬编码在脚本里统一放在一个配置文件中。改IP、改网段只需要动一处。幂等性同一个脚本可以重复执行重复执行不会导致集群损坏或配置重复追加。分阶段可执行整个部署过程拆成多个独立阶段可以一键全跑也可以单独执行某个阶段。这样排错时不用从头再来。离线支持所有软件包预先下载到本地脚本不依赖外部网络。3.2 目录结构与配置驱动脚本的目录结构建议如下k8s-binary-installer/ ├── config.env # 集群配置文件所有变量都在这里改 ├── install.sh # 主入口脚本 ├── libs/ │ ├── common.sh # 公共函数库日志、检查、分发 │ ├── env_init.sh # 环境初始化模块 │ ├── cert_gen.sh # 证书生成模块 │ ├── etcd_install.sh # etcd集群安装模块 │ ├── master_install.sh # Master组件安装模块 │ └── worker_install.sh # Worker节点安装模块 ├── packages/ # 二进制包和镜像文件存放目录 └── confs/ # 各组件配置文件模板config.env是我改动最频繁的文件它决定了整个集群的架构参数。简单示例# 集群基本信息 CLUSTER_NAMEk8s-prod K8S_VERSION1.28.2 ETCD_VERSION3.5.9 # 节点列表Master节点同时部署etcd MASTER_NODES(192.168.10.11 192.168.10.12 192.168.10.13) WORKER_NODES(192.168.10.21 192.168.10.22) # VIP和负载均衡 APISERVER_VIP192.168.10.20 APISERVER_PORT6443 # 网段规划 POD_CIDR10.244.0.0/16 SERVICE_CIDR10.96.0.0/12 CLUSTER_DNS10.96.0.10 # 服务网段第一个IPapiserver证书需要包含 SERVICE_CLUSTER_IP10.96.0.13.3 核心函数与执行流程主脚本install.sh的执行流程是线性的但每阶段内部又有细粒度检查。伪代码大致是#!/bin/bash set -euo pipefail source config.env source ./libs/common.sh if [ $1 all ]; then init_environment generate_certs deploy_etcd deploy_haproxy_keepalived deploy_master_components deploy_worker_components deploy_cni_and_addons elif [ $1 master ]; then deploy_master_components fi初始化环境中有一个关键步骤是节点互信SSH配置。脚本需要在一个控制节点上免密登录其他所有节点才能分发文件。生产环境推荐用专门的部署账号不要直接用root更不要把root密码明文写在脚本里。我这里的方案是让部署人员提前配置好SSH密钥脚本只做检查不做生成。3.4 幂等与安全设计幂等性这点我踩过很多坑。比如往/etc/hosts里追加条目如果脚本执行两次就会重复追加两行。因此所有需要追加或修改的配置文件我都先备份再写入且在操作前检查是否已存在目标配置。如果检测到相同内容就跳过写入function append_if_not_exist() { local file$1 local content$2 grep -qF $content $file || echo $content $file }另一个安全设计是脚本执行的每步关键操作都要有日志输出和错误码判断。我用的是颜色区分日志级别绿色表示成功红色表示失败黄色表示警告并输出到日志文件。这样在无人值守跑脚本时可以通过日志快速定位是哪个阶段失败了。4. 实操过程与关键环节配置解析4.1 环境初始化与内核参数环境初始化这步看似不起眼实则决定了集群能否稳定运行。主要在每台节点上做这几件事配置主机名和/etc/hosts映射、关闭swap、加载内核模块、设置iptables不拦截桥接流量、调整系统参数。/etc/hosts需要包含所有节点的主机名和IP否则组件之间通过主机名通信时会解析失败。我习惯的主机名命名规则是k8s-master-1、k8s-master-2、k8s-master-3、k8s-worker-1这样的格式在证书签发时也方便识别。内核模块至少要加载br_netfilter和overlay否则K8s的iptables规则和容器网络会出问题。对应内核参数检查清单net.bridge.bridge-nf-call-iptables 1 net.bridge.bridge-nf-call-ip6tables 1 net.ipv4.ip_forward 1 vm.swappiness 0这些参数放在/etc/sysctl.d/k8s.conf里执行sysctl --system生效。若跳过了这一步最典型的现象就是Pod能创建但网络不通Service无法正常转发。4.2 etcd集群部署要点etcd集群是所有组件中第一个要装的因为它没有依赖关系是K8s数据层的根基。二进制部署etcd时每台节点只需要三个文件etcd可执行文件、etcdctl可执行文件和etcd.service系统服务文件。etcd的数据目录我通常放在/data/etcd避免和系统盘混在一起。etcd启动参数里以下这几项要特别留意--initial-cluster定义集群所有成员的名称和地址格式为etcd-1http://192.168.10.11:2380,etcd-2...--initial-advertise-peer-urls当前节点用于与其他节点通信的地址--advertise-client-urls对外提供客户端服务的地址--initial-cluster-state首次部署必须是new后续重启不能改成existing这里有我踩过的一个大坑如果某个etcd节点数据目录损坏重新加入集群时--initial-cluster-state还写成newetcd会认为这是一个新集群强行把所有节点拉进一个新的集群导致数据错乱。正确做法是删除损坏节点的数据目录以existing状态重新加入。每台etcd节点的systemd服务文件核心部分如下[Unit] Descriptionetcd server Afternetwork.target Afternetwork-online.target Wantsnetwork-online.target [Service] Typenotify ExecStart/usr/local/bin/etcd \ --nameetcd-1 \ --data-dir/data/etcd \ --listen-peer-urlshttps://192.168.10.11:2380 \ --listen-client-urlshttps://192.168.10.11:2379 \ --advertise-client-urlshttps://192.168.10.11:2379 \ --initial-advertise-peer-urlshttps://192.168.10.11:2380 \ --initial-clusteretcd-1https://192.168.10.11:2380,etcd-2https://192.168.10.12:2380,etcd-3https://192.168.10.13:2380 \ --initial-cluster-statenew \ --cert-file/etc/etcd/ssl/etcd-server.pem \ --key-file/etc/etcd/ssl/etcd-server-key.pem \ --peer-cert-file/etc/etcd/ssl/etcd-peer.pem \ --peer-key-file/etc/etcd/ssl/etcd-peer-key.pem \ --trusted-ca-file/etc/etcd/ssl/ca.pem \ --peer-trusted-ca-file/etc/etcd/ssl/ca.pem Restarton-failure RestartSec10s [Install] WantedBymulti-user.target注意Typenotify这个细节etcd通过systemd通知机制告知服务已就绪如果没有设置systemd会认为服务还在启动中导致后续脚本判断依赖关系时出错。4.3 控制面组件与负载均衡联动Master节点上的kube-apiserver是最难配的组件因为它要把证书、etcd地址、Service网段、VIP地址全部串起来。核心启动参数里有几个必须解释清楚。--advertise-address必须绑定VIP地址而不是本机IP。这是为了保证kubelet通过VIP访问apiserver时apiserver返回的地址也是VIP客户端才能正常连接。如果这里配成了本机IPkubelet连上apiserver后会被要求重连到那个本机IP但本机IP在集群外可能不可达于是一连一连失败。--service-cluster-ip-range要和config.env里定义的Service网段一致kube-proxy会在这个网段里分配Service的ClusterIP。--client-ca-file指向kubernetes CA的证书。所有客户端包括kubectl、kubelet、scheduler访问apiserver时apiserver都会校验客户端证书是否由这个CA签发。apiserver的systemd服务文件核心参数示例ExecStart/usr/local/bin/kube-apiserver \ --bind-address0.0.0.0 \ --advertise-address192.168.10.20 \ --secure-port6443 \ --etcd-servershttps://192.168.10.11:2379,https://192.168.10.12:2379,https://192.168.10.13:2379 \ --etcd-cafile/etc/kubernetes/pki/etcd-ca.pem \ --etcd-certfile/etc/kubernetes/pki/etcd-client.pem \ --etcd-keyfile/etc/kubernetes/pki/etcd-client-key.pem \ --service-cluster-ip-range10.96.0.0/12 \ --service-node-port-range30000-32767 \ --client-ca-file/etc/kubernetes/pki/ca.pem \ --tls-cert-file/etc/kubernetes/pki/apiserver.pem \ --tls-private-key-file/etc/kubernetes/pki/apiserver-key.pem \ --kubelet-client-certificate/etc/kubernetes/pki/apiserver-kubelet-client.pem \ --kubelet-client-key/etc/kubernetes/pki/apiserver-kubelet-client-key.pem \ --service-account-key-file/etc/kubernetes/pki/sa.pub \ --service-account-signing-key-file/etc/kubernetes/pki/sa.key \ --service-account-issuerhttps://kubernetes.default.svc.cluster.local \ --authorization-modeNode,RBAC \ --allow-privilegedtrue \ --enable-admission-pluginsNodeRestrictioncontroller-manager和scheduler相对简单只需要通过kubeconfig访问apiserver加上--leader-electtrue开启选主即可。这两个组件的kubeconfig我可以提前生成好放到/etc/kubernetes/conf目录下它们的systemd单元文件只要正确指向kubeconfig就能工作。4.4 Worker节点加入与校验Worker节点的初始化相对简单核心是安装kubelet和kube-proxy。kubelet负责注册节点、运行Podkube-proxy负责维护Service的iptables/IPVS规则将Service访问负载到后端Pod。生产环境建议用bootstrap token方式代替手动签发每个节点的kubelet证书。流程是在Master上创建一个bootstrap token把token信息放到Worker节点的bootstrap-kubeconfig里kubelet首次启动时用这个token向apiserver发起CSR请求管理员批准该CSR后apiserver自动为kubelet签发证书。不过这里有个关键配置要开启kubelet的证书自动轮转。不开启的话kubelet证书过期后节点会直接失联。自动轮转主要涉及两个参数--rotate-certificatestrue和kubelet配置里的rotate-server-certificates: true。前者是kubelet启动参数后者是配置文件里的开关。还要在kube-system命名空间里单独创建一个ClusterRoleBinding允许bootstrap组自动轮转证书apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: kubelet-bootstrap-auto-approve roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: system:certificates.k8s.io:certificatesigningrequests:nodeclient subjects: - apiGroup: rbac.authorization.k8s.io kind: Group name: system:bootstrappers脚本执行完Worker节点的包后立刻进入验证环节。我个人习惯用以下checklist确认集群健康# 查看所有节点状态都应该是Ready kubectl get nodes -o wide # 查看核心组件Pod状态都应该是Running kubectl get pods -n kube-system # 验证ETCD集群健康状况 ETCDCTL_API3 etcdctl --endpointshttps://192.168.10.11:2379,https://192.168.10.12:2379,https://192.168.10.13:2379 \ --cacert/etc/kubernetes/pki/etcd-ca.pem \ --cert/etc/kubernetes/pki/etcd-client.pem \ --key/etc/kubernetes/pki/etcd-client-key.pem \ endpoint health4.5 CNI网络插件和CoreDNS部署集群节点起来了网络还是空的。接下来需要部署CNI插件我默认选Calico它支持网络策略且常用的IPIP模式和BGP模式都成熟。Calico部署时需要把configmap里的Pod网段改成自己的规划网段再应用Calico的manifest。这里有个容易混淆的地方Calico的Pod网段和Service网段完全是两回事。Calico管理的是Pod实际使用的IP段Service的ClusterIP是K8s在service网段内分配的虚拟IP不参与实际网络转发。如果两个网段配重合了数据包路由就会乱套。CoreDNS是集群内部DNS服务Service的域名解析全靠它。如果CoreDNS不部署集群内的Service名字无法解析Pod之间无法通过服务名互通。CoreDNS部署后要确认Pod是Running状态并且能解析到cluster.local域名。5. 常见问题与排查技巧实录5.1 部署过程中的典型故障脚本化部署最让我抓狂的问题都集中在证书和网络两个地方。证书问题通常表现为集群组件起来了但互相通信失败日志里出现x509: certificate signed by unknown authority。这类报错第一反应不是重新签发而是检查apiserver的--client-ca-file路径是否正确、etcd的CA是否和apiserver访问etcd时用的CA一致、证书的SAN列表有没有包含对应IP。网络问题里最高频的是Node一直NotReady。遇到这个状态先看kubelet服务是否正常再去看kubelet日志里是否报CNI相关错误。最经典的原因是容器运行时没装好。二进制部署K8s时容器运行时也要自己装我用的是containerd如果containerd没启动kubelet连不上容器运行时节点当然无法Ready。另一个常见问题是kubectl get nodes时发现apiserver连不上。如果keepalived的VIP状态正常但6443端口不通用ss -lntp看看haproxy是否在监听6443再看haproxy的配置文件里后端服务器地址是否写对。这类问题通过curl -k https://VIP:6443/healthz能否返回ok来判断一步就定位了。5.2 故障速查表现象可能原因排查命令解决方案etcd集群无法启动--initial-cluster-state配错journalctl -u etcd -f检查是否该用existingkubelet报x509错误apiserver证书SAN缺IPopenssl x509 -in apiserver.pem -text重新签发包含VIP的证书Node状态NotReadycontainerd未启动/CNI未装systemctl status containerdkubectl get pods -n kube-system启动containerd重装CalicoService无法访问kube-proxy未运行kubectl logs -n kube-system kube-proxy-xxx检查kube-proxy配置文件出现大量Evicted Pod节点磁盘/内存压力kubectl describe node扩容或清理节点资源CPU throttling严重CPU limit设置不当/节点资源不足kubectl top node调整Pod资源配额扩节点这里要单独说一下CPU throttling。K8s的CPU limit是通过CFS配额实现的如果Pod设置的CPU limit过小但实际负载波动大会出现CPU配额用完后的强制节流表现为服务响应时间毛刺。这个kubectl top只能看到Pod用量看不到throttling需要用容器运行时级别或cgroup指标去观测。遇到这种问题优先调大CPU limit或者使用cpu-manager-policystatic保证CPU独占。5.3 二进制方案的几点实战经验整套部署流程跑通后沉淀下来的经验比脚本本身更值钱。编排脚本时一定要给日志加上时间戳和阶段标识我见过太多人集群部署失败后面对没有任何标识的日志根本无从下手。每行日志形如[2025-03-01 14:30:00] [INFO] [cert_gen] Start to generate kubernetes certs排错时一眼就知道卡在哪一步。再有就是版本锁定。脚本里所有二进制包我都固定到具体版本号不搞latest。K8s生态的版本兼容矩阵很严格apiserver、controller-manager、scheduler、kubelet、kube-proxy必须保持同一版本etcd和CNI插件需要满足对应兼容要求。随意升级某个组件很可能导致整个集群不可用。关于备份etcd定期快照这件事无论如何强调都不过分。生产集群数据是核心资产脚本里应该定时执行etcdctl snapshot save快照文件保留最近七天。我在脚本里写了一个cron任务每天凌晨两点全量备份备份文件通过rsync同步到独立存储。这套机制在多次故障恢复中真的救了大命。5.4 后续方向二进制部署K8s的上手门槛确实高但它的收益也很实。通过一次部署你能真正理解每个组件的作用、证书的流转关系、高可用的选主机制这些都是排障时的底层能力。这个脚本目前覆盖了从环境初始化到CoreDNS部署的完整链路后续有时间我计划加上Cert-Manager自动管理证书、Velero备份恢复、以及升级脚本。如果你在生产环境用过类似的部署方案欢迎一起交流踩坑经验毕竟K8s这套东西越多人趟过的坑后来者就越少踩雷。本文还有配套的精品资源点击获取
返回列表