使用 CDK 定义带有服务发现的 ECS Fargate 集群,没有负载均衡器

Using CDK to define ECS Fargate cluster with Service Discovery, without Load Balancer

我们在 ECS 服务中使用 CDK and we are starting using service discovery(因此,服务器到服务器而不是客户端到服务器)。这意味着我们不需要 ALB(至少目前,也许我们可以稍后重新考虑这个选择)。

不幸的是,用于构建 ECS 服务的 CDK 模式 (ecs_patterns.ApplicationLoadBalancedFargateService) 也会创建一个 ALB,因此我们不能按原样使用它,我们需要自己创建这些 CDK 步骤。

这个想法基本上是将 this tutorial from AWS 从使用 AWS CLI“移植”到使用 CDK。

问题是:有没有人已经做过并想分享它或知道 CDK Patterns 没有该选项的原因?

(如果没有人要分享它,我们会做,然后当然分享;我认为这个选项应该立即出现在 CDK 中,只是不要浪费时间“只是”一个配置问题 – 除非我们在这里没有看到某些东西...)。

CDK 模式是一个很好的资源,但是它仅限于在 AWS 上部署基础设施的所有可能用例的一个子集,因此 'patterns'。

我没有使用 AWS 服务发现的个人经验,但 CDK 似乎确实为它提供了 L2 结构。 aws-servicediscovery

除了服务发现,您还可以使用 aws-ecs 库创建 L2 FargateService 结构。

好的,所以最后比预期的要容易。这是我的最终解决方案(并查看评论,因为我被卡住了几次):

/*
 * ECS Fargate with service discovery but without Load Balancing
 */
import * as cdk from "@aws-cdk/core";
import * as ec2 from "@aws-cdk/aws-ec2";
import * as ecs from "@aws-cdk/aws-ecs";
import * as servicediscovery from "@aws-cdk/aws-servicediscovery";
import * as iam from "@aws-cdk/aws-iam";
import * as logs from "@aws-cdk/aws-logs";
import { DnsRecordType } from "@aws-cdk/aws-servicediscovery";

export class EcsServiceDiscoveryStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const serviceName = "zambulo";
    const namespace = "caludio.magic";

    const vpc = ec2.Vpc.fromLookup(this, "VPC", {
      isDefault: true,
    });

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

    const dnsNamespace = new servicediscovery.PrivateDnsNamespace(
      this,
      "DnsNamespace",
      {
        name: namespace,
        vpc: vpc,
        description: "Private DnsNamespace for my Microservices",
      }
    );

    const taskrole = new iam.Role(this, "ecsTaskExecutionRole", {
      assumedBy: new iam.ServicePrincipal("ecs-tasks.amazonaws.com"),
    });

    taskrole.addManagedPolicy(
      iam.ManagedPolicy.fromAwsManagedPolicyName(
        "service-role/AmazonECSTaskExecutionRolePolicy"
      )
    );

    /*
     * Check the doc for the allowed cpu/mem combiations:
     * https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ecs.FargateTaskDefinition.html
     */
    const serviceTaskDefinition = new ecs.FargateTaskDefinition(
      this,
      `${serviceName}ServiceTaskDef`,
      {
        cpu: 256,
        memoryLimitMiB: 512,
        taskRole: taskrole,
      }
    );

    const serviceLogGroup = new logs.LogGroup(
      this,
      `${serviceName}ServiceLogGroup`,
      {
        logGroupName: `/ecs/${serviceName}Service`,
        removalPolicy: cdk.RemovalPolicy.DESTROY,
      }
    );

    /* Fargate only support awslog driver */
    const serviceLogDriver = new ecs.AwsLogDriver({
      logGroup: serviceLogGroup,
      streamPrefix: `${serviceName}Service`,
    });

    /*
     * If you chose a public image from the registry (like in this case),
     * the `assignPublicIp` in the Fargate definition (below) must be true
     */
    const serviceContainer = serviceTaskDefinition.addContainer(
      `${serviceName}ServiceContainer`,
      {
        image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"),
        logging: serviceLogDriver,
      }
    );

    serviceContainer.addPortMappings({
      containerPort: 80,
    });

    const serviceSecGrp = new ec2.SecurityGroup(
      this,
      `${serviceName}ServiceSecurityGroup`,
      {
        allowAllOutbound: true,
        securityGroupName: `${serviceName}ServiceSecurityGroup`,
        vpc: vpc,
      }
    );

    serviceSecGrp.connections.allowFromAnyIpv4(ec2.Port.tcp(80));

    new ecs.FargateService(this, `${serviceName}Service`, {
      cluster: cluster,
      taskDefinition: serviceTaskDefinition,
      // Must be `true` when using public images
      assignPublicIp: true,
      // If you set it to 0, the deployment will finish succesfully anyway
      desiredCount: 1,
      securityGroup: serviceSecGrp,
      cloudMapOptions: {
        // This will be your service_name.namespace
        name: serviceName,
        cloudMapNamespace: dnsNamespace,
        dnsRecordType: DnsRecordType.A,
      },
    });
  }
}