AWS ECR:您的 ECS Fargate 所需的容器镜像库(以及为什么它在崩溃前总是隐形的)

AWS ECR:您的 ECS Fargate 所需的容器镜像库(以及为什么它在崩溃前总是隐形的)

在 AWS 中管理镜像拉取、IAM 权限和账单的实用指南

什么是 AWS ECR 以及为什么要关注它?

AWS ECR (Elastic Container Registry) 是亚马逊的托管容器镜像存储服务。您可以把它看作是内置于 AWS 中的私有 Docker Hub。每次在 ECS Fargate 上运行容器时,任务都必须从 某个地方 拉取镜像——而 ECR 正是大多数团队存放镜像的地方。

在 2026 年 7 月 1 日,容器编排已成为任何严肃云部署的基本要求。如果您正在运行 ECS Fargate,您几乎肯定也在使用 ECR。但问题在于:ECR 有点像隐形的存在。它一直默默工作直到崩溃,而当它崩溃时,错误信息却毫无帮助。任务启动失败并提示 ResourceInitializationError。您的队友耸耸肩。六个月后,您发现镜像库中堆积了五年未打标签的镜像,悄无声息地每月向您收取 400 美元的存储费用。本指南涵盖了 ECR 文档中一带而过的部分:拉取操作的实际工作原理、私有子网任务失败的原因,以及如何保持合理的账单费用。

ECR 如何与 ECS Fargate 协同工作

当 ECS Fargate 任务启动时,它需要拉取一个容器镜像。该任务在本地没有安装 Docker——它运行在亚马逊的托管基础设施上。因此,Fargate 代理会连接到 ECR,进行身份验证并下载镜像。

这种身份验证是无人提及的关键环节。您的 Fargate 任务不会使用用户名和密码登录。相反,它使用 IAM 角色——具体来说,就是您分配给任务的执行角色 (execution role)。ECR 会检查该角色的权限。如果该角色能够读取镜像,那就没问题。如果不能,任务会近似静默地失败(您会收到一个通用的错误提示)。

ECR 也是存在于特定的 AWS 区域中的。如果您的任务在 us-east-1 而您的镜像在 eu-west-1,不进行额外配置任务就无法拉取它。这通常不是什么大问题,但值得了解。

IAM 权限:无形的墙

这是大多数人跌倒的地方。您的 ECS 任务需要一个执行角色——它用来拉取镜像、写入日志以及与其他 AWS 服务通信的身份。该角色需要特定的权限才能从 ECR 读取数据。

最低限度的权限看起来像这样:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ecr:GetDownloadUrlForLayer",
        "ecr:BatchGetImage",
        "ecr:BatchCheckLayerAvailability"
      ],
      "Resource": "arn:aws:ecr:us-east-1:REPLACE_WITH_ACCOUNT_ID:repository/REPLACE_WITH_REPO_NAME"
    },
    {
      "Effect": "Allow",
      "Action": "ecr:GetAuthorizationToken",
      "Resource": "*"
    }
  ]
}

第二条语句至关重要。 GetAuthorizationToken唯一 不适用于特定存储库的 ECR 操作——它是全局适用的。如果没有它,您的任务甚至无法对 ECR 进行身份验证,其他一切都会失败。

如果您弄错了这一点,您的任务会停留在 PROVISIONING 状态一分钟,然后失败并提示 ResourceInitializationError。没有日志会说“嘿,您的 IAM 角色无法读取 ECR。” 错误信息很模糊。因此,当任务无法启动时,首先要检查的是执行角色。

私有子网失败及其发生的原因

假设您的 Fargate 任务位于私有子网中(一种良好的安全实践)。它没有直接的互联网访问权限——所有出站流量都经过 NAT 网关。现在您的任务尝试从 ECR 拉取镜像。

ECR 是一项 AWS 服务,因此它存在于互联网上(从某种意义上说——技术上它同时具有公共端点和 VPC 端点)。当您的私有子网任务连接到 ECR 的公共端点时,请求会通过 NAT 网关出去再回来,这 应该 有效。通常情况下确实如此。

但有时也会失败。如果您的 NAT 网关与您的任务不在同一个可用区 (AZ) 中,或者您配置错了路由表,请求就会静默失败。或者,如果您的安全组阻止了 443 端口 (HTTPS) 的出站流量,ECR 将无法响应。

修复方法通常是以下之一:

  1. 为 ECR 使用 VPC 端点。 在您的 VPC 中创建一个 VPC 端点,Fargate 就会通过该端点而不是公共互联网拉取镜像。这样更安全也更快。
  2. 确保您的 NAT 网关是可达的。 检查路由表——到 ECR 的流量应该通过 NAT 路由。
  3. 开放出站 HTTPS 流量。 您的任务的安全组需要在 443 端口上有出站权限才能访问 ECR。
  4. 检查 CloudWatch 日志。 如果您深入挖掘错误信息,通常能在任务的 CloudWatch 日志组中找到线索。

如果您在私有子网中,VPC 端点是黄金标准。它将所有流量保留在 AWS 内部,避免了 NAT 费用,并且速度更快。一次设置,一劳永逸。

了解 ECR 定价和镜像清理

ECR 的费用计算很简单:您按存储的镜像数据付费。没有按拉取次数收费,也没有按推送次数收费。仅仅是存储费。

需要注意的是: 您推送的每一个镜像层都会被永久存储,除非您将其删除。如果您反复推送相同的镜像标签(例如 "latest" 标签),在底层每次推送都是一个新镜像。几年后,您就会看到成千上万未打标签的镜像留在那里。

根据基础操作系统和包的不同,单个镜像可能在 500 MB 到 2 GB 之间。乘以数百或数千次构建,您看到的就是 TB 级的数据。大约以每月每 GB 0.10 美元计算,这很昂贵。

解决方案是生命周期策略。这是一种规则,它说“删除任何 30 天未使用的镜像”或“每个标签只保留最后 10 个镜像”。这里有一个合理的例子:

{
  "rules": [
    {
      "rulePriority": 1,
      "description": "Keep last 10 images",
      "selection": {
        "tagStatus": "tagged",
        "countType": "imageCountMoreThan",
        "countNumber": 10
      },
      "action": {
        "type": "expire"
      }
    },
    {
      "rulePriority": 2,
      "description": "Delete untagged images after 30 days",
      "selection": {
        "tagStatus": "untagged",
        "countType": "sinceImagePushed",
        "countUnit": "days",
        "countNumber": 30
      },
      "action": {
        "type": "expire"
      }
    }
  ]
}

这会保留最后 10 个已标记的镜像,并删除任何超过 30 天的未标记镜像。在设置 ECR 时应用此策略,您将永远不会遇到令人吃惊的 400 美元账单。

调试 ECR 问题

当任务启动失败时,错误信息通常毫无用处。但答案几乎总是以下之一:

  1. 错误的 IAM 权限。 执行角色无法读取存储库。
  2. 错误的存储库或区域。 任务在 app.example.com/myimage:latest 中寻找 us-east-1,但您将它推送到了 eu-west-1.
  3. 网络问题。 私有子网、安全组或路由表阻止了对 ECR 的访问。
  4. 镜像不存在。 您推送了一个标签,然后删除了它,接着又尝试使用它。
  5. ECR API 限流。 比较罕见,但如果您同时拉取数百个镜像,ECR 可能会对您进行速率限制。

排查步骤:

  • 在 IAM 控制台中检查任务的执行角色。它有 ECR 权限吗?
  • 检查任务的 CloudWatch 日志组。线索通常埋藏在 awslogs 输出中。
  • 尝试在同一个 VPC 中的 EC2 实例上手动拉取镜像。如果成功了,问题出在网络或任务配置的 IAM 上。
  • 查看 VPC 端点(如果您正在使用的话)。它从任务的子网可达吗?

结论

ECR 并不复杂,但很容易忽略细节。它位于您的 ECS 任务和外部世界之间,如果配置错误,一切都会停止。需要做对的三件事是:IAM 权限(包括 GetAuthorizationToken)、网络访问(尤其是在私有子网中)以及镜像清理(生命周期策略)。做好这三点,ECR 就会以一种好的方式变得“隐形”——它只会默默工作,而且您的账单也会保持合理。

优点

  • 完全托管——无需自行操作容器镜像库
  • 与 IAM 集成——内置细粒度访问控制
  • 便宜——仅按存储付费,没有按拉取收费
  • 快速——镜像与您的任务位于同一个 AWS 区域中
  • 提供 VPC 端点——将流量保留在 AWS 内部以提高安全性和速度
  • 生命周期策略——自动清理可防止账单意外超支

缺点

  • 错误信息不透明——"ResourceInitializationError" 什么也没告诉你
  • 地域性——一个区域的镜像对另一个区域的任务不可见,除非使用变通方法
  • 没有内置通知——您的镜像存储量可能会在没有警告的情况下膨胀
  • IAM 复杂性——执行角色有许多动态部分
  • VPC 端点设置需要手动——确保私有子网访问安全的流程应该更简单
  • 未标签镜像的清理是手动的——生命周期策略默认不启用

注意

本指南使用了占位符值:存储库名称为 REPLACE_WITH_REPO_NAME,账户 ID 为 REPLACE_WITH_ACCOUNT_ID,区域为通用示例。请务必替换为您 AWS 账户的真实值。在将任何这些配置部署到生产环境之前,请先在沙盒环境中对其进行测试。IAM 更改和网络配置可能会中断正在运行的工作负载,因此在进行更改时请务必小心并准备好回滚计划。请自行承担风险进行操作,并验证所有占位符已替换为实际、正确的值。

常见问题

  • 我如何从 CI/CD 管道将镜像推送到 ECR?
  • 公共 ECR 存储库和私有 ECR 存储库有什么区别?
  • 我可以从 AWS 外部拉取 ECR 镜像吗?
  • 如何扫描 ECR 镜像以查找安全漏洞?
  • 为什么我的 ECR 账单突然变得这么高?
  • 我必须使用 ECR 吗,还是可以使用 Docker Hub 或其他镜像库?
  • 如何向另一个 AWS 账户授予对我的 ECR 存储库的访问权限?
  • 如果我删除了一个正在运行的任务正在使用的镜像会怎样?

标签

#aws #ecr #ecs #containers #fargate #devops #cloudnative #iam

Free field guide

Prompt-Injection Defense Checklist

The controls that actually reduce the blast radius when your app feeds untrusted text to an LLM. Enter your email — you'll get the PDF instantly, plus new posts on AI, security & Linux.