0

i am having troubles setting up my AWS VPC via cdk. I want to create a VPC with 2 subnets, one public and one private_isolated, with no nat gateways and one internet gateway. In the public i will host my node web server and in the private my java microservice. Since i don't know a lot about networking in general, i used a private dns namespace and got the 2 services communicate to each other via AWS Service Discovery*. The thing is, when i deploy my stack, it gets stuck in creating the java fargate service, and i think the problem is because of the private_isolated subnet. So i added interface endpoints for ecr_docker and ecr and even an s3 gateway endpoint, but the service still remains stuck on create in progress. Here's my code:

export class EcsServiceDiscoveryStack extends Stack {
 readonly serviceBack = "back-service";
 readonly servicePdf = "pdf-service";
 readonly namespace = "env.test";
 readonly vpc: Vpc;
 readonly cluster: Cluster;
 readonly dnsNamespace: PrivateDnsNamespace;
 readonly ingressSecurityGroup: SecurityGroup;
 readonly egressSecurityGroup: SecurityGroup;

 constructor(scope: Construct, id: string, props?: StackProps) {
  super(scope, id, props);

  /* ----------------------------------- VPC ---------------------------------- */

  const subnetConfig: ec2.SubnetConfiguration[] = [
   {
    name: "test-public-subnet",
   subnetType: SubnetType.PUBLIC,
   },
   {
    name: "test-private-subnet",
    subnetType: SubnetType.PRIVATE_ISOLATED,
   },
  ];

  this.vpc = new ec2.Vpc(this, "test-vpc", {
   maxAzs: 1,
   subnetConfiguration: subnetConfig,
   gatewayEndpoints: {
    S3: { service: ec2.GatewayVpcEndpointAwsService.S3 },
   },
  });

  /* ------------------------- INTERFACE VPC ENDPOINT ------------------------- */
  this.vpc.addInterfaceEndpoint("aws-ecr_docker-endpoint", {
   service: ec2.InterfaceVpcEndpointAwsService.ECR_DOCKER,
   privateDnsEnabled: true,
   subnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
   open: true,
  });

  this.vpc.addInterfaceEndpoint("aws-ecr-endpoint", {
   service: ec2.InterfaceVpcEndpointAwsService.ECR,
   privateDnsEnabled: true,
   subnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
   open: true,
  });

  /* --------------------------------- CLUSTER -------------------------------- */

  this.cluster = new ecs.Cluster(this, "test-cluster", {
   clusterName: "test-cluster",
   vpc: this.vpc,
  });

  /* ------------------------------ DNS NAMESPACE ----------------------------- */

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

  /* -------------------------------- TASK ROLE ------------------------------- */

  //NODE
  const backTaskrole = new iam.Role(this, "backTaskExecutionRole", {
   assumedBy: new iam.ServicePrincipal("ecs-tasks.amazonaws.com"),
  });

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

  //JAVA
  const pdfTaskRole = new iam.Role(this, "pdfTaskExecutionRole", {
   assumedBy: new iam.ServicePrincipal("ecs-tasks.amazonaws.com"),
  });

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

  /* ---------------------------- TASKS DEFINITIONS ---------------------------- */
 
  //NODE
  const backFargateTaskDefinition = new ecs.FargateTaskDefinition(
   this,
   `${this.serviceBack}ServiceTaskDef`,
   {
    cpu: 256,
    memoryLimitMiB: 512,
    taskRole: backTaskrole,
   }
  );

  //JAVA
  const pdfFargateTaskDefinition = new ecs.FargateTaskDefinition(
   this,
   `${this.servicePdf}ServiceTaskDef`,
   {
    cpu: 256,
    memoryLimitMiB: 512,
    taskRole: pdfTaskRole,
   }
  );

  /* ---------------------------- SERVICE LOG GROUP --------------------------- */

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

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

  /* ------------------------------- LOG DRIVER ------------------------------- */

  //NODE

  const backServiceLogDriver = new ecs.AwsLogDriver({
   logGroup: backServiceLogGroup,
 

---
  streamPrefix: `${this.serviceBack}Service`,
  });

  //JAVA

  const pdfServiceLogDriver = new ecs.AwsLogDriver({
   logGroup: pdfServiceLogGroup,
   streamPrefix: `${this.servicePdf}Service`,
  });

  /* ---------------------------- REPOISTORY (ECR) ---------------------------- */

  //NODE
  const repoBackNode = Repository.fromRepositoryName(
   this,
   "back-nodejs",
   "task-nodejs-test"
  );

  //JAVA
  const repoBackJava = Repository.fromRepositoryName(
   this,
   "pdf-java",
   "task-nodejs-test"
  );

  /* -------------------------------- CONTAINER ------------------------------- */

  //NODE

  const backServiceContainer = backFargateTaskDefinition.addContainer(
   `${this.serviceBack}ServiceContainer`,
   {
    containerName: `${this.serviceBack}ServiceContainer`,
    essential: true,
    image: ecs.ContainerImage.fromEcrRepository(repoBackNode),
    logging: backServiceLogDriver,
    portMappings: [{ containerPort: 80 }],
    environment: {
     PORT: "80",
     NAME: "back-nodejs",
     PDF_HOST: `http://${this.servicePdf}.${this.namespace}:80`,
    },
   }
  );

  //JAVA
  const pdfServiceContainer = pdfFargateTaskDefinition.addContainer(
   `${this.servicePdf}ServiceContainer`,
   {
    containerName: `${this.servicePdf}ServiceContainer`,
    image: ecs.ContainerImage.fromEcrRepository(repoBackJava),
    logging: pdfServiceLogDriver,
    portMappings: [{ containerPort: 80 }],
    environment: {
     PORT: "80",
     NAME: "pdf-java",
     PDF_HOST: this.servicePdf,
    },
   }
  );

  /* ----------------------------- SECURITY GROUP ----------------------------- */
  //VPC
  this.ingressSecurityGroup = new ec2.SecurityGroup(
   this,
   `IngressSecurityGroup`,
   {
    allowAllOutbound: true,
    securityGroupName: `IngressSecurityGroup`,
    vpc: this.vpc,
    description: "IngressSecurityGroup for the VPC",
   }
  );

  this.ingressSecurityGroup.connections.allowFromAnyIpv4(ec2.Port.tcp(80));


  //NODE
  const backServiceSecGroup = new ec2.SecurityGroup(
   this,
   `${this.serviceBack}ServiceSecurityGroup`,
   {
    allowAllOutbound: true,
    securityGroupName: `${this.serviceBack}ServiceSecurityGroup`,
    vpc: this.vpc,
    description: "Security Group for the nodejs server",
   }
  );


  backServiceSecGroup.connections.allowFrom(
   new ec2.Connections({
    securityGroups: [this.ingressSecurityGroup],
   }),
   ec2.Port.tcp(80),
   "Allow traffic on port 80 from the VPC ingress security group"
  );

  //JAVA
  const pdfServiceSecGroup = new ec2.SecurityGroup(
   this,
   `${this.servicePdf}ServiceSecurityGroup`,
   {
    allowAllOutbound: true,
    securityGroupName: `${this.servicePdf}ServiceSecurityGroup`,
    vpc: this.vpc,
    description: "Security Group for the java pdf service",
   }
  );
  pdfServiceSecGroup.connections.allowFrom(
   new ec2.Connections({
    securityGroups: [backServiceSecGroup],
   }),
   ec2.Port.tcp(80),
   "Allow traffic on port 80 from the backService security group"
  );

  /* ----------------------------- FARGATE SERVICE ---------------------------- */

  //NODE
  const backFargateService = new ecs.FargateService(
   this,
   `${this.serviceBack}Service`,
   {
    cluster: this.cluster,
    taskDefinition: backFargateTaskDefinition,
    assignPublicIp: true,
    desiredCount: 1,
    securityGroups: [backServiceSecGroup],
    cloudMapOptions: {
     name: this.serviceBack,
     cloudMapNamespace: this.dnsNamespace,
     dnsRecordType: servicediscovery.DnsRecordType.A,
    },
   }
  );

  //JAVA
  const pdfFargateService = new ecs.FargateService(
   this,
   `${this.servicePdf}Service`,
   {
    cluster: this.cluster,
    taskDefinition: pdfFargateTaskDefinition,
    desiredCount: 1,
    securityGroups: [pdfServiceSecGroup],
    cloudMapOptions: {
     name: this.servicePdf,
     cloudMapNamespace: this.dnsNamespace,
     dnsRecordType: servicediscovery.DnsRecordType.A,
    },
   }
  );
 }
}

Where did i do wrong? Thanks in advance for your time

*i did a try with only public subnet, in order to verify service discovery was working

Mark B
  • 183,023
  • 24
  • 297
  • 295
RettoScorretto
  • 125
  • 1
  • 7
  • 1
    Does the ECS service deployment not fail eventually? It should fail and have an error message or failure reason listed on the service or task in the ECS web console. You are correct in thinking it is probably due to the lack of a NAT gateway. It would be interesting to see what happens if you added a NAT gateway. When you say you tried with only a public subnet, did the app actually deploy correctly? Perhaps the error is because ECS can't access Route53 for service discovery registration from the isolated subnet. – Mark B Dec 10 '22 at 16:07
  • 1
    You probably need to also add a VPC gateway for CloudWatch Logs. And if you are injecting secrets from SecretsManager or SSM Parameter Store you would need a gateway to those. If you "don't know a lot about networking in general" then you picked the most complicated setup by going with an isolated subnet. A private subnet with a NAT Gateway is much easier to configure. – Mark B Dec 10 '22 at 16:19
  • @MarkB ok so, the ECS deployment does not fail, it remains in create_in_progress forever. No error messages are displayed.i am not using SecretsManager nor SSM Parameter. I will try adding a NAT gateway and see what happens. Thanks for the response – RettoScorretto Dec 10 '22 at 20:48
  • @MarkB i switched to private subnet type, instead of private_isolated, and everything went fine, thanks also to the NAT gateway. Anyway in the near future, i would like to obtain the structure i wrote in the post before. Could you be so kind to point me some resources that, in your opinion, are a must read in order to understand aws vpc fully? – RettoScorretto Dec 11 '22 at 15:16

0 Answers0