Amazon ECS Agent 深度解析:架构、部署与生产环境实战指南
1. 项目概述:深入理解 Amazon ECS Agent
如果你正在或计划在 AWS 上运行容器化应用,那么Amazon ECS Agent就是你绕不开的核心组件。简单来说,它是部署在每一个 ECS 容器实例(通常是 EC2 实例)上的“大脑”和“执行者”。当你在 ECS 控制台或通过 API 创建一个任务(Task)时,这个任务定义并不会直接飞到你的服务器上执行。相反,ECS 服务端会将任务指令下发给运行在你实例上的 ECS Agent,然后由这个 Agent 负责与本地 Docker 守护进程(或 containerd)通信,拉起指定的容器,并持续管理它们的生命周期——包括健康检查、日志收集、资源监控,以及在任务结束时清理容器。
这个开源项目aws/amazon-ecs-agent正是这个 Agent 的源代码仓库。它不仅包含了 Agent 本身(用 Go 语言编写),还包含了用于 Linux 系统的ecs-init服务(一个 systemd 服务),这个服务负责安装、启动并守护 Agent 进程,确保其高可用。对于刚接触 ECS 的开发者,理解 Agent 的工作原理和部署方式,是掌握 ECS 运维、进行故障排查乃至进行二次开发定制的基础。无论是运维工程师需要优化实例性能,还是开发者在混合云场景下需要自定义调度逻辑,深入这个仓库都能获得第一手的信息。
2. 核心架构与工作原理拆解
要玩转 ECS Agent,不能只停留在“安装启动”的层面,必须理解其内部的工作流和与各组件间的交互。这能帮助你在出现网络抖动、任务启动失败、资源竞争等问题时,快速定位根因。
2.1 Agent 的双向通信桥梁角色
ECS Agent 本质上是一个常驻进程,扮演着“云端控制平面”与“本地数据平面”之间的桥梁。
- 与控制平面通信(ECS Service):Agent 通过长轮询(Long Polling)的方式,持续向 ECS 服务端的一个特定端点(
/v1/agent/metadata)发起请求。这个请求会挂起,直到服务端有新的指令(如:启动新任务、停止现有任务)需要下发,或者需要 Agent 上报当前状态。这种方式比短轮询更高效,减少了不必要的请求开销。所有通信都通过标准的 AWS SDK 进行,并依赖实例的 IAM 角色(或配置的凭证)进行鉴权。 - 与容器运行时通信(Docker Daemon):Agent 通过 Docker 的 Unix Socket(通常是
/var/run/docker.sock)或 Windows 的命名管道与 Docker 守护进程交互。它调用 Docker API 来执行docker run,docker stop,docker inspect等操作。这也是为什么在安装 Agent 时,必须将宿主机的 Docker Socket 挂载到 Agent 容器内部。
2.2 关键状态管理与数据持久化
Agent 并非无状态服务。为了保证实例重启或 Agent 自身崩溃后能恢复任务状态,它实现了状态检查点(Checkpoint)机制。
- 状态文件:Agent 会将当前实例上所有任务和容器的状态序列化后,持久化到磁盘上的一个文件中。在 Linux 上,默认路径是
/var/lib/ecs/data/(由ECS_DATADIR环境变量控制)。这个文件包含了任务定义、容器 ID、网络绑定信息等关键元数据。 - 恢复流程:当 Agent 启动时,它会首先尝试从检查点文件加载之前的状态。然后,它会向 Docker 查询当前实际运行的容器列表,并与内存中加载的状态进行比对、调和(Reconcile)。例如,如果检查点记录了一个任务正在运行,但 Docker 中对应的容器已不存在,Agent 会认为该任务失败,并向 ECS 服务端报告。这个机制确保了 ECS 对任务状态的认知与实际情况最终保持一致,是 ECS 可靠性的基石。
2.3 ecs-init 服务:Linux 系统的守护者
在 Linux 系统上,直接运行一个docker run命令来启动 Agent 容器是不够的,因为 Docker 服务本身可能重启,或者宿主机重启后需要自动拉起 Agent。ecs-init就是为了解决这个问题而生的。
- 核心功能:
- 依赖检查与安装:在启动前,它会检查并确保 Docker 服务已经就绪。
- 环境准备:创建 Agent 运行所需的目录结构(如
/var/log/ecs,/var/lib/ecs/data),并处理一些网络配置(如设置net.ipv4.conf.all.route_localnet=1和配置 iptables 规则,以支持任务 IAM 角色功能)。 - 启动与守护:以
systemd服务的形式,负责启动 Agent 容器,并监控其运行状态。如果 Agent 容器异常退出,ecs-init会根据重启策略(默认为on-failure:10)尝试重启它。 - 生命周期管理:提供了
start、stop、restart等标准 systemd 命令来管理 Agent。
- 包管理:
ecs-init被打包成 RPM(用于 Amazon Linux、RHEL、CentOS 等)和 DEB(用于 Ubuntu、Debian 等)格式。通过包管理器安装,能实现最规范的系统集成,例如将日志自动集成到journald。
注意:很多初次部署时遇到的“Agent 状态不健康”问题,根源往往在于
ecs-init服务未能成功配置网络规则或挂载目录权限不正确。务必确保/etc/ecs/ecs.config配置文件存在且格式正确,并且/var/run/docker.sock的权限允许ecs-init进程访问。
3. 多环境部署实操全指南
官方文档给出了多种部署方式,但每种方式背后的适用场景和细节陷阱各不相同。这里我将结合多年运维经验,为你拆解最实用的几种部署路径及其核心要点。
3.1 Amazon Linux 2/2023 AMI:最省心的方案
对于 AWS 原生的 Amazon Linux AMI,这是最推荐、最稳定的方式。
# 1. 更新系统并安装 ecs-init 包 sudo yum update -y sudo yum install -y ecs-init # 2. 配置集群名称(可选,默认为 ‘default’) # 编辑配置文件,设置你的集群名 echo 'ECS_CLUSTER=my-production-cluster' | sudo tee -a /etc/ecs/ecs.config # 3. 启动服务 sudo systemctl enable ecs # 设置开机自启 sudo systemctl start ecs # 立即启动实操心得:
- 安装后,务必检查服务状态:
sudo systemctl status ecs。不仅要看active (running),还要看下方的日志有无错误。 - 通过
sudo tail -f /var/log/ecs/ecs-init.log和sudo tail -f /var/log/ecs/ecs-agent.log分别查看ecs-init和Agent的日志,这是排查启动问题的第一现场。 - 如果实例需要加入一个已存在的集群,且该集群启用了 EC2 实例保护或特定的 IAM 策略,请确保实例的 IAM 角色拥有
ecs:RegisterContainerInstance等必要权限。
3.2 通用 Linux 系统(Ubuntu/CentOS)的 Docker 运行方式
当你使用自定义的 AMI,或者非 Amazon Linux 发行版时,直接使用 Docker 运行 Agent 容器是最灵活的方式。官方提供的命令是一个很好的起点,但我们需要理解每一行命令的意图。
#!/bin/bash # 这是一个生产环境可用的部署脚本片段 # 1. 创建必要的目录并设置权限 sudo mkdir -p /var/log/ecs /etc/ecs /var/lib/ecs/data sudo touch /etc/ecs/ecs.config # 确保目录权限,允许容器内进程写入日志和数据 sudo chmod -R 755 /var/log/ecs /var/lib/ecs # 2. 配置集群名称 echo 'ECS_CLUSTER=my-cluster' | sudo tee /etc/ecs/ecs.config # 如果需要任务IAM角色,必须启用(这是生产环境常见配置) echo 'ECS_ENABLE_TASK_IAM_ROLE=true' | sudo tee -a /etc/ecs/ecs.config echo 'ECS_ENABLE_TASK_IAM_ROLE_NETWORK_HOST=true' | sudo tee -a /etc/ecs/ecs.config # 3. 配置支持任务IAM角色的网络规则(关键步骤!) # 允许本地回环地址的路由,这是实现169.254.170.2重定向的基础 sudo sysctl -w net.ipv4.conf.all.route_localnet=1 # 使配置持久化,防止重启后失效 echo "net.ipv4.conf.all.route_localnet=1" | sudo tee -a /etc/sysctl.conf # 配置iptables规则,将任务元数据服务请求重定向到Agent # 这条规则可能已由ecs-init包管理,手动运行时需自行添加 sudo iptables -t nat -A PREROUTING -p tcp -d 169.254.170.2 --dport 80 -j DNAT --to-destination 127.0.0.1:51679 sudo iptables -t nat -A OUTPUT -d 169.254.170.2 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 51679 # 保存iptables规则(根据发行版不同,命令可能为iptables-save > /etc/sysconfig/iptables 或使用iptables-persistent包) sudo iptables-save | sudo tee /etc/iptables/rules.v4 # 4. 运行Agent容器 sudo docker run --name ecs-agent \ --detach=true \ --restart=on-failure:10 \ --volume=/var/run/docker.sock:/var/run/docker.sock \ --volume=/var/log/ecs:/log \ --volume=/var/lib/ecs/data:/data \ --volume=/etc/ecs:/etc/ecs \ --net=host \ --env-file=/etc/ecs/ecs.config \ --env=ECS_LOGFILE=/log/ecs-agent.log \ --env=ECS_DATADIR=/data/ \ --env=ECS_ENABLE_TASK_IAM_ROLE=true \ --env=ECS_ENABLE_TASK_IAM_ROLE_NETWORK_HOST=true \ amazon/amazon-ecs-agent:latest关键参数解析与避坑指南:
--net=host:使用主机网络模式。这简化了网络配置,特别是对于需要任务 IAM 角色和awsvpc网络模式的任务至关重要。但这也意味着 Agent 容器没有独立的网络命名空间。--volume=/var/run/docker.sock:/var/run/docker.sock:这是 Agent 能控制 Docker 的“钥匙”。务必确保路径正确。--env-file=/etc/ecs/ecs.config:将所有环境变量集中管理在这个文件中,比在docker run命令中用多个-e更清晰,也便于后续修改。- iptables 规则是核心:任务内应用程序通过访问
169.254.170.2这个链路本地地址来获取临时凭证。上述 iptables 规则将这些请求劫持并重定向到了本机127.0.0.1:51679端口,这正是 Agent 提供任务元数据服务的端口。如果忘记配置,任务 IAM 角色功能将完全失效。 - 数据持久化:将
/data卷挂载出来,保证了 Agent 的状态检查点文件得以保存。如果这个目录丢失,实例重启后 Agent 可能无法正确恢复之前运行的任务状态。
3.3 启用 awsvpc 网络模式的特例
当你的任务使用awsvpc网络模式(每个任务拥有独立的弹性网络接口 ENI)时,对 Agent 的运行环境有额外要求,因为需要调用 CNI(容器网络接口)插件来管理网络。
sudo docker run --name ecs-agent \ --init \ --restart=on-failure:10 \ --volume=/var/run:/var/run \ --volume=/var/log/ecs/:/log:Z \ --volume=/var/lib/ecs/data:/data:Z \ --volume=/etc/ecs:/etc/ecs \ --volume=/sbin:/host/sbin \ --volume=/lib:/lib \ --volume=/lib64:/lib64 \ --volume=/usr/lib:/usr/lib \ --volume=/usr/lib64:/usr/lib64 \ --volume=/proc:/host/proc \ --volume=/sys/fs/cgroup:/sys/fs/cgroup \ --net=host \ --env-file=/etc/ecs/ecs.config \ --cap-add=sys_admin \ --cap-add=net_admin \ --env ECS_ENABLE_TASK_ENI=true \ --env ECS_UPDATES_ENABLED=true \ --env ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION=1h \ --env ECS_DATADIR=/data \ --env ECS_ENABLE_TASK_IAM_ROLE=true \ --env ECS_ENABLE_TASK_IAM_ROLE_NETWORK_HOST=true \ --env ECS_LOGFILE=/log/ecs-agent.log \ --env ECS_AVAILABLE_LOGGING_DRIVERS='["json-file","awslogs","syslog","none"]' \ --env ECS_LOGLEVEL=info \ --detach \ amazon/amazon-ecs-agent:latest与标准模式的主要区别:
- 更多卷挂载:挂载了
/sbin、/lib、/lib64等系统目录。这是因为 CNI 插件(位于/amazon-ecs-cni-plugins)是二进制文件,它依赖于宿主机的动态链接库。通过挂载这些目录,容器内的 CNI 插件才能正确执行。 - 挂载
/proc和/sys/fs/cgroup:awsvpc模式需要更深入的系统交互来管理网络命名空间和 cgroup。 - 额外权限:
--cap-add=sys_admin --cap-add=net_admin赋予了容器进行系统管理和网络配置的高级权限,这是操作网络接口和命名空间所必需的。 - 关键环境变量:
ECS_ENABLE_TASK_ENI=true是启用任务 ENI 功能的开关。ECS_UPDATES_ENABLED=true允许 Agent 自动更新,这在生产环境中需谨慎评估。
警告:以如此高的权限(
sys_admin,net_admin)运行容器存在安全风险。务必确保你信任该容器镜像(官方amazon/amazon-ecs-agent),并且实例本身处于安全的网络环境中(如私有子网)。切勿随意运行来源不明的容器镜像。
3.4 Windows 容器实例部署
对于 Windows 容器实例,ECS 提供了 PowerShell 模块ECSTools来简化部署。
# 导入模块 Import-Module ECSTools # 基础安装,加入名为 ‘windows’ 的集群 Initialize-ECSAgent -Cluster 'windows' -EnableTaskIAMRole # 安装特定版本的 Agent $agentVersion = "v1.70.0" Initialize-ECSAgent -Cluster 'my-windows-cluster' -EnableTaskIAMRole -Version $agentVersionWindows 部署注意事项:
- IAM 角色:与 Linux 类似,EC2 实例必须附加一个具有正确 ECS 权限的 IAM 角色。
- 网络:Windows 的任务 IAM 角色实现机制与 Linux(iptables 重定向)不同,无需手动配置网络规则。
- 日志:Windows Agent 的日志默认位于
C:\ProgramData\Amazon\ECS\log\ecs-agent.log。 - 版本兼容性:注意 Windows Docker 版本与 ECS Agent 版本的兼容性,建议参考 AWS 官方文档的最新兼容性矩阵。
4. 高级配置与环境变量深度解析
ECS Agent 的强大和灵活性很大程度上通过环境变量来体现。官方列表很长,这里我挑出生产环境中最常调整、也最容易出问题的几个进行深度解读。
4.1 集群与资源管理
| 环境变量 | 建议值/示例 | 作用与解析 |
|---|---|---|
ECS_CLUSTER | prod-backend | 最重要的配置之一。指定实例要注册到的 ECS 集群名称。如果集群不存在,ECS 会自动创建。建议显式设置,避免所有实例都挤在default集群里。 |
ECS_RESERVED_PORTS | [22, 80, 443, 8080] | 声明宿主机上哪些端口已被占用,ECS 调度器会避开这些端口为任务分配主机端口。务必包含 SSH(22)、Agent 自身服务端口(51678/51679)以及你实例上其他服务占用的端口。 |
ECS_RESERVED_MEMORY | 256 | 极易误解的配置。它并非“预留”内存,而是从实例总内存中“扣除”一个值,再报告给 ECS 调度器。例如,一个 4GB 内存的实例,设置ECS_RESERVED_MEMORY=256,那么 ECS 认为该实例只有 3840MB 可用内存用于调度任务。这个值用于补偿操作系统、Agent 及其他非容器进程的内存开销。设置过小会导致任务内存超额分配引发 OOM;设置过大会浪费资源。建议通过监控观察系统基线内存使用,再设置此值。 |
ECS_RESERVED_PORTS_UDP | [53, 123] | 与ECS_RESERVED_PORTS类似,但针对 UDP 端口。如果你的实例运行了 DNS(53)或 NTP(123)服务,需要在此声明。 |
4.2 任务生命周期与清理
| 环境变量 | 默认值 | 作用与解析 |
|---|---|---|
ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION | 3h | 任务停止后,Agent 等待多久才删除对应的 Docker 容器。这是一个非常重要的调优参数。默认 3 小时很长,目的是为了给你留足时间调试和查看已停止任务的日志。在生产环境中,可以适当缩短(如30m),以更快释放容器占用的资源(如未使用的镜像层、网络端点)。但如果你依赖停止后的容器进行日志分析,则需保留较长时间。 |
ECS_IMAGE_CLEANUP_INTERVAL | 30m | Agent 自动清理未使用镜像的间隔时间。 |
ECS_IMAGE_MINIMUM_CLEANUP_AGE | 1h | 镜像被拉取后,至少经过多久才可能被清理。防止刚拉取的镜像立刻被清理。 |
ECS_NUM_IMAGES_DELETE_PER_CYCLE | 5 | 每次清理周期最多删除的镜像数量。防止一次性清理过多镜像对 I/O 造成压力。 |
ECS_DISABLE_IMAGE_CLEANUP | false | 设为true则完全禁用自动镜像清理。如果你有严格的镜像版本控制策略,或者磁盘空间充足,可以禁用。 |
实操心得:镜像清理策略需要根据你的发布频率和磁盘空间权衡。对于开发测试环境,可以设置较短的清理间隔和年龄,保持磁盘清爽。对于生产环境,如果发布不频繁,可以拉长ECS_IMAGE_MINIMUM_CLEANUP_AGE(例如24h),避免回滚时需要重新拉取旧镜像。
4.3 网络与安全增强
| 环境变量 | 默认值 | 作用与解析 |
|---|---|---|
ECS_ENABLE_TASK_IAM_ROLE | false | 必须显式设为true才能使用任务 IAM 角色功能。这是让容器内应用安全访问 AWS 资源(如 S3、DynamoDB)的推荐方式。 |
ECS_ENABLE_TASK_IAM_ROLE_NETWORK_HOST | false | 对于使用host网络模式的任务,也必须设为true才能启用任务 IAM 角色。 |
ECS_AWSVPC_BLOCK_IMDS | false | 在awsvpc网络模式下,是否阻止任务容器访问实例元数据服务(IMDS,169.254.169.254)。强烈建议在生产环境中设为true。这可以防止任务中的代码误操作或恶意代码获取到实例的 IAM 角色凭证,这是一个重要的安全加固措施。任务所需的权限应通过任务 IAM 角色授予,而非实例角色。 |
ECS_EXCLUDE_IPV6_PORTBINDING | 自动检测 | 在非 IPv6-only 实例上,默认排除 IPv6 端口绑定。这可以避免在双栈环境中因 IPv6 绑定问题导致任务启动失败。通常保持默认即可。 |
4.4 日志与调试
| 环境变量 | 默认值 | 作用与解析 |
|---|---|---|
ECS_LOGLEVEL | info | Agent 自身的日志级别。排查复杂问题时,可临时设为debug以获取最详细的信息,但注意debug日志量巨大,长期开启会影响性能并迅速占满磁盘。 |
ECS_LOGFILE | (空) | Agent 日志文件路径。在容器运行时,通常设置为挂载卷的路径,如/log/ecs-agent.log,以便日志持久化到宿主机。 |
ECS_AVAILABLE_LOGGING_DRIVERS | ["json-file","none"] | 实例支持的 Docker 日志驱动。如果你计划使用awslogs将容器日志直接发送到 CloudWatch Logs,必须在此数组中加入"awslogs"。例如:'["json-file","awslogs","syslog"]'。 |
ECS_ENABLE_RUNTIME_STATS | false | 是否启用 Go 语言的 pprof 性能分析端点。仅在深度调试 Agent 内存泄漏、CPU 占用等性能问题时开启,并通过localhost:51678/debug/pprof/访问。生产环境不建议开启。 |
4.5 代理与特殊环境
| 环境变量 | 示例 | 作用与解析 |
|---|---|---|
HTTP_PROXY/HTTPS_PROXY | http://proxy.internal:3128 | 当你的容器实例处于私有子网,没有公网 IP,需要通过代理服务器访问互联网(例如拉取公有 Docker 镜像)时设置。 |
NO_PROXY | 169.254.169.254,/var/run/docker.sock | 与代理配套使用,至关重要。它告诉 Agent 哪些地址不应通过代理访问。必须包含: 1. 169.254.169.254:实例元数据服务,用于获取 IAM 凭证和实例信息。2. /var/run/docker.sock:本地 Docker 守护进程。3. (可选)你的 VPC 端点地址。如果漏配,Agent 将无法与 ECS 服务端通信,也无法管理 Docker。 |
5. 从源码构建与深度定制
对于大多数用户,使用官方发布的 Docker 镜像或系统包就足够了。但在某些场景下,比如需要验证某个问题是否在新版本中修复,或者需要进行深度的定制化开发(例如,为 Agent 添加特定的监控指标或日志钩子),从源码构建就成为了必备技能。
5.1 在 Linux 上构建 Agent Docker 镜像
构建环境需要安装好 Git、Docker 和 Make 工具。
# 1. 克隆仓库 git clone https://github.com/aws/amazon-ecs-agent.git cd amazon-ecs-agent # 2. 查看可用的构建目标 make help # 3. 构建 Agent 的 Docker 镜像。这会执行一个复杂的流程: # - 拉取 Go 编译环境镜像 # - 编译 Agent 的 Go 二进制文件 # - 将其打包进一个基于 Alpine 的轻量级 Docker 镜像 make release-agent # 构建成功后,会输出类似信息,并生成一个 tar 包 # ... Build output ... # Wrote docker image to ecs-agent-v1.70.0.tar # 4. 加载构建好的镜像到本地 Docker docker load < ecs-agent-v1.70.0.tar # 5. 查看并验证镜像 docker images | grep ecs-agent # 你应该能看到一个名为 amazon/amazon-ecs-agent 的镜像,TAG 是类似 latest 或一个提交哈希构建过程解析:make release-agent这个目标背后,Makefile 会调用scripts/build等脚本。它使用了一个“构建器容器”模式,确保编译环境的一致性。最终产物是一个包含了amazon-ecs-agent二进制文件、启动脚本和必要依赖的 Docker 镜像。你可以像使用官方镜像一样,用docker run命令来运行你自己构建的镜像,只需将镜像标签替换为你本地的标签即可。
5.2 以独立二进制文件运行(用于开发调试)
对于 Go 语言开发者,可能更希望直接运行二进制文件,方便使用 delve 等调试器进行单步调试。
# 1. 确保已安装 Go (版本要求参见 go.mod) cd amazon-ecs-agent # 2. 编译 Go 二进制文件 make gobuild # 编译产物位于 ./out/amazon-ecs-agent # 3. 运行前,需要手动准备环境变量和目录,模拟容器环境 export ECS_CLUSTER=my-test-cluster export ECS_DATADIR=/tmp/ecs/data export ECS_LOGFILE=/tmp/ecs/agent.log export ECS_ENABLE_TASK_IAM_ROLE=true mkdir -p /tmp/ecs/data touch /tmp/ecs/agent.log # 4. 以独立进程运行Agent # 注意:这种方式下,Agent会尝试直接与Docker守护进程通信, # 你需要确保当前用户有权限访问 /var/run/docker.sock ./out/amazon-ecs-agent这种方式的局限性:独立运行模式缺少了ecs-init提供的许多服务管理功能(如自动重启、环境准备)。它主要用于开发、测试新功能,或者快速验证某个代码修改。生产环境强烈建议使用 Docker 容器或系统包的方式运行。
5.3 构建 ecs-init 系统包
如果你需要为自定义的 Linux 发行版(比如某个特定的 CentOS 衍生版)制作ecs-init安装包,也可以从源码构建。
# 进入打包目录 cd amazon-ecs-agent/packaging # 构建 RPM 包(适用于 RHEL/CentOS/Amazon Linux) cd generic-rpm-integrated make rpm # 构建 DEB 包(适用于 Ubuntu/Debian) cd ../generic-deb-integrated make deb构建过程会生成.rpm或.deb文件,你可以将其分发到你的机器上,用yum localinstall或dpkg -i进行安装。这在你需要严格管控内部软件供应链,或者需要对ecs-init脚本进行定制化修改时非常有用。
6. 生产环境故障排查与性能调优实录
即使配置无误,在生产环境中运行 ECS Agent 也可能遇到各种问题。下面是我总结的几个最常见的问题场景及其排查思路。
6.1 Agent 状态不健康或无法注册到集群
症状:在 ECS 控制台,容器实例状态显示为“不健康”或“注册失败”。
排查步骤:
- 检查
ecs-init或 Docker 容器状态:# 如果使用 ecs-init sudo systemctl status ecs # 如果使用 Docker 直接运行 docker ps | grep ecs-agent docker logs ecs-agent --tail 50 - 检查关键日志:
ecs-init日志:sudo journalctl -u ecs --no-pager -f或sudo tail -f /var/log/ecs/ecs-init.logecs-agent日志:sudo tail -f /var/log/ecs/ecs-agent.log- 重点关注日志中的
ERROR和WARN。常见错误包括:Unable to reach ECS service: 网络问题,实例无法访问 ECS 服务端点。检查安全组、网络 ACL、路由表,以及是否配置了代理(HTTP_PROXY)且NO_PROXY设置正确。Unable to assume role/AccessDenied: IAM 角色权限不足。检查实例附加的 IAM 角色策略是否包含ecs:RegisterContainerInstance、ecs:DeregisterContainerInstance、ecs:Submit*等必要动作。CannotCreateContainerError: No such image: Docker 镜像拉取失败。检查任务定义中的镜像名称是否正确,以及实例是否有权限从 ECR 或 Docker Hub 拉取镜像(可能需要配置私有仓库认证或 VPC 端点)。
- 验证网络连通性:
# 测试是否能解析 ECS 服务端点 curl -s https://ecs.${AWS_REGION}.amazonaws.com/ # 预期返回类似 <AccessDeniedException>... 的错误,这至少证明网络是通的。 # 如果超时或无法解析,则是网络问题。 - 检查
/etc/ecs/ecs.config文件:确保文件格式正确(每行KEY=VALUE),没有多余空格或错误引号。
6.2 任务启动失败(Stopped before essential containers completed)
症状:任务状态迅速变为STOPPED,原因显示为“Essential container in task exited”。
排查步骤:
- 查看任务详情:在 ECS 控制台点击失败的任务,查看“Stopped reason”和“Exit code”。
- 查看容器日志:即使容器启动失败,只要配置了日志驱动(如
awslogs),日志可能已被发送。在 CloudWatch Logs 中查找对应日志组。如果使用json-file,可以在宿主机上通过docker logs <container_id>查看(需要先通过docker ps -a找到已停止的容器ID)。 - 检查任务定义:
- 命令(Command)与入口点(Entrypoint):是否拼写错误?路径是否存在?
- 环境变量:是否缺少必需的环境变量?
- 挂载点(Mount Points):声明的卷(Volume)或绑定挂载(Bind Mount)在宿主机上是否存在?权限是否正确?
- 用户(User):容器内运行的用户是否有权限执行命令或写入文件?
- 检查资源限制:任务定义的 CPU/内存限制是否过小,导致容器因 OOM(内存溢出)被系统杀死?可以尝试临时调大限制进行测试。
- 检查依赖服务:容器启动时是否需要连接数据库、缓存等外部服务?这些服务是否可达?
6.3 任务 IAM 角色不生效
症状:容器内应用无法获取临时凭证,访问 AWS 服务被拒绝。
排查步骤:
- 确认 Agent 配置:确保
ECS_ENABLE_TASK_IAM_ROLE=true已设置,并且对于host网络模式的任务,ECS_ENABLE_TASK_IAM_ROLE_NETWORK_HOST=true也已设置。 - 验证 iptables 规则(仅 Linux):
应该能看到将目标地址sudo iptables -t nat -L -n | grep -A2 -B2 169.254.170.2169.254.170.2:80重定向到127.0.0.1:51679的规则。如果没有,需要手动添加(见 3.2 节)。 - 在容器内测试:
如果返回# 进入一个运行中的任务容器(需要安装curl) docker exec -it <container_id> sh # 尝试访问凭证端点 curl http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI404或连接被拒绝,说明容器内网络到 Agent 的路径不通。检查网络模式和安全组规则(对于awsvpc模式)。 - 检查任务角色:确认任务定义中正确引用了 IAM 角色,并且该角色信任实体(Trust Policy)包含
ecs-tasks.amazonaws.com,且附加了正确的权限策略。
6.4 磁盘空间被占满(镜像堆积)
症状:实例磁盘空间不足,导致新任务无法启动(无法拉取镜像)或系统运行缓慢。
解决方案:
- 调整自动清理策略:如前所述,优化
ECS_IMAGE_CLEANUP_INTERVAL、ECS_IMAGE_MINIMUM_CLEANUP_AGE等参数。 - 手动清理:
警告:# 查看磁盘使用情况 df -h # 查看 Docker 磁盘使用详情 docker system df # 删除所有未被任何容器引用的镜像、停止的容器、未使用的卷和网络 docker system prune -a -fdocker system prune -a会删除所有未被容器使用的镜像,包括可能用于快速回滚的旧版本镜像,请在业务低峰期谨慎操作。 - 增加实例存储:对于长期运行的实例,考虑使用更大的 EBS 卷或挂载额外的 EBS 卷专门用于 Docker(通过配置 Docker 的
>
