2. 容器化基础与AWS服务选型

容器化应用平台的第一步,不是立刻创建集群,而是把“镜像、运行时、编排、托管边界”四件事分清楚。Docker 镜像是一个只读的分层文件系统模板,容器则是镜像被运行时实例化后的可写进程沙箱。理解这一点,才能理解为什么 ECR 只负责存镜像、ECS/EKS 负责调度、Fargate 负责把底层节点隐藏掉。

镜像与容器运行时:从分层到进程

Docker 镜像由若干只读层叠加而成,每一层对应 Dockerfile 中的一条指令。例如一个 Node.js 应用的镜像通常包含:基础镜像层(如 node:20-alpine)、依赖安装层(npm ci)、源码复制层、启动命令层。容器启动时,运行时在镜像顶部加一个可写层,所有写操作先落在这一层,删除容器即可丢弃。这种“分层复用 + 写时复制”的机制,使多个容器可以共享同一镜像的只读层,显著减少磁盘占用和拉取时间。

容器运行时负责把镜像变成进程。以 Docker 为例,docker run 会依次完成:拉取镜像、创建可写层、配置命名空间(PID、网络、挂载、UTS、IPC)、设置 cgroups 资源限制、执行 ENTRYPOINT/CMD。在 AWS 上,ECS 使用 containerd 或 Docker 作为运行时,EKS 默认使用 containerd。运行时差异会影响镜像格式兼容性、启动速度和日志采集方式,因此选型时要确认镜像是否遵循 OCI 标准。

镜像构建的关键实践是:使用多阶段构建减小体积、固定基础镜像 tag 避免漂移、把不常变的层放在前面以利用缓存、用 .dockerignore 排除无关文件。一个典型的多阶段构建示例:

FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/server.js"]

构建完成后,镜像需要推送到镜像仓库。ECR 是 AWS 的托管镜像仓库,支持私有仓库、跨区域复制、镜像扫描和生命周期策略。推送命令通常为:

aws ecr get-login-password --region ap-southeast-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-southeast-1.amazonaws.com
docker build -t myapp:1.0.0 .
docker tag myapp:1.0.0 123456789012.dkr.ecr.ap-southeast-1.amazonaws.com/myapp:1.0.0
docker push 123456789012.dkr.ecr.ap-southeast-1.amazonaws.com/myapp:1.0.0

推送成功后,ECR 中会出现带 tag 的镜像。建议同时打上 Git commit SHA 作为不可变 tag,并开启扫描,以便在部署前发现基础镜像漏洞。

ECS、EKS、Fargate、ECR 的定位与选型

ECR 是“仓库”,不参与运行;ECS 和 EKS 是“编排控制面”,决定容器跑在哪里、跑几个、如何扩缩;Fargate 是“计算启动类型”,它让 ECS 或 EKS 不需要管理 EC2 节点。四者不是互斥关系,而是可以组合:ECR + ECS + Fargate、ECR + EKS + Fargate、ECR + EKS + EC2 都是常见组合。

ECS 是 AWS 原生编排服务,概念少、上手快,适合团队规模不大、希望减少 Kubernetes 学习成本的场景。EKS 是托管 Kubernetes,适合已经使用 K8s 生态、需要 Helm、Operator、CRD、多集群联邦或跨云一致性的团队。Fargate 适合不想管理节点、任务负载波动大、希望按 vCPU/内存秒级计费的场景;EC2 启动类型适合需要 GPU、特殊实例族、DaemonSet 或对成本做精细控制的场景。

选型时可以用四个问题快速判断:第一,团队是否已有 Kubernetes 运维能力?有则优先 EKS,没有则 ECS 更稳。第二,是否需要 GPU、Windows 容器或特权容器?需要则排除 Fargate。第三,负载是否长期稳定且资源利用率高?稳定高负载用 EC2 更省,波动负载用 Fargate 更省心。第四,是否需要跨云或本地一致?需要则 EKS 更合适。

容器化平台四层职责与选型路径 ECR 镜像仓库 存储 / 扫描 / 复制 ECS AWS 原生编排 Task / Service / Cluster EKS 托管 Kubernetes Pod / Deployment / CRD Fargate 无服务器计算 按 vCPU / 内存计费 EC2 启动类型 自管节点 GPU / 特权 / DaemonSet 推送镜像 二选一 可搭配 可搭配 选型判断路径 已有 K8s 能力? 需要 GPU/特权? 负载长期稳定? 跨云一致? 是 → EKS 否 → ECS 是 → EC2 启动类型 否 → Fargate 是 → EC2 更省 否 → Fargate 更省心 是 → EKS 否 → ECS

选型决策的量化参考

除了定性判断,还可以用成本模型辅助决策。假设一个服务需要 2 vCPU、4 GB 内存,每天运行 24 小时,每月 730 小时。Fargate 在 ap-southeast-1 的示例价格约为每 vCPU-小时 0.04048 美元、每 GB-小时 0.004445 美元,则月成本约为:2 × 0.04048 × 730 + 4 × 0.004445 × 730 ≈ 59.1 + 13.0 = 72.1 美元。若使用 EC2 的 m5.large(2 vCPU、8 GB)按需约 0.096 美元/小时,月成本约 70.1 美元,但可承载更多内存余量;若购买 1 年期 Savings Plan,可降至约 45 美元。这说明:当资源利用率高且负载稳定时,EC2 或 Savings Plan 更经济;当负载波动、需要快速伸缩时,Fargate 的按秒计费和零节点运维更有优势。

ECR 的成本主要来自存储和跨区域数据传输。镜像层数多、tag 多会累积存储费用,建议配置生命周期策略,例如“保留最近 10 个 tag,超过 30 天未拉取的镜像自动删除”。跨区域复制会产生传输费用,只在多区域部署时才开启。

选型不是一次性的。初期用 ECS + Fargate 快速上线,当团队具备 K8s 能力、需要多集群治理时,再迁移到 EKS;迁移时镜像和 ECR 可以保持不变,主要改的是编排定义和网络模型。

常见误区与检查点

第一个误区是把 ECR 当成运行时。ECR 只存镜像,容器启动必须由 ECS、EKS 或 EC2 上的 Docker 完成。第二个误区是认为 Fargate 支持所有容器特性。Fargate 不支持特权容器、GPU、DaemonSet、HostNetwork,也不支持挂载 EBS 以外的块存储。第三个误区是忽略镜像架构。Fargate 和 Graviton 实例需要 arm64 镜像,若本地构建的是 amd64,部署时会报 exec format error,需要用 docker buildx 构建多架构镜像。

部署前建议检查:镜像是否推送到 ECR 且 tag 不可变;任务定义中的 CPU/内存是否符合 Fargate 允许的组合(如 0.25 vCPU 只能配 0.5/1/2 GB);容器端口是否与负载均衡目标组一致;日志是否配置到 CloudWatch Logs;执行角色是否有拉取 ECR 镜像和写日志的权限。这些检查点能避免大部分首次部署失败。

总结来说,ECR 解决“镜像放哪里”,ECS/EKS 解决“谁来编排”,Fargate/EC2 解决“跑在什么算力上”。先明确团队能力、负载特征和合规要求,再组合这四者,才能得到既不过度设计也不欠扩展的容器平台底座。