如何让 AWS ECS 自动将我的容器的端口映射到主机 (EC2)

How to have AWS ECS automatically map ports of my container to the host machine(EC2)

上下文:

我正在使用 Circle CI 的 aws-ecs/deploy-service-update orb 来部署我的 docker 容器,方法是在 AWS ECR 中拉取最新的图像并将其部署在带有 AWS EC2 实例的 AWS ECS 中。这个容器是一个机器学习模型,它在 TCP 端口 3000 上接受 API 请求(我为此使用 fastAPI)和 returns 预测。部署后,我无法向在端口 3000 部署容器的任务的容器实例的 public IP 发送请求(此 IP 不是我的 EC2 实例的 public IP;它只有私有 IP 并且 public IP 已禁用)。

调试

  1. 我检查了我的安全组并确保端口 3000 已打开以接收来自所有 IP (0.0.0.0) 的请求,作为入站规则的一部分。
  2. 我停止了任务(它会自动停止 EC2 实例中的容器 运行ning),我认为 Circle CI 可能出了点问题。然后,根据 AWS ECS 的服务配置(1 个所需任务)和任务定义,一个新任务(因此容器)自动启动。但是,我也无法向其发送请求。
  3. 我通过 SSH 连接到我的 EC2 实例以了解端口 3000 是否打开。这是我得知端口根本没有映射的时候:
    如您所见,容器的 PORTS 列为空,并且容器必须接受来自命令的端口 3000 的请求。

下面是 EC2 实例的开放端口: 如您所见,此处未列出端口 3000。


这是部署容器(到 AWS ECS)的端口映射任务,如上图 docker ps 屏幕截图所示:
在任务定义中可以看到我为容器定义的端口映射。


这是我的 EC2 实例上的任务 运行ning,任务定义如上所示,我使用的网络模式是 'awsvpc':


这里是任务关联的ENI的“Networking”选项卡,以及任务所在的EC2实例关联的安全组的入站规则运行ning在里面,它接受3000端口的请求来自所有IP。

编辑 1:

我做了之后

docker run -p 3000:3000 <my-image:my-tag>

在 EC2 机器内部(通过从我的笔记本电脑进行 SSH 连接),我可以发送 API 请求并接收对容器的正确响应到 AWS ECS 集群的 public IP。这意味着只有当我手动 运行 容器时才会映射端口。

当我使用 FARGATE 时,当我从 Circle CI 更新服务时,甚至当我手动启动任务时,我的端口都没有问题。

那么,当来自 AWS ECS 服务仪表板或来自 Circle CI 的任务 运行 时,如何自动映射端口?如果我手动 运行 docker 容器,我将无法从 AWS Cloudwatch 自动获取日志,也无法从 AWS ECS 仪表板停止它。 AWS 的另一个容器 运行ning 在 EC2 实例中将处理这些事情。它会将日志路由到 Cloudwatch 并接受停止现有日志并启动命令以使用存储在 AWS ECR 中的新图像启动新容器,而无需每次我想查看日志或 start/stop 容器时都使用 SSH。

这里出了什么问题,导致端口没有被映射,我该如何修复它并正确映射端口,这样我就可以向我的容器发送 API 请求。

对于 awsvpc 网络模式,端口映射的工作方式略有不同。 hostPort 在这里不是有效选项,创建的 ENI 会将容器端口暴露给 VPC。

此模式有几个先决条件,例如 ECS 代理版本、实例类型(ENI 计数限制)、实例配置文件……查看官方 AWS 文档: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-networking.html

您检查过是否连接了 ENI 以及这些 ENI 上打开了哪些端口?

我犯的错误是使用了FARGATE优化集群和其中的EC2实例;这可能导致我的应用程序无法使用网络模式(默认、网桥、主机、awsvpc 和 none)。因此,当我重做与上次相同的所有内容,但使用 EC2 优化的集群类型时,bridge 网络模式按预期工作。