Search code examples
amazon-web-servicesamazon-ecsaws-cdk

Connecting AWS ECS Services with the CDK


I want to deploy two containers into an ECS cluster, one gets called with HTTP from outside, and then it calls the other container, also via HTTP.

const cluster = new ecs.Cluster(this, "mycluster", {});
cluster.addDefaultCloudMapNamespace({ name: "local" });

new ecsPatterns.ApplicationLoadBalancedFargateService(this, "abc", {
  cluster,
  taskImageOptions: {
    containerPort: 8000,
    image: ecs.ContainerImage.fromRegistry("my/abc-image:latest"),
  },
});

const xyztask = new ecs.FargateTaskDefinition(this, "xyztask");
const xyz = xyztask.addContainer("xyzcontainer", {
  image: ecs.ContainerImage.fromRegistry("my/xyz-image:latest"),
});
xyz.addPortMappings({ containerPort: 8000 });
new ecs.FargateService(this, "xyz", {
  cluster,
  taskDefinition: xyztask,
  cloudMapOptions: { name: "xyz" },
});

The abc service looks like this:

const axios = require("axios");
const bodyParser = require("body-parser");
const express = require("express");

const app = express();
app.use(bodyParser.json());

app.post("/", async ({ body: { x } }, response) => {
  response.end(JSON.stringify({ x }));
  await axios.post(
    `http://xyz.local:8000/`,
    { x },
    { timeout: 3000 }
  );
});

app.listen(8000);

The xyz service looks like this:

const axios = require("axios");
const bodyParser = require("body-parser");
const express = require("express");

const app = express();
app.use(bodyParser.json());

app.post("/", async ({ body: { x } }, response) => {
  response.end();
});

app.listen(8000);

The abc service is available from the outside, but somehow the request to xyz always fails.


Solution

  • I try to make an educated guess as I see two starting points here:

    a) The issue is related to DNS resolution.
    You can check if this is the case by starting an EC2 instance inside the same subnet as the abc service and running: nslookup xyz.local. If the dns resolution yields the IP of the xyz service container(s), then DNS resolution is not an issue.

    b) The security group of the xyz service blocks incoming calls from the abc service. Outgoing connections are allowed by default, but incoming ones are usually not (except for the ApplicationLoadBalancedFargateService construct, which opens ALB's security group for connections from everywhere by default [1]). I guess the FargateService construct on the contrary does not open any incoming container ports by default, so you have to connect both services manually:

    // initialize both services as before
    const abc = new ecsPatterns.ApplicationLoadBalancedFargateService(...)
    const xyz = new ecs.FargateService(...);
    
    // add the ingress rule to xyz service for abc service's traffic via TCP port 8000
    xyz.connections.allowFrom(abc, Port.tcp(8000));
    

    I did not try this out yet, but these are two possible causes of your issue that come into my mind.

    References

    [1] https://github.com/aws/aws-cdk/blob/53f092f8a658e7b72adc996a0d06b18f7ca7ab4d/packages/%40aws-cdk/aws-ecs-patterns/lib/base/application-load-balanced-service-base.ts#L69