3. 医疗容器集群部署与初始化
医疗容器集群与通用互联网集群最大的区别,不在于 Kubernetes 本身,而在于它承载的业务具有强合规、强连续性和强数据敏感性。HIS、LIS、PACS、EMR 等系统一旦中断,直接影响门急诊与住院业务;患者影像与检验数据一旦泄露,涉及《个人信息保护法》与等保 2.0 的合规责任。因此本章的部署目标不是"能跑起来",而是"规划可审计、节点可隔离、运行时可控、网络可追溯、存储可恢复"。
一、生产级集群规划:先定边界,再定规模
规划的第一步是划分集群边界。建议按业务域拆分为三个逻辑集群:核心诊疗集群(HIS、EMR、LIS,要求最高可用性)、影像与检验集群(PACS、RIS,特点是高吞吐、大存储)、对外服务集群(互联网医院、预约挂号、报告查询,暴露在 DMZ)。三者之间通过 API 网关或消息队列通信,不共享 etcd,避免一个集群的故障域扩散到全院。
规模估算要落到具体参数。以核心诊疗集群为例,假设日均门诊 8000 人次、峰值并发 1200 会话,按每会话 0.15 vCPU、256 MiB 内存估算,业务负载约需 180 vCPU、300 GiB 内存。考虑 1.5 倍冗余与 30% 预留,控制面 3 节点(4 vCPU / 16 GiB / SSD),工作节点起步 6 台(16 vCPU / 64 GiB / NVMe),后续按节点池横向扩展。etcd 必须使用独立 SSD,且与 kubelet 数据盘物理分离,否则镜像拉取 IO 会拖垮 etcd 的 fsync 延迟——这是生产环境最常见的隐性故障源。
二、节点角色分配:用标签与污点固化隔离
节点角色不能只靠命名区分,必须通过 label 与 taint 强制约束。推荐的角色划分如下:
- control-plane:3 台,仅运行 apiserver、controller-manager、scheduler、etcd,打上
node-role.kubernetes.io/control-plane并设置NoSchedule污点。 - infra:2~3 台,承载 Ingress Controller、CoreDNS、监控、日志、镜像仓库代理,标签
role=infra。 - app-core:承载 HIS/EMR 等核心业务,标签
role=app-core,配合 PodDisruptionBudget 保证滚动升级时至少 2 副本在线。 - app-pacs:承载影像处理,标签
role=app-pacs,节点需挂载大容量本地盘或直连存储。 - edge:DMZ 区对外服务节点,标签
role=edge,网络策略最严格。
污点与容忍的典型写法:
kubectl taint nodes node-infra-01 role=infra:NoSchedule
kubectl label nodes node-core-01 role=app-core
# 业务 Pod 中声明
tolerations:
- key: "role"
operator: "Equal"
value: "infra"
effect: "NoSchedule"
nodeSelector:
role: "app-core"
这样即使调度器出现异常,核心业务也不会被挤到 DMZ 节点上,满足等保对区域边界隔离的要求。
三、容器运行时选型:containerd 为主,兼顾合规审计
自 Kubernetes 1.24 起 Dockershim 被移除,生产环境应直接选用 containerd 作为 CRI 运行时。相比 Docker,containerd 组件更少、调用链更短、资源开销更低,且原生支持 CRI。配置要点是启用 SystemdCgroup 驱动,避免与 kubelet 的 cgroup 管理冲突:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
runtime_type = "io.containerd.runc.v2"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
对于多租户或需要更强隔离的影像处理任务,可额外配置 gVisor 或 Kata Containers 作为 RuntimeClass,通过 runtimeClassName: kata 按 Pod 粒度选择。医疗场景还需关注镜像来源合规:所有镜像必须来自院内 Harbor 私服,开启镜像签名与漏洞扫描,禁止直接拉取公网镜像。
四、网络插件与存储插件安装
网络插件推荐 Calico,原因是它同时提供 BGP 路由与 NetworkPolicy,能满足医疗环境"默认拒绝、按需放通"的东西向管控要求。安装时选择 IPIP 或 VXLAN 模式需与院内网络团队确认:若底层是传统三层网络且不允许 BGP 穿透,选 VXLAN;若机房支持 BGP 且追求性能,选 BGP 直连。安装后必须验证跨节点 Pod 互通与 NetworkPolicy 生效:
kubectl apply -f calico.yaml
kubectl get pods -n kube-system -l k8s-app=calico-node
# 验证策略:默认拒绝后,仅放通 8080
kubectl apply -f deny-all.yaml
kubectl exec -it test-pod -- curl http://svc-his:8080
存储插件方面,核心业务使用 Ceph RBD 或商用 SAN 提供的 CSI 驱动,保证块存储的低延迟与快照能力;PACS 影像建议使用 NFS 或对象存储 CSI,配合生命周期策略将冷数据下沉。StorageClass 必须区分性能等级,例如 sc-gold(SSD,核心库)、sc-silver(SAS,一般业务)、sc-archive(大容量,影像归档),并通过 volumeBindingMode: WaitForFirstConsumer 避免跨可用区调度失败。
五、医疗环境部署检查清单
集群初始化完成后,必须逐项验证,不能只看 Pod 是否 Running。以下清单按"基础设施—运行时—网络—存储—合规"五类组织,每项都给出可执行的判断依据:
| 类别 | 检查项 | 判断依据 |
|---|---|---|
| 基础设施 | etcd 健康与延迟 | etcdctl endpoint health 全部 healthy,fsync 延迟 < 10ms |
| 基础设施 | 节点资源预留 | kubelet 配置 --system-reserved 与 --kube-reserved,避免系统进程被 OOM |
| 运行时 | containerd cgroup 驱动 | SystemdCgroup = true,与 kubelet 一致 |
| 运行时 | 镜像来源合规 | 所有镜像来自院内 Harbor,签名验证通过,无 latest 标签 |
| 网络 | 跨节点 Pod 互通 | 不同节点 Pod 互 ping 成功,延迟 < 1ms |
| 网络 | NetworkPolicy 生效 | 默认拒绝后,未放通的端口访问超时 |
| 存储 | StorageClass 绑定 | PVC 能成功 Bound,Pod 重启后数据不丢失 |
| 存储 | 快照与恢复 | VolumeSnapshot 可创建并成功恢复到新 PVC |
| 合规 | 审计日志 | apiserver 审计策略开启,日志留存 ≥ 180 天 |
| 合规 | 区域隔离 | DMZ 节点与内网节点间无直接路由,仅经网关通信 |
kubectl describe pod 的 Events。医疗集群最常见的原因是 PVC 因 WaitForFirstConsumer 等待调度、节点污点与 tolerations 不匹配、或资源预留后实际可分配量不足。不要急于扩容节点,先确认调度约束是否自相矛盾。