系列二十五篇本已完结,但运维线一直是个缺口——前面讲过的”K8s 部署痕迹”(云主线的 pod 配置、物联篇的 0 号节点)都只是切片。这两篇增补把切片拼成整图:本篇讲一套生产 K8s 部署清单——CentOS 7 自建集群上跑全套 MES 微服务,外加完全自建的 Prometheus 告警监控栈;下一篇讲 MySQL 的物理备份一键化与恢复演练。
先修正一个容易望文生义的误解:这个项目叫 install-k8s,但里面没有一行安装脚本——它是部署清单(manifests)仓库,K8s 集群本身装好后,”把 MES 搬上去”的全部知识都沉淀在这三十八个 YAML 里。这个定位本身就值得说:集群是易耗品,清单才是资产——装集群一天的活,调清单调了一年。
一、部署形态:五节点、三块清单、一种纪律
集群拓扑是中小制造企业的典型形态:一台 Master、两台 Worker,外加专职的数据节点和文件节点——单 Master 不是 HA,是有意的取舍:集群规模小、Master 挂了全厂停线的概率被接受,省下的复杂度换给业务。清单分三块:
- 注册中心层:Eureka 双副本 StatefulSet 加 headless service、配置中心、网关(NodePort 暴露);
- 业务层:约二十个微服务的 Deployment,统一命名空间,镜像全部来自私有 Harbor 仓库;
- 监控层:完全自建的 Prometheus、Alertmanager、Grafana、Loki 栈,二十多条告警规则,告警走钉钉机器人。
纪律体现在镜像 tag 上:日期号版本(如 20260723.1)而不是 latest——每次发版一个可回溯的号,回滚就是改回上一个日期号。这个习惯的养成通常伴随一次”latest 标签被覆盖、回滚无门”的事故,属于 K8s 运维的第一课。
二、Eureka 上 K8s:稳定域名组网
微服务族里最先要解决的是注册中心的容器化——Eureka 双副本互相注册,pod 换 IP 就失联。K8s 的答案是 StatefulSet 加 headless service:副本获得稳定域名(pod-0、pod-1),互相注册的地址写死在这两个域名上,pod 重建 IP 变了域名不变。
呼应全景篇埋的伏笔:业务服务的配置里有 K8S_EUREKA_SERVER 环境变量——服务发现地址通过环境变量注入,本地开发指本地 Eureka、集群里指 StatefulSet 域名,一份镜像两端跑。这个模式和交付篇讲过的云主线”K8s 里 Service 域名直连替代对等发现”是同一条演进线:容器平台接管了稳定寻址,应用层注册中心的角色在悄悄降级——但没降到能删,因为滚动发布窗口里还有它兜底。
三、Java 微服务的容器适配:四个实战细节
Java 微服务上 K8s,坑全在”JVM 的脾气和容器的生活习惯不同”。这套清单里四个细节全是事故的化石:
其一:探针的超长宽限。 清单演进 diff 里新增了 livenessProbe 且 initialDelaySeconds 设到 600 秒——十分钟的启动宽限。背景是 Spring Cloud 微服务的冷启动(注册、拉配置、建连接池)加上 JVM 预热,低配节点上几分钟才就绪;探针配短了就是启动中被误杀、重启、再被杀的循环(OOMKill 循环)。十分钟看着粗暴,是拿事故换的参数。
其二:优雅终止的取舍。 terminationGracePeriodSeconds: 0——pod 被删时不给优雅退出时间,立即砍。常规建议是给 30 秒让在途请求排空,这里归零的动机是发布速度和”服务自身已有无损下线机制”的自信(网关切流先行)。优雅终止参数没有标准答案,只有和自身流量调度机制的配合。
其三:故障的快速漂移。 节点故障时给 pod 配了极短的容忍时间(tolerationSeconds: 2)——节点失联两秒就开始驱逐漂移到别的节点。激进值的背景是车间的可用性要求高于”防抖动”:宁可误漂移一次,不可多挂一分钟。
其四:有状态数据的落点。 监控组件用 hostPath 加节点固定(nodeSelector 绑死某台 worker)加 DirectoryOrCreate 的组合——不用分布式存储,用”指定节点上的本地目录”模拟持久卷。数据不漂移(nodeSelector 钉死)是 hostPath 可用的前提,这是自建集群在没有存储方案时的标准过渡姿势。
四、注解式监控自动发现:三个注解和两个坑
监控栈最有含金量的设计是 Prometheus 的注解式自动发现:每个业务 pod 打三个注解(声明”我被监控、暴露端口、路径”),Prometheus 的 discovery 配置按注解筛选并重写抓取地址——新服务上集群,打注解自动进监控,不改监控配置。这是”约定优于配置”在监控层的第四次出场(物联篇的参数映射、状态机篇的流程图、框架篇的 Layout XML,同一个思想)。
两个坑的注释原文都在配置里。坑一:kubelet 的指标端点是 HTTPS——按 HTTP 配永远是连接拒绝,正确姿势是 https 加跳过证书校验加 Bearer token 三件套。坑二:instance 标签必须重写为节点名——不重写时默认是 pod IP,pod 重建 IP 一换,Prometheus 里历史曲线就”换了个对象”,图表断成两截;固定成节点名后重启不丢历史。监控配置的坑有个共同点:配错了不报错,只是安静地给你错误的数据——监控系统的故障是”看起来正常”的故障,要靠对数据的敏感度发现。
五、自建监控栈与演进考古
监控栈的选型组合是 Prometheus(指标)+ Alertmanager(分组静默)+ Grafana(可视化)+ Loki(日志),全部自建于同集群——云服务(如云监控)被放弃的原因是私有化环境的数据边界。告警规则二十多条(服务存活、资源水位、证书过期),推送走钉钉机器人 webhook——和总线篇的系统事件告警通道在终端汇合。离线环境的镜像获取也有痕迹:多个组件的镜像来自云厂商中转仓库再转推私服——离线集群的每一个镜像都是一条搬运路线。
清单仓库里的 .bak 文件是演进考古的富矿:diff 一下能看到镜像号推进了几个月、资源限额翻了一倍(1Gi 到 2Gi——业务量涨了)、探针从无到有——部署清单的版本历史,就是这套系统在 K8s 上的成长记录。这也是”清单即资产”的另一面:资产要能读出历史。
六、面试视角:五个问题拆到底
Q1:微服务上 K8s,注册中心怎么处理?
答:两条路线并存。StatefulSet 加 headless service 给 Eureka 稳定域名,双副本互相注册的地址写死 pod 域名;业务服务通过环境变量注入发现地址,一份镜像两端跑。趋势上 K8s 的 Service DNS 正在接管稳定寻址,注册中心降级为滚动窗口的兜底——但删它要等所有发布路径都不再依赖它。
Q2:Java 应用在 K8s 里的探针怎么配?
答:启动探针或超长 initialDelay 给足冷启动时间(我们是十分钟,来自启动期被误杀循环的事故),就绪探针接真实健康检查、存活探针别绑重资源检查(失败即杀,误杀代价最大)。配合资源限额观察 OOMKill 和 CPU 节流——Java 的堆参数要和容器限额对齐,这是另一个常见事故源。
Q3:Pod 的监控自动发现怎么实现?
答:注解式发现:业务 pod 声明式打注解(开启监控、暴露端口、路径),Prometheus 的 kubernetes-pods 发现配置按注解筛选、relabel 重写抓取地址——新服务自动纳管。两个必踩坑:kubelet 指标端点是 HTTPS 要跳过证书校验加 token;instance 标签要重写成稳定标识,否则 pod 重建后监控历史断裂。
Q4:单 Master 不做 HA,怎么辩护?
答:按可用性预算算账:集群规模小、Master 故障频率低、故障影响是”调度不可用但存量 pod 继续跑”(K8s 控制面挂了不杀业务容器),全厂停线概率远小于存储或网络故障。省下的 HA 复杂度(多 Master 加负载均衡加分布式存储)投入给了监控和备份——可用性投资要花在失效概率乘影响权重最大的地方。
Q5:离线环境的镜像和监控怎么解决?
答:镜像走”云厂商中转仓库再转推私服 Harbor”的搬运路线,版本用日期号 tag 保证可回溯;监控栈全部自建(Prometheus/Alertmanager/Grafana/Loki),数据边界留在内网。离线环境的运维哲学是每一样东西都要有一条明确的获取路线和一份固定的版本清单。
小结
- 集群是易耗品,清单是资产:三十八个 YAML 里的知识密度远超装集群的一天,.bak diff 就是成长记录;
- StatefulSet 稳定域名是注册中心容器化的钥匙:环境变量注入发现地址,一份镜像两端跑;
- Java 容器化的四个事故化石:十分钟探针宽限、优雅终止的取舍、快速漂移的激进值、hostPath 加节点固定的过渡姿势;
- 注解式监控自动发现是约定优于配置的第四次出场:三个坑里最阴的是”配错不报错、安静给错数据”;
- 镜像日期号 tag 是可回溯部署的底线:latest 是回滚事故的预定席位;
- 单 Master 是可用性预算的分配结果:省下的复杂度投给了监控与备份——下一篇的主角。
下一篇预告:运维篇·下——物理备份一键化:CentOS 7 离线装 XtraBackup 加 qpress 压缩、七天全量加每日增量链的备份策略、增量链的四连自愈修复(坏基准卡死、失败吞噬清理、孤儿链、在线 DDL 重试),以及那个比备份更重要的东西——恢复演练脚本。