Post

Configure ECS private DNS (Service Discovery)


Ensuring effective communication among Elastic Container Service (ECS) services is paramount, particularly in automated processes. A robust solution is essential for establishing secure and highly available ECS tasks capable of seamless interaction. Leveraging the Private Hosted Zone within a Virtual Private Cloud (VPC) serves as a key component to achieve this.

To establish a private DNS for an AWS ECS cluster utilizing Service Discovery through AWS Cloud Map, the following general steps can be followed:

We will demonstrate these steps using CloudFormation and aws-cli.

1. Create the simple ECS Cluster with a dedicated namespace

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ECSCluster:
    Type: 'AWS::ECS::Cluster'
    Properties:
      ClusterName: My-Cluster
      ServiceConnectDefaults: 
        Namespace: !Ref Namespace
      
Namespace:
    Type: 'AWS::ServiceDiscovery::PrivateDnsNamespace'
    Properties:
      Description: AWS Cloud Map private DNS namespace for resources in backend services
      Vpc: !Ref Vpc
      Name: local
      Properties:
        DnsProperties:
          SOA:
            TTL: 60

2. Create ServiceDiscovery Service for the specific ECS Service you intend to run.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ServiceDiscovery:
    Type: 'AWS::ServiceDiscovery::Service'
    Properties:
      Description: Service based on a private DNS namespace
      DnsConfig:
        DnsRecords:
          - Type: A
            TTL: 60
          - Type: AAAA
            TTL: 60
        RoutingPolicy: WEIGHTED
      Name: example
      NamespaceId: !Ref Namespace

Outputs:
  OutputSD:
    Description: CloudFront Bucket
    Value: !GetAtt ServiceDiscovery.Arn
    Export:
      Name: ServiceDiscovery

3. Now we can run new ECS services and add them to the service registries.

  • Create Task Definition for a simple application: My_task.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
  "containerDefinitions": [
    {
      "name": "app",
      "image": "nginx:latest",
      "cpu": 512,
      "memory": 1024,
      "essential": true,
      "portMappings": [
        {
            "containerPort": 80,
            "hostPort": 80,
            "protocol": "tcp"
        }
      ],
    }
  ],
  "family": "app",
  "cpu": "512",
  "memory": "1024",
  "networkMode": "awsvpc",
  "executionRoleArn": "<My_TASK_EXECUTION_ROLE>",
  "taskRoleArn": "<My_TASK_ROLE>",
  "runtimePlatform": {
    "operatingSystemFamily": "LINUX"
  },
  "requiresCompatibilities": ["FARGATE"]
}
  • Register new Task Definition
1
aws ecs register-task-definition --cli-input-json file://My_task.json
  • Create ECS Service for the new Task Definition
1
2
3
4
5
6
7
8
9
aws ecs create-service \
    --cluster My-Cluster \
    --service-name My-Service-Name \
    --desired-count 1 \
    --launch-type "FARGATE" \
    --service-registries "registryArn=<OutputSD-ARN>,containerName=app"\
    --service-connect-configuration "enabled=true,namespace=local" \
    --task-definition My-Task \
    --network-configuration "awsvpcConfiguration={subnets=[PrivateSubnetA,PrivateSubnetB],securityGroups=[AppSG]}"

4. After starting the ECS Service, ServiceDiscovery creates a new DNS record in the Private Hosted Zone associated with the PrivateDnsNamespace we created earlier.

5. We can confirm connectivity to the service by performing a quick ping test from AWS CloudShell or any service running within the VPC.

1
ping example.local

To connect different services, you can use the new service name inside of other services. For instance, you can use an ECS Service to run a database and a separate ECS Service to run an application that needs to connect to that database. You can simply use the new DNS name app.local in Task Definition to connect.

This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.