Amazon SAA-C03: 容器与编排 — 学习指南
属于 AWS SAA-C03 — 完整学习指南. 使用经过验证的答案练习: Amazon 考试中心, 或参加限时模拟考试: ExamRoll.io.
在 ECS 和 EKS 之间、以及在 EC2 和 Fargate 之间进行选择
对于 AWS 上的任何容器工作负载,首要的架构决策是选择编排器和计算模式。Amazon ECS 是 AWS 的专有编排器,与 IAM、ALB/NLB、CloudWatch、Service Discovery 和 VPC 网络紧密集成。它没有控制平面费用,对于不需要 Kubernetes 特定工具的团队来说,是投入生产的最快路径。任务(Task)是一个或多个共享生命周期的容器单元;服务(Service)是由调度器支持的、长期运行的托管任务集。Amazon EKS 运行上游兼容的 Kubernetes,每个集群每小时收费 0.10 美元,当工作负载必须保持可移植性、使用 Kubernetes API 或利用 CNCF 生态系统(Helm、CRD、Operator)时,它是正确的选择。控制平面——API server、etcd、controller manager、scheduler——由 AWS 负责打补丁、备份,并在三个可用区(AZ)中实现高可用性。
两种编排器都支持两种计算模式。AWS Fargate 在隔离的 Firecracker 微虚拟机上运行每个任务或 Pod;无需修补 AMI,无需调整 Auto Scaling Group 容量提供程序,无需进行 bin-packing(装箱)决策,也没有可通过 SSH 访问的主机。您按任务的 vCPU-秒和 GB-秒付费。EC2 启动类型 / 托管节点组意味着您拥有这些实例,并随之带来了灵活性和运维负担。
只要工作负载符合其限制:每个任务最大 16 vCPU / 120 GB 内存、无 GPU、无特权容器、无 DaemonSet、无 HostPort/HostNetwork、无 Windows 主机级自定义,那么在任何强调“无服务器”、“最少运维开销”或“无需管理基础设施”的场景下,Fargate 都是正确的默认选择。当您需要 GPU、需要主机访问权限的 DaemonSet、自定义 AMI、使用 GMSA 的 Windows Server 容器、亚秒级的 bin-packing(装箱)效率或激进的基于 Spot 的成本优化时,请选择托管节点组或 EC2 启动类型。
| 需求 | 正确选择 |
|---|---|
| Kubernetes API + 上游工具 | EKS |
| 最简单的 AWS 原生编排器 | ECS |
| 无需基础设施管理 | Fargate (两种编排器均可) |
| GPU、DaemonSet、自定义内核模块 | 托管节点组 / EC2 |
| 使用 GMSA 的 Windows 容器 | EC2 启动类型 |
| 大规模的基于 Spot 的成本优化 | 使用 Spot 的托管节点组 |
| EKS 上由 EBS 支持的持久卷 | 托管节点组 |
| 突发性、不可预测的 Pod | Fargate |
一个典型的陷阱是选择 EC2 节点,因为它们“感觉上”更便宜。对于有尖峰或利用率低的工作负载,如果将闲置容量以及用于 AMI 修补、节点排空和集群自动扩缩容配置的工程时间——所有这些 Fargate 都已为您免除——考虑在内,Fargate 通常更便宜。
任务定义、放置和容量提供程序
一个典型的 ECS Fargate 任务定义包含了基本要素——CPU/内存大小、用于拉取镜像和写入日志的执行角色、awsvpc 网络模式以及 CloudWatch Logs 配置:
family: checkout-service
requiresCompatibilities: [FARGATE]
networkMode: awsvpc
cpu: "1024"
memory: "2048"
executionRoleArn: arn:aws:iam::111122223333:role/ecsTaskExecutionRole
containerDefinitions:
- name: checkout
image: 111122223333.dkr.ecr.us-east-1.amazonaws.com/checkout:1.4.2
portMappings: [{ containerPort: 8080 }]
logConfiguration:
logDriver: awslogs
options:
awslogs-group: /ecs/checkout
awslogs-region: us-east-1
在带有 EC2 的 ECS 上,任务放置策略决定了任务如何在实例间分布。它们按顺序组合:
| 策略 | 行为 | 典型用途 |
|---|---|---|
spread | 在某个字段上均匀分布 (例如, attribute:ecs.availability-zone) | 跨 AZ 的高可用性 |
binpack | 按 CPU 或内存打包到最少的实例上 | 成本优化 |
random | 随机放置 | 很少适用 |
使用集群查询语言的放置约束(如 distinctInstance 或 memberOf)会进一步限制候选实例。
容量提供程序将服务与底层的 Auto Scaling Group 解耦。FARGATE 和 FARGATE_SPOT 是托管提供程序;自定义提供程序则包装一个 ASG 并启用托管扩展,这样 ECS 就可以根据预置的任务数量来调整 ASG 的期望计数。容量提供程序策略根据权重和基数来分配任务——例如,保证两个任务在按需 Fargate 上运行,并将其余任务以 1:4 的比例分配给 Fargate Spot,以用于可容忍中断的工作负载:
capacityProviderStrategy:
- capacityProvider: FARGATE
base: 2
weight: 1
- capacityProvider: FARGATE_SPOT
weight: 4
自动扩缩容:Pod、任务和节点
Fargate 免去了节点管理,但它不会自动扩展任务或 Pod 的数量。这个区别是关于 Fargate 最常被误解的一点:无服务器适用于主机层,而绝不适用于您服务的期望计数。您仍然需要负责服务级别的自动扩缩容。
对于 ECS,请使用 Application Auto Scaling。目标跟踪是惯用的默认方式,因为它会自动创建扩展(scale-out)和缩减(scale-in)的 CloudWatch 警报,并遵循冷却时间。合理的指标包括 ECSServiceAverageCPUUtilization、ECSServiceAverageMemoryUtilization 和 ALBRequestCountPerTarget:
aws application-autoscaling register-scalable-target \
--service-namespace ecs \
--resource-id service/prod-cluster/checkout \
--scalable-dimension ecs:service:DesiredCount \
--min-capacity 2 --max-capacity 30
aws application-autoscaling put-scaling-policy \
--policy-name cpu-target-50 \
--service-namespace ecs \
--resource-id service/prod-cluster/checkout \
--scalable-dimension ecs:service:DesiredCount \
--policy-type TargetTrackingScaling \
--target-tracking-scaling-policy-configuration \
'{"TargetValue":50.0,"PredefinedMetricSpecification":{"PredefinedMetricType":"ECSServiceAverageCPUUtilization"}}'
对于非线性响应曲线或已知的流量窗口,步进扩展和计划扩展仍然可用。
对于 EKS on EC2 节点,Pod 维度的扩缩容由 Horizontal Pod Autoscaler (HPA) 处理,它根据 CPU、内存或自定义指标调整副本数。仅 HPA 本身无法添加节点——它会很乐意地将副本数增加到超出集群容量,此时新的 Pod 将进入 Pending 状态并伴有 FailedScheduling 事件。这就是为什么在 EC2 上的 HPA 必须始终与 Kubernetes Cluster Autoscaler 或 Karpenter 配对使用。忘记这种配对是一个常见的设计错误:HPA 报告“已扩展到 20 个副本”,而其中一半却卡在 pending 状态。一个最小化的 Cluster Autoscaler 配置通过 ASG 标签来发现节点组:
- --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/prod-eks
- --balance-similar-node-groups
- --skip-nodes-with-system-pods=false
在 Fargate profile 上,这个问题就消失了——每个 Pod 都成为其自己的微虚拟机,因此节点扩缩容这个维度被完全消除了。这恰恰解释了为什么对于具有不可预测 Pod 数量的突发性工作负载,Fargate 是正确的选择。
Fargate Profile 及其功能限制
EKS 中的 Fargate profile 是一个选择器——由命名空间和可选的 pod 标签组成——它指示 EKS 将匹配的 pod 调度到 Fargate 上,而不是节点上:
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata: { name: microservices, region: us-east-1 }
fargateProfiles:
- name: fp-app
selectors:
- namespace: app
labels: { compute: fargate }
关键的注意事项是,EKS on Fargate 并不支持完整的 Kubernetes 功能集:
- DaemonSets 无法运行。 由于没有节点可以运行守护进程,像
fluentd这样的日志收集器 DaemonSets 必须被替换为 sidecar 容器或内置的 Fluent Bit 日志路由器。 - 特权容器、HostPort 和 HostNetwork 不可用。
- 持久化存储仅限于 EFS(通过 CSI 驱动程序)。不支持 EBS,因为 EBS 卷需要挂载到特定的 EC2 实例上。
- 不支持 GPU 工作负载。
NodePort服务以及依赖特权 init 容器的服务网格无法工作。
如果想当然地认为功能对等,则会导致需要 EBS 的 StatefulSets、使用 hostPort 的 ingress 控制器或 GPU 推理工作负载在迁移时失败。
Ingress:通过 AWS Load Balancer Controller 使用 ALB vs NLB
AWS Load Balancer Controller 是一个 Kubernetes 控制器,可将 Ingress 和 Service 对象转换为实际的 ALB 和 NLB。对于需要基于路径或主机进行路由的 HTTP/HTTPS 微服务,应创建一个 alb 类型的 Ingress。一个 ALB 前端代理多个服务(通过 alb.ingress.kubernetes.io/group.name)比每个服务一个 ALB 要便宜得多,是典型的成本效益模式:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shop
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/group.name: shop
spec:
rules:
- http:
paths:
- path: /customers
pathType: Prefix
backend: { service: { name: customers, port: { number: 80 }}}
- path: /orders
pathType: Prefix
backend: { service: { name: orders, port: { number: 80 }}}
对于 TCP、UDP、TLS 直通、静态 IP 需求或极高的第 4 层吞吐量场景,应使用 NLB(类型为 LoadBalancer 的 Service,并带有 service.beta.kubernetes.io/aws-load-balancer-type: external 注解和 nlb-ip 目标类型)。将基于 HTTP/2 的 gRPC 或纯 TCP 数据库代理置于 ALB 之后仅对 gRPC 可行(因为 ALB 支持 HTTP/2 和 gRPC);ALB 无法终止任意 TCP 或任何 UDP 流量。试图通过 ALB 为 UDP 游戏流量提供服务是一种协议不匹配,必须在设计阶段就发现。
使用 IRSA 实现 Pod 级别的 IAM
IAM Roles for Service Accounts (IRSA) 是为单个 pod 授予 AWS API 权限的正确机制。通过附加节点的实例配置文件来赋予 pod S3 访问权限是错误的做法,因为节点上的每个 pod 都会继承这些权限,这违背了最小权限原则。IRSA 的工作原理是将集群的 OIDC 提供商与 IAM 进行联合:只需创建一次 OIDC 提供商,然后创建一个 IAM 角色,其信任策略信任该提供商以及一个特定的 namespace:serviceaccount 主体。
eksctl utils associate-iam-oidc-provider --cluster prod --approve
eksctl create iamserviceaccount \
--cluster prod --namespace payments --name orders-sa \
--attach-policy-arn arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess \
--approve
服务账户通过 eks.amazonaws.com/role-arn: arn:aws:iam::...:role/orders-role 注解进行配置,挂载了该服务账户的 pod 会通过一个投射令牌(projected token)接收到短期的 STS 凭证。如果跳过了 OIDC 提供商关联步骤或遗漏了该注解,系统将静默地回退到使用节点角色——这是一个在审查中很容易被忽略的、细微的安全倒退。
VPC CNI 插件 对此进行了补充,它为每个 pod 分配一个 VPC 子网内的可路由 ENI/IP 地址。这样,pod 就可以使用安全组直接与 RDS、ElastiCache 或 VPC 端点通信,并且 CloudTrail 在审计时能看到 pod 的真实 IP。
持久化存储和临时存储
存储的选择取决于访问模式、持久性和启动类型。
EBS(在 EKS 上通过 EBS CSI 驱动程序,或在 ECS 上通过任务附加的 EBS)为单 pod 有状态工作负载(如 Postgres 主库)提供 ReadWriteOnce 的块存储卷。EFS 提供 ReadWriteMany 的 NFS 存储,它是区域性的、跨多可用区的,并且可以被多个 pod 同时挂载——当需求中提到“高可用、容错、多容器共享”或共享机器学习产物时,这是正确的选择。FSx for Lustre 用于处理高吞吐量的 HPC 场景;FSx for NetApp ONTAP 和 FSx for Windows File Server 用于处理企业级 NFS/SMB 需求。
Fargate 任务默认获得 20 GB 的临时存储,在平台版本 1.4.0+ 上可通过 ephemeralStorage.sizeInGiB 配置最高 200 GB。认为 Fargate 总有“足够临时空间”是一个陷阱:一个会写入 50 GB 中间文件的供应商容器可能适合扩展后的临时存储,但如果需求是 50 GB 的共享或持久存储(跨任务重启或跨多个任务),那么临时存储就是错误的选择,因为它在任务停止时会被销毁且从不共享。Fargate 不支持 EBS。 如果 Fargate 工作负载需要持久化或共享存储,EFS 基本上是唯一支持的选项。
对于 ECS,直接在任务定义中挂载 EFS;访问点为每个任务强制执行 POSIX UID/GID 和根目录,从而在单个文件系统上提供安全的多租户隔离,并且 IAM 授权可以限定 elasticfilesystem:ClientMount 范围:
"volumes": [{
"name": "scratch",
"efsVolumeConfiguration": {
"fileSystemId": "fs-0abc123",
"transitEncryption": "ENABLED",
"authorizationConfig": {
"accessPointId": "fsap-0def456",
"iam": "ENABLED"
}
}
}],
"containerDefinitions": [{
"name": "app",
"mountPoints": [{
"sourceVolume": "scratch",
"containerPath": "/data"
}]
}]
对于 EKS,通过 StorageClass 来配置 EFS:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata: { name: efs-sc }
provisioner: efs.csi.aws.com
parameters:
provisioningMode: efs-ap
fileSystemId: fs-0123456789abcdef0
directoryPerms: "700"
一个常见的陷阱是:为有状态工作负载选择 Fargate,却忘记安装 EFS CSI 驱动程序和创建 StorageClass——这会导致 pod 启动但 PersistentVolumeClaims 永远处于 Pending 状态。反之,当需求是共享的多写存储时,仅仅为了挂载 EBS 而选择 EC2 节点也是错误的;挂载到单个节点上的 EBS io2 卷无法跨可用区共享。
ECR 镜像扫描和生命周期
Amazon ECR 提供两种扫描模式。基本扫描使用开源的 Clair 数据库,在推送时(或按需)运行,不收取费用。增强型扫描集成了 Amazon Inspector,持续监控操作系统和语言包的 CVE,并将发现结果报告到 Security Hub。对于“扫描 CVE、在新镜像创建时扫描、对工作负载改动最少”这类需求,正确的操作是在存储库级别启用推送时扫描(scan on push)——这不需要更改流水线,因为推送事件本身就会触发扫描:
aws ecr put-image-scanning-configuration \
--repository-name payments-api \
--image-scanning-configuration scanOnPush=true
然后,CI/CD 流程可以调用 describe-image-scan-findings,并在发现 CRITICAL 或 HIGH 级别的漏洞时使构建失败。跳过扫描意味着未修补的 Log4j、OpenSSL 或 glibc CVE 会在生产环境中运行;不扫描的缓解成本远超启用扫描的近零成本。
生命周期策略可以控制存储成本并强制执行标签规范:
{
"rules": [{
"rulePriority": 1,
"selection": {
"tagStatus": "untagged",
"countType": "sinceImagePushed",
"countUnit": "days",
"countNumber": 14
},
"action": { "type": "expire" }
}]
}
迁移 Kubernetes + MongoDB 工作负载
在“不更改应用程序代码”和“最小化运维开销”的约束下,将自托管的 Kubernetes + MongoDB 技术栈“直接迁移”(lift-and-shift)到 AWS 时,有两个决策方向是一致的。首先,计算层迁移到 EKS,因为 Kubernetes API 的兼容性意味着清单(manifests)和 Helm charts 可以无需更改即可移植;对无状态服务使用 Fargate profiles,以消除节点所有权的负担。
其次,MongoDB 本身不应重新托管在自管理的 EC2 或 StatefulSets 上——这会重新引入备份、分片、故障转移和补丁管理等运维负担。应使用 Amazon DocumentDB (with MongoDB compatibility),它支持 MongoDB 3.6/4.0/5.0 的有线协议,因此现有的驱动程序和连接字符串只需极少更改即可工作。
兼容性方面的注意事项很重要。DocumentDB 模拟了 MongoDB 的 API 接口,但它并非 MongoDB。某些聚合运算符、特定的索引类型、变更流(change stream)的语义以及较新 MongoDB 版本中引入的功能可能会失败。正确的迁移前步骤是,使用 DocumentDB 兼容性工具(compat.py)对应用程序进行扫描,以确认每个操作都受支持。如果选择 DynamoDB,将迫使进行数据模型重写;如果选择 RDS,则会完全破坏文档模型。这两种选择都违反了“不更改代码”的约束。
混合云选项:ECS Anywhere 和 EKS Anywhere
ECS Anywhere 将本地服务器(或其他云的虚拟机)作为外部实例注册到一个 ECS 集群中。控制平面保留在 AWS 中;外部实例上的 SSM Agent 和 ECS Agent 会向外连接到 AWS。只需一个部署流水线、一个任务定义和一套 IAM 角色,即可覆盖云端和本地的工作负载。
EKS Anywhere 在您的硬件(通常是 vSphere 或裸金属)上安装一个合规的 Kubernetes 发行版,并可选择通过 EKS Connector 在 AWS 控制台中获得可见性。当需要一个基于任务定义的轻量级混合模式时,选择 ECS Anywhere;当法规或延迟约束要求在本地部署 Kubernetes,并希望使用与云上 EKS 相同的工具链时,选择 EKS Anywhere。两者都保持了编排的一致性——其根本价值在于团队可以避免维护两套 CI/CD 系统或两种心智模型。
使用 EKS Connector 实现多集群可见性
企业经常会混合运行 EKS 集群、EC2 上的自管理 Kubernetes 集群以及本地集群。Amazon EKS Connector 可以将任何合规的 Kubernetes 集群注册到 EKS 控制台中,从而为节点、工作负载和集群元数据提供一个单一管理平台。它本质上是一个轻量级代理加上一个 SSM 通道——是实现“所有集群的集中视图”的低开销解决方案。使用自托管的 Rancher、Anthos 或自定义的 Prometheus/Grafana 联邦来构建等效的可见性是可行的,但运维成本要高得多,并且无法与 IAM 或基于控制台的访问集成。
EKS Connector 严格来说只是一个可见性层;它不管理或升级远程集群,这正符合“以最低开销实现集中视图”的含义。
综合运用这些模式
对于一个包含负载均衡前端、容器化中间层和关系型存储的电子商务工作负载,如果标准是“尽可能少的人工干预”,那么典型的技术栈是 ALB → ECS on Fargate → Aurora Serverless v2。每一层都消除了实例级别的所有权:ALB 是完全托管的,Fargate 无需管理主机,而 Aurora Serverless v2 以 ACU 为单位进行扩展,无需调整实例大小。
对于一个团队“无法管理额外基础设施”的微服务平台,正确的组合是 ECS 或 EKS 与 Fargate,再加上一个完全托管的数据服务。选择 EC2 启动类型或自管理节点组,尽管技术上工作负载也能运行,但这与约束条件相矛盾。
对于 Kubernetes + MongoDB 的直接迁移,答案最终会选择 EKS + DocumentDB:Kubernetes API 保留了部署方法,DocumentDB 保留了驱动程序的兼容性,而 Fargate profiles 则保持了最低的运维开销——前提是工作负载所使用的 Kubernetes 功能和 MongoDB 命令接口都落在上述支持的范围内。
← 计算、Auto Scaling 与实例管理 · 所有领域 · 无服务器与事件驱动架构 →
练习这些题目 → · 在 ExamRoll.io 上限时练习 →
Pass the whole exam — not just this question
You found this answer. Get every verified question and explanation in one place, and save hours of prep. Free to start.
通过考试 →