5 台服务器,从二进制装 K8s 到 Spring Cloud 上线

用 5 台服务器从二进制安装 K8s 1.36 高可用集群,再搭 DevOps 工具链、上线 Spring Cloud 微服务。全文拆为 5 篇:系统与证书、控制面、工作节点、工具链、上线验收。

技术文章约 7 分钟86 次阅读
项目说明
适用环境5 台 Rocky Linux 9.x(3 控制面 + 2 工作节点),内核 ≥ 5.10
系列共 5 篇,按顺序读;旧单篇链接仍指向本页
版本Kubernetes v1.36.4、etcd v3.6.13、containerd v2.3.3 LTS、Calico v3.32.2
最后核对2026-10-27

#开篇:这个问题背后是一条依赖链

5 台物理机或虚机,要求二进制安装 Kubernetes,再承载 DevOps 工具链并跑起一套 Spring Cloud 微服务——这件事做到最后的标准不是"命令能不能复制",而是"每个组件进程是不是被喂饱了依赖":etcd 要有奇数成员的共识和双向 TLS,apiserver 要有覆盖所有访问地址的证书和唯一的稳定入口,kubelet 要有容器运行时、pause 镜像和 CNI,微服务要有 Service 提供的稳定名字和注册中心里可路由的 IP。背后最基础的事实是:Kubernetes 本质上是一组用证书互信的进程,所有状态写入都汇聚到 apiserver 这一个入口、再落到 etcd 这一个共识存储,任何一层依赖断掉,集群都会以具体症状还给你。这篇文章从这条因果链出发:先把机制讲透,再给可复现的操作、验证方法与纠错路径。

#系列导航

#篇目内容
一系统初始化与证书底座角色与网段、系统初始化、containerd、证书
二etcd 与控制面高可用etcd 三成员、控制平面三件套、haproxy + keepalived
三工作节点、CNI 与存储kubelet/kube-proxy、Calico、Ingress-NGINX、NFS
四DevOps 工具链Harbor、Gitea、Nexus、Jenkins、Argo CD、可观测性
五Spring Cloud 上线与验收中间件、微服务上线、发布回滚、验收

怎么读:只想搭集群,读一 → 二 → 三;还要工具链,加四;要把微服务上线,加五。只想理解原理,继续读本页的原理层。

原单篇 7.7 万字已拆为 5 篇,旧链接仍指向本页。

#原理层:先看清每个进程需要什么

#控制面是"一个入口 + 一组共识 + 一堆循环"

etcd 需要的是共识。 etcd 用 Raft 协议在成员之间复制日志,写入必须过半数确认,所以成员数必须是奇数,3 是最小的可靠配置;2 个成员的 etcd 没有任何意义,坏一台整个集群就不可写。它对外暴露两类端口:2379 给客户端读写键值,2380 给成员之间做 peer 同步,两侧都要求 TLS,否则任何一台被抓端口都能冒充成员。etcd 还依赖两件常被忽略的事:磁盘(快照与 WAL 都要求低延迟,--quota-backend-bytes 限制总容量,超过后集群拒绝写入)和时间(证书校验强依赖时间,差几分钟,peer 通信会以各种想不到的姿势失败,而且报错里一个字都不提"时间")。

apiserver 需要的是唯一入口。 所有组件——kubelet、kube-controller-manager、kube-scheduler、kube-proxy、kubectl——都只跟 apiserver 说话,etcd 也只接受 apiserver 的读写。所以 apiserver 必须满足三个条件:能连上 etcd(--etcd-servers 指向三个 2379);自身服务端证书的 SANs 必须覆盖所有会被访问的地址(本机 IP、VIP、Service IP 10.96.0.1、集群内域名 kubernetes.default.svc.cluster.local);能验证别人的身份(--client-ca-file)。多副本 apiserver 是允许的,但它们必须共享一个 VIP 或负载均衡入口,这就是后面 haproxy + keepalived 存在的理由。

controller-manager 需要的是签发权和视野。 它是一堆控制循环(节点监控、ReplicaSet、Endpoint、namespace、ServiceAccount 等),用 kubeconfig 连 apiserver 读取期望状态并持续修正实际状态。它手里还有两把钥匙:--cluster-signing-cert-file / --cluster-signing-key-file 给 kubelet 的证书签名请求(CSR)签发证书,--service-account-private-key-file 签 JWT。它的 --cluster-cidr 决定每个节点分到的 Pod 网段,这个值和 CNI 的 IP 池必须一字不差。

scheduler 需要的是最小依赖。 它读 Pod 的调度约束(nodeSelector、亲和性、污点容忍),把 Pod 绑定到节点,只需要一个 kubeconfig,是控制面里最简单的进程。

#工作节点是"容器管家 + 流量转发"

kubelet 是节点上的总管家。 它用 kubeconfig 连 apiserver,watch 分配到本节点的 Pod 期望,然后驱动容器运行时创建容器。它需要:containerd 的 socket(--container-runtime-endpoint)、pause 沙箱镜像、自己的客户端证书(首装用 bootstrap token 申请,之后 rotateCertificates: true 自动续签)、CNI 提供的 Pod 网络。kubelet 的 10250 端口是它的 API,apiserver 要拉日志、执行 exec 必须用受信证书访问它——这正是 system:kube-apiserver-to-kubelet 这个 ClusterRole 存在的意义。

kube-proxy 是流量的翻译器。 它 watch Service 和 EndpointSlice,把"ClusterIP:Port"翻译成本机内核里的转发规则。二进制部署常用 ipvs 模式,依赖 ip_vs 系列内核模块(初始化脚本加载的就是这些)。Pod 访问 Service 时,流量在本机被 kube-proxy 的规则转发到某个后端 Pod IP。

#为什么二进制安装能暴露真实依赖

kubeadm 能用就用,但它把证书、静态 Pod、启动参数都藏起来了,出问题时你不知道该看哪儿。二进制装一遍,每个组件是 systemd 里一个看得见的进程、一组可读的参数,依赖关系显式暴露:apiserver 起不来,journalctl 会告诉你到底是证书 SANs 少了、etcd 连不上还是 RBAC 没配;kubelet 不 Ready,日志会直接说 cgroup driver 不一致。你亲手把每一个文件、每一个端口、每一条命令拼起来,之后它坏在哪一层,你一眼就能定位到那一层——这个排障能力是买不来的。代价是安装包自己管、升级自己滚、证书自己轮换,规模上来之后维护成本高。所以这套方案适合几百节点以下、没有专职 K8s 团队、但又想完全掌控的场景。

#微服务在 K8s 上如何发现彼此

K8s 里的服务发现是两套并存的:

  • 平台层的 Service/DNS:每个 Service 被分配一个稳定的 ClusterIP(取自 10.96.0.0/12),并自动产生 DNS 记录 <service>.<namespace>.svc.cluster.local(CoreDNS 固定在 10.96.0.10)。Pod 的 /etc/resolv.conf 被 kubelet 指向 CoreDNS,业务代码只需要用名字访问,kube-proxy 负责把名字背后的 ClusterIP 转发到具体 Pod。Service 的 selector 匹配一组 Pod,Pod 重建后 IP 变了,Service 和 DNS 名不变。
  • 应用层的注册中心(Nacos):Spring Cloud 微服务启动时主动向 Nacos 注册自己的地址,网关和 Feign 从 Nacos 拉实例列表。这里有一个 K8s 特有的大坑:Nacos 里注册的必须是 Pod IP,而不是容器 hostname 或错误的网卡 IP,否则网关转发连不上——部署清单里用 SPRING_CLOUD_NACOS_DISCOVERY_IP=$(POD_IP) 解决。

分工很清晰:Service/DNS 解决"进程在集群里怎么找到对方",注册中心解决"业务代码在运行期怎么选路、怎么做配置下发"。

#与部署到虚拟机的差异

虚拟机部署时代,每个服务一个固定 IP,服务间调用地址写死在配置里,扩容靠人工或自建注册表,Nginx 配置坏了就是访问故障。K8s 上则完全不同:Pod 是"临时公民",IP 随时可能变,所以一切稳定性依赖都从 IP 挪到了名字——Service 提供稳定的 ClusterIP 和 DNS 名,Deployment 声明副本数,HPA 按指标扩缩容,Ingress 按域名把外部流量路由进集群。原来写死的服务地址变成"每次调度都可能变化,但名字永远不变"的模型;这要求应用对生命周期有明确态度:优雅下线、探针、启动窗口,都是为"Pod 随时会消失"这个事实服务的。

#延伸阅读

相关阅读

Related

留言讨论

0 条

还没有留言,来说点什么吧。

5 台服务器,从二进制装 K8s 到 Spring Cloud 上线 · LXH·BLOG