Fargate 上多个容器(django、nginx)的最佳实践

Best practice for multiple Container(django,nginx) on Fargate

我有多个containers/images比如admin(django),nginx(httpserver)

我的系统在下面。

port80-> nginx -> port8011 -> admin

我想在 fargate 上部署这些。

然而我还是一头雾水

两个镜像,两个容器,两个任务定义,两个负载均衡器就可以了。

但是一个publicIP只能给nginx?

容器之间如何连接?

目前我的源码是这样的

我熟悉 docker-compose,但不熟悉 aws fargate。

感谢任何帮助。

const VPCID='vpc-0867d6797e62XXXXX';
const vpc = ec2.Vpc.fromLookup(this, "VPC", {
  vpcId:VPCID
  //isDefault: true,
});

const cluster = new ecs.Cluster(this, "SampleCluster", {
  vpc:vpc,
  clusterName: "StAdminNginxCluster"
});

const adminRepo = ecr.Repository.fromRepositoryArn(this, 'AdminRepository', 'arn:aws:ecr:ap-northeast-1:678100XXXXXX:repository/st_admin_site');
const nginxRepo = ecr.Repository.fromRepositoryArn(this, 'NginxRepository', 'arn:aws:ecr:ap-northeast-1:678100XXXXXX:repository/st_nginx');

const adminImage = ecs.ContainerImage.fromEcrRepository(adminRepo,"latest");
const nginxImage = ecs.ContainerImage.fromEcrRepository(nginxRepo,"latest");

//make task definition
     const taskDefinitionAdmin = new ecs.FargateTaskDefinition(this, "TaskDefAdmin",{
  memoryLimitMiB: 512,
  cpu: 256,
});
const taskDefinitionNginx = new ecs.FargateTaskDefinition(this, "TaskDefNginx",{
  memoryLimitMiB: 512,
  cpu: 256,
});
const adminContainer = taskDefinitionAdmin.addContainer("AdminContainer", {
  image: adminImage,
});
const nginxContainer = taskDefinitionNginx.addContainer("NginxContainer", {
  image: nginxImage,
});

adminContainer.addPortMappings({
  containerPort: 8011
});
nginxContainer.addPortMappings({
  containerPort: 80
})

const ecsServiceAdmin = new ecs.FargateService(this, "ServiceAdmin", {
  cluster,
  taskDefinition:taskDefinitionAdmin,
  desiredCount: 2
});
const ecsServiceNginx = new ecs.FargateService(this, "ServiceNginx", {
  cluster,
  taskDefinition:taskDefinitionNginx,
  desiredCount: 2
});

const lbAdmin = new elb.ApplicationLoadBalancer(this, "LBAdmin", {
  vpc: cluster.vpc,
  internetFacing: true
});
const listenerAdmin = lbAdmin.addListener("Listener", { port: 8011 });

const targetGroupAdmin = listenerAdmin.addTargets("ECSAdmin", {
  protocol: elb.ApplicationProtocol.HTTP,
  port: 8011,
  targets: [ecsServiceAdmin]
});

const lbNginx = new elb.ApplicationLoadBalancer(this, "LBNginx", {
  vpc: cluster.vpc,
  internetFacing: true
});
const listenerNginx = lbNginx.addListener("Listener", { port: 80 });

const targetGroupNginx = listenerNginx.addTargets("ECS", {
  protocol: elb.ApplicationProtocol.HTTP,
  port: 80,
  targets: [ecsServiceNginx]
});

这个 docker-compose 有效。

version: "3.9"
   
services:

  admindjango:
    image: 678100XXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/st_admin_site:latest
    ports:
      - "8011:8011"
    restart: always 

  nginx:
    image: 678100XXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/st_nginx:latest
    ports:
      - '80:80'
    depends_on:
      - admindjango

更新

我用两个容器定义一个任务。

我刚从一个 taskDifinition.addContainer 中调用了两次 addContainer

(暂时忽略loadbalancer

您也可以通过 127.0.0.1:XXX 访问每个容器。

它很适合我的目的。感谢 @Mark B

const taskDefinitionAdmin = new ecs.FargateTaskDefinition(this, "TaskDefAdmin",{
  memoryLimitMiB: 512,
  cpu: 256,
});
const adminContainer = taskDefinitionAdmin.addContainer("AdminContainer", {
  image: adminImage,
});
adminContainer.addPortMappings({
  containerPort: 8011,
  hostPort: 8011
});
const nginxContainer = taskDefinitionAdmin.addContainer("NginxContainer", {
  image: nginxImage,
});

nginxContainer.addPortMappings({
  containerPort: 80,
  hostPort: 80
})
const adminSG = new ec2.SecurityGroup(this, 'admin-server-sg', {
  vpc,
  allowAllOutbound: true,
  description: 'security group for a web server',
});

adminSG.addIngressRule(
  ec2.Peer.anyIpv4(),
  ec2.Port.tcp(80),
  'allow SSH access from anywhere',
);

const ecsAdminService = new ecs.FargateService(this, "AdminService", {
  cluster,
  taskDefinition:taskDefinitionAdmin,
  desiredCount: 2,
  vpcSubnets:  {subnetType: ec2.SubnetType.PUBLIC },
  assignPublicIp: true,
  securityGroups:[adminSG]
});

How can I connect between container?

在您当前的配置中,您无法在容器之间直接连接。您必须让 Nginx 连接到连接到 Django 任务的内部负载平衡器。

Web 浏览器 -> Public Nginx 负载均衡器 -> Nginx 容器 -> 私有 Django 负载均衡器 -> Django 容器。


我建议查看 运行 同一 ECS 任务中的两个容器。如果只拥有一个负载均衡器和一半数量的 Fargate 实例,您可能会节省一大笔钱。流量看起来像这样:

Web 浏览器 -> Public 负载均衡器 -> 端口 80 上的 Nginx 容器 -> 端口 8011 上的 Django 容器。

在那种情况下,您可以将 Nginx 配置为将请求代理到 127.0.0.1:8011。同一任务中的所有容器都可以在 Fargate 实例内通过 127.0.0.1 相互连接。请参阅 Fargate 网络文档 here


更高级的设置是将每个容器 运行 作为一个单独的任务,并使用 AWS App Mesh 进行内部容器通信,而不是内部负载平衡器。对于您的情况,这可能有点矫枉过正,并且更适合具有许多独立部署的微服务的大型环境。