如何在EC2模式下为运行在AWS ECS集群中的容器分配公共IP



我正在尝试使用服务之间的服务发现来实现一个多服务ECS集群。我正在尝试学习教程"使用Amazon ECS CLI创建使用服务发现的Amazon ECS服务"。然而,它不包括一个完整的工作示例

我所做的是定义两个服务,通过使用定义:

  • docker-compose.yml
  • ecs-params.yml

我可以很容易地打开ECS集群和这两个服务。一切看起来都很好。但其中一项服务需要一个公共IP地址。因此,在相应的ecs-params.yml文件中,我放置了assign_public_ip: ENABLED。但是没有分配公共IP地址。在ECS控制台中,服务详细信息显示Auto-assign public IP DISABLED,对于Task,它列出了一个私有IP地址,没有列出公共IP地址。

不幸的是,根据awsvpc网络模式下任务网络的文档,这似乎是不可能的:

awsvpc网络模式不为使用EC2启动类型的任务提供具有公共IP地址的任务ENI。要访问互联网,使用EC2启动类型的任务应该在配置为使用NAT网关的专用子网中启动。有关更多信息,请参阅亚马逊专有网络用户指南中的NAT网关。入站网络访问必须使用专有IP地址从VPC内进行,或者通过VPC内的负载均衡器进行路由。在公用子网内启动的任务无法访问internet。

问题:如何绕过AWS ECS EC2发布类型的限制?

我不明白为什么EC2启动类型不支持公共IP地址?或者-我使用不同的网络模式,然后会分配一个公共IP地址吗?为什么AWS文档中没有更清楚地说明这一点?

源代码

集群创建使用:

ecs-cli up --cluster-config ecs-service-discovery-stack --ecs-profile ecs-service-discovery-stack --keypair notes-app-key-pair --instance-type t2.micro --capability-iam --force --size 2

正如上面的教程所建议的,定义了两个服务。backend(一个容器中的简单Node.js应用程序)和frontend(一个配置为代理后端的简单NGINX服务器)服务都在各自的目录中。每个目录中都有docker-compose.ymlecs-params.yml文件。

前端服务使用提供

ecs-cli compose --project-name frontend service up --private-dns-namespace tutorial --vpc ${VPC_ID}  --enable-service-discovery --container-port 80 --cluster ecs-service-discovery-stack --force-deployment

docker-compose.yml为:

version: '3'
services:
nginx:
image: USER-ID.dkr.ecr.REGION.amazonaws.com/nginx-ecs-service-discovery
container_name: nginx
ports:
- '80:80'
logging:
driver: awslogs
options: 
awslogs-group: simple-stack-app
awslogs-region: REGION
awslogs-stream-prefix: nginx

ecs-params.yml是:

version: 1
task_definition:
task_execution_role: ecsTaskExecutionRole
ecs_network_mode: awsvpc
task_size:
mem_limit: 0.5GB
cpu_limit: 256
run_params:
network_configuration:
awsvpc_configuration:
subnets:
- "subnet-00928d3fc1339b27b"
- "subnet-0ad961884e5f93fb1"
security_groups:
- "sg-0c9c95c6f02597546"
# assign_public_ip: ENABLED

后端服务是使用类似的命令和类似的docker-compose.ymlecs-params.yml文件启动的。

您是对的,当使用EC2启动类型时,不可能为ECS任务分配公共IP。

关于awsvpc以外的网络模式,它们也不会有帮助:

  • 如果网络模式设置为none,则任务的容器没有外部连接,并且无法在容器定义中指定端口映射
  • 如果网络模式为bridge,则任务使用Docker内置的虚拟网络,该网络在每个容器实例中运行
  • 如果网络模式为host,则该任务绕过Docker内置的虚拟网络,将容器端口直接映射到AmazonEC2实例的网络接口。在这种模式下,当使用端口映射时,不能在单个容器实例上运行同一任务的多个实例

选项A-负载均衡器

如果您希望通过互联网访问您的任务,您可以考虑创建集成负载均衡器的ECS服务,以便客户端能够将请求路由到您的任务。请注意,具有使用awsvpc网络模式的任务的服务仅支持应用程序负载平衡器和网络负载平衡器。

选项B-法盖特发射类型

另一种选择是使用Fargate启动类型配置ECS任务以接收公共IP地址:

当您使用Fargate启动类型创建ECS服务/任务时,您可以选择是否将公共IP关联到ECS任务使用的ENI。您可以参考如何配置网络,了解如何在ECS中使用Fargate Type服务配置公共IP。基于此配置,一旦任务运行,该任务使用的ENI应该具有公共IP,它将能够让您直接通过互联网访问该任务。

您可以设置以下内容:

NetworkMode.HOST的网络模式

离开assignPublicIpfalse

vpcSubnets保留为undefinedsecurityGroups保留为[]

您可以如下找到公共IP和公共DNS:

AWS控制台->亚马逊弹性容器服务->群集->CCD_ 26->基础设施->容器实例->container_instance_id->分别为公共IP或公共DNS

示例如下:https://github.com/LajosPolya/aws-cdk-templates/blob/main/deploy-ecs-with-ec2/lib/deploy-ecs-with-ec2-stack.ts#L9

这使用容器主机的公共IP。更多信息可以在这里的";使用公共子网和互联网网关";标题

此外,更多信息请点击此处:https://github.com/aws/aws-cdk/issues/13348

解决方案是使用主机模式而不是awsvpc模式,并确保主机ec2实例在VPC内。

最新更新