深入 Amazon ECS Managed Daemons:daemon_bridge 网络模式、滚动部署与生命周期解耦的实现细节
上周在排查一个监控数据缺失的问题时,我发现根因居然是——某个应用团队两个月前重新部署时,不小心把 task definition 里的 Amazon CloudWatch Agent sidecar 删掉了。
两个月。整整两个月没人发现。
这件事让我下定决心,把所有 sidecar 模式部署的 Agent 迁移到 Amazon ECS 新推出的 Managed Daemons 上。折腾了一周,踩了不少坑,这篇文章把技术细节完整记录下来。
背景:sidecar 模式的系统性缺陷
在讨论 Managed Daemons 之前,有必要梳理清楚 sidecar 模式到底哪里不行。不是说它不能用,而是在规模化运维场景下,它有几个根本性的结构缺陷。
缺陷一:生命周期耦合
Agent 和应用容器共享同一个 task definition。这意味着 Agent 的任何变更(版本升级、配置修改、资源调整)都必须通过修改 task definition 来实现。而修改 task definition 就等于触发应用重新部署。
在微服务架构下,一个集群可能有上百个 task definition。每个属于不同的应用团队。平台工程师要更新 Agent,需要逐个协调。
缺陷二:资源定义混杂
sidecar Agent 的 CPU 和内存配额在应用的 task definition 里定义。应用团队在做容量规划时,要把 Agent 的开销算进去。这增加了认知负担,也容易出错。
缺陷三:无启动顺序保证
Amazon ECS 不保证同一 task 里多个容器的启动顺序(依赖关系可以配但不够可靠)。Agent 可能在应用容器之后启动,导致前几秒的日志和指标丢失。
缺陷四:规模化成本
每个应用任务一个 Agent 副本。一台实例跑 10 个任务,就有 10 个 Agent 进程。资源浪费不说,Agent 之间还可能互相争抢。
Managed Daemons 架构解析
2025 年 4 月,亚马逊云科技发布了面向 Amazon ECS 托管实例的 Managed Daemons 功能。下面从几个核心维度拆解。
daemon task definition:独立的资源类型
Managed Daemons 引入了全新的 daemon task definition 概念。它和普通 task definition 是完全独立的资源类型,有自己的参数体系和验证逻辑。
关键区别:
- 注册入口不同(控制台有单独的"进程守护程序定义"菜单)
- API 调用不同(
register-daemon-task-definition而非register-task-definition) - 部署方式不同(关联到容量提供商,而非通过 service 调度)
这种设计从根本上切断了守护进程和应用任务的耦合。
daemon_bridge 网络模式
这是 Managed Daemons 引入的新网络模式。让我详细说说它解决了什么问题。
在 sidecar 模式下,Agent 和应用共享同一个网络命名空间。Agent 可以通过 localhost 采集应用指标,但同时也意味着:
- Agent 的端口可能和应用端口冲突
- Agent 的网络配置变更会影响应用
- 安全边界模糊
daemon_bridge 模式下:
- 守护进程有独立的网络栈
- 可以和应用任务通信(用于指标采集、日志推送等)
- 但网络配置互相隔离,不会互相干扰
这在网络层面实现了"该通的通、该隔的隔"。
主机级访问能力
对于监控和安全代理来说,主机级访问权限是刚需。Managed Daemons 支持三种方式:
特权容器(privileged mode)
{
"containerDefinitions": [
{
"name": "monitoring-agent",
"privileged": true
}
]
}
给容器完整的主机权限。适用于需要深度系统访问的场景。
Linux capabilities
比特权模式更精细的权限控制。比如只需要网络管理能力:
{
"linuxParameters": {
"capabilities": {
"add": ["NET_ADMIN", "SYS_PTRACE"]
}
}
}
建议优先用 capabilities,而不是一上来就开 privileged。权限越小越安全。
主机文件系统挂载
{
"mountPoints": [
{
"sourceVolume": "proc",
"containerPath": "/host/proc",
"readOnly": true
}
],
"volumes": [
{ "name": "proc", "host": { "sourcePath": "/proc" } }
]
}
监控 Agent 采集 CPU、内存、网络、磁盘 I/O 指标都需要读取 /proc 和 /sys。
生命周期保证
Managed Daemons 在生命周期管理上提供了三个关键保证:
- 先启动保证:守护进程先于应用任务启动。应用开始处理请求前,监控已经就绪。
- 最后耗尽:实例退出时,守护进程最后停止。确保应用停止过程中的日志和指标仍然被采集。
- 唯一性:每台实例只运行一个守护进程副本。不会出现多副本竞争的问题。
实操:部署 Amazon CloudWatch Agent 作为 Managed Daemon
完整的 daemon task definition
{
"family": "cloudwatch-agent-daemon",
"containerDefinitions": [
{
"name": "cloudwatch-agent",
"image": "public.ecr.aws/cloudwatch-agent/cloudwatch-agent:latest",
"cpu": 1024,
"memory": 512,
"essential": true,
"privileged": true,
"mountPoints": [
{
"sourceVolume": "proc",
"containerPath": "/host/proc",
"readOnly": true
},
{
"sourceVolume": "sys",
"containerPath": "/host/sys",
"readOnly": true
},
{
"sourceVolume": "rootfs",
"containerPath": "/rootfs",
"readOnly": true
}
],
"environment": [
{
"name": "HOST_PROC",
"value": "/host/proc"
},
{
"name": "HOST_SYS",
"value": "/host/sys"
}
]
}
],
"volumes": [
{ "name": "proc", "host": { "sourcePath": "/proc" } },
{ "name": "sys", "host": { "sourcePath": "/sys" } },
{ "name": "rootfs", "host": { "sourcePath": "/" } }
],
"executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
"taskRoleArn": "arn:aws:iam::123456789012:role/ecsCloudWatchAgentRole"
}
这个配置比前面的示例更完整,多了:
/rootfs挂载:让 Agent 能读取根文件系统(磁盘指标需要)- 环境变量
HOST_PROC和HOST_SYS:告诉 Agent 主机 proc/sys 的挂载路径
创建和关联 daemon
# 创建配置
cat <<'EOF' > create-daemon.json
{
"clusterArn": "arn:aws:ecs:us-east-1:123456789012:cluster/production",
"daemonName": "cloudwatch-agent",
"daemonTaskDefinitionArn": "arn:aws:ecs:us-east-1:123456789012:daemon-task-definition/cloudwatch-agent-daemon:1",
"capacityProviderArns": [
"arn:aws:ecs:us-east-1:123456789012:capacity-provider/prod-managed-cp"
]
}
EOF
# 创建 daemon
aws ecs create-daemon --cli-input-json file://create-daemon.json
# 验证状态
aws ecs describe-daemons \
--daemon-arn arn:aws:ecs:us-east-1:123456789012:daemon/production/cloudwatch-agent
滚动更新机制详解
这是我认为 Managed Daemons 设计得相当精妙的部分。
更新触发
aws ecs update-daemon \
--daemon-arn arn:aws:ecs:us-east-1:123456789012:daemon/production/cloudwatch-agent \
--daemon-task-definition-arn arn:aws:ecs:us-east-1:123456789012:daemon-task-definition/cloudwatch-agent-daemon:2
更新流程
- Amazon ECS 根据 drain 百分比(默认 25%)选择一批实例
- 被选中的实例进入排空状态
- 实例上的应用任务被迁移到其他健康实例
- 新实例启动,先拉起新版本守护进程
- 守护进程就绪后,应用任务被调度到新实例
- 旧实例终止
- 循环处理下一批
核心原则:先启动后停止。 任何时刻都有守护进程在运行。监控不中断,日志不丢失。
回滚机制
三层保护:
第一层:断路器。 部署过程中如果新版本启动失败达到阈值,自动停止部署。
第二层:Bake time。 更新完所有实例后,等待指定时间观察。这个时间窗口用来发现那些不会立即暴露的问题(比如内存泄漏、性能劣化)。
第三层:Amazon CloudWatch 告警联动。 在 bake time 期间,如果配置的 Amazon CloudWatch 告警触发,自动执行回滚。
这三层加起来,基本覆盖了从"启动就挂"到"跑一阵才出问题"的各种故障场景。
踩坑详录
坑 1:UpdateDaemon API 不保留上次配置
这个设计和大多数 AWS API 的行为不一样。每次 UpdateDaemon 必须传完整配置。
举个例子:你第一次创建时启用了 enableExecuteCommand: true。更新 daemon task definition 版本时如果没带这个参数,ECS Exec 功能会被关掉。
这个行为在官方文档的 Important 框里有说明,但说实话我第一次就没注意。
坑 2:守护进程崩溃循环会导致实例反复替换
守护进程停止 → Amazon ECS 判定实例不健康 → 排空替换 → 新实例启动 → 守护进程又崩 → 再次替换……
如果 Agent 配置有错误导致反复崩溃,这个循环很恐怖。建议上线前一定在测试环境跑稳了再推生产。
坑 3:公共 ECR 镜像的权限
用 public.ecr.aws 的镜像时,任务执行角色需要 ecr-public:GetAuthorizationToken 和 ecr-public:BatchGetImage 权限。这两个权限比较容易漏。
总结
Amazon ECS Managed Daemons 从架构层面解决了 sidecar 模式在规模化运维场景下的系统性缺陷。独立的 daemon task definition、daemon_bridge 网络模式、生命周期保证、滚动部署与自动回滚——每个设计决策都指向同一个目标:让平台工程师独立管控基础设施组件。
目前已在所有亚马逊云科技区域可用,不收额外费用。
参考资料:
- 亚马逊云科技官博:https://aws.amazon.com/cn/blogs/china/announcing-managed-daemon-support-for-amazon-ecs-managed-instances/
- Managed Daemons 文档:https://docs.aws.amazon.com/AmazonECS/latest/developerguide/managed-daemons.html
- 操作指南:https://docs.aws.amazon.com/AmazonECS/latest/developerguide/managed-daemons-create-manage.html

浙公网安备 33010602011771号