2918 字
约 9 分钟
13
S15-A04 · 运行时选择:物理机、容器与编排的分界

运行时选型最常见的错误不是选错技术,而是默认往上走一层:单机能跑就上容器,容器多了就上编排,最后一套 8 个实例的系统养着一个控制面。运行时形态不是先进性的度量,它买的是"环境一致性、交付速度、扩缩能力",代价是"多一层抽象、多一层排障距离"。

判据只有一条:你要解决的问题,是不是这一层独有能解的。


1. 三层选择:各自解决什么,又引入什么

形态 独有能力 引入的新问题 谁该选它
裸机 / 虚机 直接掌控内核、IO、网络栈 环境漂移、交付靠手工 IO 敏感、需要特殊内核模块
容器 打包一致性、秒级启动、资源视图 网络与存储抽象、镜像治理、内核共享 无状态服务、多环境交付
编排 声明式副本、自动恢复、调度 控制面开销、概念负担、排障链路变长 实例多、发布频繁、要自动恢复
判断顺序(从下往上问,任一层"不需要"就停):
1) 这台机器上的东西,会经常换版本吗?      → 不会,裸机/虚机即可
2) 需要多环境一致、快速回滚吗?            → 需要,容器化
3) 实例数会超过一双手,且发布是常态吗?    → 是,才考虑编排

关键:每一层都只能解决它自己那一层的问题。容器不会让你的服务更有弹性——弹性来自无状态与快速启动;编排不会让你的发布更安全——安全来自可回滚与灰度。


2. 容器的四个收益与四个代价

收益 前提条件 代价 表现
环境一致 镜像自包含、依赖不外挂 网络与存储变复杂 端口映射、overlay、卷挂载
快速交付 构建流水线可靠 镜像治理 标签混乱、体积膨胀、基底过期
资源隔离 正确设置 limit 调试变难 容器内看不到宿主,工具缺失
扩缩 无状态、启动快 内核共享风险 一个容器打爆页缓存,全体受损
FROM eclipse-temurin:17-jre
COPY app.jar /app/app.jar
# 关键决策:进程 PID 1、时区、JVM 感知容器内存
ENTRYPOINT ["java", "-XX:MaxRAMPercentage=75", "-jar", "/app/app.jar"]
# 隔离的开关在这里,不在容器里
services:
  app:
    mem_limit: 1g
    cpus: 1.5
    pids_limit: 512

-XX:MaxRAMPercentage 这类参数的存在,本身就是"抽象漏了"的证据:JVM 曾经按宿主内存算堆,容器化后必须重新教它看 cgroup。任何依赖"看到真实硬件"的组件,容器化都要额外验证。


3. 什么时候不该上容器

场景 症状 更合适的做法
IO 敏感 磁盘吞吐打满,容器层叠加放大延迟 裸机 + 直连设备
特殊内核模块 需要加载自定义模块、调整内核参数 虚机或裸机
团队无运维能力 出问题只会重启 虚机 + 脚本化部署
单实例常驻小服务 一年不重启、不扩容 物理机 + systemd
离线批处理集群 任务排队、资源独占 队列 + 裸机

判断容器是否值得,问三个问题:版本更换频率、环境数量、是否需要隔离故障域。三个都低,容器只是给运维加了一层需要学习的东西。


4. 编排的门槛判据

判据 未达标的迹象 达标的迹象
实例数量 一只手数得过来 多服务 × 多副本,手工登记已不可行
发布频率 月级 周级或更高,需要灰度与回滚
故障恢复要求 人工介入可接受 要求自愈、自动重调度
团队规模 1–2 人全包 有明确的分工与值班
荒谬场景的最小反例:
一台 4C8G 的机器上跑单节点编排,控制面吃掉约四分之一资源,
换来的是——一个本来用 systemd 就能管好的进程。
判断:编排的收益随实例数增长,成本却是固定的(控制面 + 学习曲线)。

这就是判据的本质:编排是固定成本 + 规模收益。实例数没到规模,成本那一项永远算不过来。


5. 调度策略:requests、limits 与抢占

配置 对调度的影响 对稳定性的影响
requests 设小、limits 设大 调度器以为很空闲,超卖严重 高峰时集体限流与 OOM
requests = limits 可预测、可装箱 资源利用率偏低
不设 limits 无上限,邻居互相伤害 一个服务拖垮整台机器
亲和性过强 Pod 无法调度,长期 Pending 扩容失效,故障域集中
resources:
  requests: { cpu: "500m", memory: "512Mi" }   # 调度依据
  limits:   { cpu: "2",    memory: "1Gi" }     # 运行上限
# CPU 超限 = 被限流(变慢),内存超限 = 被杀(OOMKilled),两者故障表现完全不同

这条差别值得记住:CPU 超限是降速,内存超限是死亡。所以内存 limit 应该按实测峰值留余量,CPU limit 则常常干脆不设,让它在争抢中自然排队。


6. 有状态服务与发布方式的匹配

服务类型 容器化边界 关键约束
无状态 API 完全适合 启动快、健康检查准确
有状态(数据库) 谨慎,需卷与备份方案 迁移慢、恢复依赖快照
消息中间件 可容器化,但数据目录必须持久 卷性能直接决定吞吐
定时任务 适合,但要防重复执行 需要分布式锁或单例语义
发布方式 对基础设施的要求 适用形态
滚动 多副本 + 就绪探针 编排环境
蓝绿 两套环境 + 流量切换 编排或负载均衡
金丝雀 按比例分流能力 需要网关支持
原地重启 可接受停机 单机、无编排
# 发布安全性的最小前提:探针不说谎
readinessProbe:
  httpGet: { path: /health/ready, port: 8080 }
  initialDelaySeconds: 10
  periodSeconds: 5
livenessProbe:
  httpGet: { path: /health/live, port: 8080 }
  failureThreshold: 3

探针设计错了,滚动发布就变成"一边启动一边被杀"。就绪探针回答"能不能接流量",存活探针回答"要不要重启",两者混用是自愈变自杀的常见原因。


7. 超卖、隔离与可观测

问题 机制 观测方式
CPU 争抢 cgroup 配额与限流 容器 CPU throttling 指标
内存超卖 OOM Killer 按分值与用量选目标 OOMKilled 事件、重启计数
邻居效应 页缓存、磁盘 IO、网络带宽共享 宿主级 IO 等待与丢包
日志收集 容器内文件随生命周期消失 统一采集到外部存储
指标维度 容器名会变,实例会漂 以服务 + 版本打标
# 容器里看不到宿主,排障要回到宿主视角
docker stats --no-stream
cat /sys/fs/cgroup/memory.max            # cgroup v2;v1 为 memory.limit_in_bytes
kubectl top pod -n app

可观测的第一原则:指标标签不要用实例名或容器 ID——它们会变,一变历史曲线就断。用"服务 + 版本 + 区域",实例身份只作为附加维度。


8. 成本结构与迁移路径

成本项 固定/变动 容易忽略的部分
控制面开销 固定 每个节点上的常驻进程与内存预留
闲置资源 随规模 requests 虚高导致的装箱浪费
镜像存储与拉取 随版本数 大镜像让扩容变慢
人力 固定 学习与排障能力的建立周期
迁移路径(每步都可回退):
1) 无状态服务容器化,仍用脚本或 compose 部署
2) 引入镜像流水线 + 版本化标签 + 回滚演练
3) 有状态组件评估:能外置的(缓存、对象存储)先外置
4) 实例数与发布频率都过线后,再上编排
5) 最后才谈自动扩缩与多集群

顺序反了会怎样:先上编排再补镜像治理,等于把"环境不一致"从机器级搬到镜像级,问题没消失,只是更难查。


9. 排错

现象 原因 处理
容器频繁重启 存活探针过严或内存 limit 过低 看退出码:137 多为 OOM
启动慢、流量打不进 就绪探针早于应用就绪 加启动探针或延长初始延迟
容器内 CPU 用不满 CPU limit 限流 去掉 limit 或按峰值设
写入变慢但磁盘不满 卷性能或 IO 争抢 看宿主 IO 等待
Pod 长期 Pending 资源请求超出节点可分配 查 requests 与亲和性
日志缺失 采集器未覆盖或容器已销毁 改为采集到外部存储

10. 边界

场景 不该做的事 理由
单机小服务 上编排 固定成本永远收不回
长期稳定、不扩容的系统 为"先进"而容器化 收益为零,风险为正
离线批处理 用编排做任务队列 调度语义不匹配,排队与重试难控
强 IO 依赖组件 叠多层存储抽象 每层都加延迟
团队无运维能力 引入需要专人维护的平台 故障时会失去排障能力

一句话收束:运行时形态应该由"故障恢复与交付节奏"的需求拉动,而不是由技术潮流推动。选低一层的代价通常是手工,选高一层的代价通常是复杂度——哪种代价你更能长期承担,答案就出来了。


11. 自测

  1. 容器的"环境一致"收益,依赖哪个前提才成立?
  2. 为什么 CPU 超限和内存超限的故障表现完全不同?
  3. 编排的成本是固定的还是随规模变化的,这如何影响门槛判据?
  4. 就绪探针与存活探针混用,会把自愈变成什么?
  5. 有状态服务容器化,最先要解决的是卷、备份还是迁移?
  6. 迁移路径为什么强调"先无状态、后有状态、最后编排"?
S15-A04 · 运行时选择:物理机、容器与编排的分界
https://www.clxhxhhr.top/posts/6087/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。