How do I use Amazon ECS service discovery in AWS CloudFormation?

Last updated: 2019-05-28

How do I use Amazon Elastic Container Service (Amazon ECS) service discovery in AWS CloudFormation?

Short Description

The AWS::ECS::Service resource type provided by AWS CloudFormation doesn't create service discovery resources. This is different than the Amazon ECS console, which allows you to create service discovery resources during service creation.

Note: The Amazon ECS console uses the integration APIs CreatePrivateDnsNamespace, CreateService (AWS Cloud Map), and CreateService (Amazon ECS). In AWS CloudFormation, you can use the resource types AWS::ServiceDiscovery::PrivateDnsNamespace, AWS::ServiceDiscovery::Service, and AWS::ECS::Service to implement an integration in a single AWS CloudFormation template.

Resolution

1.    In your AWS CloudFormation template, in the Resources section, create a private service discovery namespace (for example, awsExampleNamespace) in one of your existing VPCs. See the following examples:

JSON:

{
  "PrivateNamespace": {
    "Type": "AWS::ServiceDiscovery::PrivateDnsNamespace",
    "Properties": {
      "Name": "awsExampleNamespace",
      "Vpc": "vpc-xxxxxxx"
    }
  }
}

YAML:

PrivateNamespace:
    Type: AWS::ServiceDiscovery::PrivateDnsNamespace
    Properties:
        Name: awsExampleNamespace
        Vpc: vpc-xxxxxxx

Replace vpc-xxxxxxx with the ID of a VPC from your account.

2.    Create a service discovery service using the namespace ID of the namespace that you created in Step 1. You can get the value of the namespace ID using the Ref intrinsic function in your AWS CloudFormation template. See the following examples:

JSON:

{
  "DiscoveryService": {
    "Type": "AWS::ServiceDiscovery::Service",
    "Properties": {
      "Description": "Discovery Service for the Demo Application",
      "DnsConfig": {
        "RoutingPolicy": "MULTIVALUE",
        "DnsRecords": [
          {
            "TTL": 60,
            "Type": "A"
          },
          {
            "TTL": 60,
            "Type": "SRV"
          }
        ]
      },
      "HealthCheckCustomConfig": {
        "FailureThreshold": 1
      },
      "Name": "awsExampleNamespace",
      "NamespaceId": {
        "Ref": "PrivateNamespace"
      }
    }
  }
}

YAML:

DiscoveryService:
  Type: AWS::ServiceDiscovery::Service
  Properties: 
    Description: Discovery Service for the Demo Application
    DnsConfig:
      RoutingPolicy: MULTIVALUE
      DnsRecords:
        - TTL: 60
          Type: A
        - TTL: 60
          Type: SRV
    HealthCheckCustomConfig: 
      FailureThreshold: 1
    Name: awsExampleNamespace
    NamespaceId: !Ref PrivateNamespace

The DnsConfig property specifies the DNS records that are automatically created in Amazon Route 53 when your Amazon ECS task is registered with the service discovery service.

Note: DNS records of type A and SRV are supported.

Important: We recommended that you use the HealthCheckCustomConfig property to allow Amazon ECS to report task health to service discovery. Amazon ECS uses information from container checks, health checks, and task state to update the health of service discovery with AWS Cloud Map.

3.    To create an Amazon ECS service that integrates with the service discovery namespace and service that you created the previous steps, specify the integration using the ServiceRegistries property in the AWS:ECS::Service resource. See the following examples:

JSON:

{
  "EcsService": {
    "Type": "AWS::ECS::Service",
    "Properties": {
      "Cluster": "awsExampleCluster",
      "DesiredCount": 4,
      "LaunchType": "FARGATE",
      "NetworkConfiguration": {
        "AwsvpcConfiguration": {
          "SecurityGroups": [
            "sg-xxxxxxx"
          ],
          "Subnets": [
            "subnet-xxxxxxx"
          ]
        }
      },
      "ServiceName": "demo-service",
      "TaskDefinition": "awsExampleTaskDefinition",
      "ServiceRegistries": [
        {
          "RegistryArn": {
            "Fn::GetAtt": [
              "DiscoveryService",
              "Arn"
            ]
          },
          "Port": 80
        }
      ]
    }
  }
}

YAML:

EcsService:
  Type: AWS::ECS::Service
  Properties:
    Cluster: awsExampleCluster
    DesiredCount: 4
    LaunchType: FARGATE
    NetworkConfiguration:
      AwsvpcConfiguration:
        SecurityGroups:
          - sg-xxxxxxx
        Subnets:
          - subnet-xxxxxxx
    ServiceName: demo-service
    TaskDefinition: awsExampleTaskDefinition
    ServiceRegistries:
      - RegistryArn: !GetAtt DiscoveryService.Arn
        Port: 80

Replace awsExampleCluster with your cluster, awsExampleTaskDefinition with your task definition, sg-xxxxxxx with your security group ID, and subnet-xxxxxxx with your subnet ID.

For the RegistryArn property, set the value to the ARN of the service discovery service that you want to integrate with your Amazon ECS service. Use the intrinsic function Fn::GetAtt to get this value from your AWS CloudFormation template.

If you use the awsvpc mode, set the value to either Port or a combination of ContainerPort and ContainerName (as specified in the task definition). If you use host or bridge mode, set the value to ContainerPort or ContainerName (as specified in the task definition).

4.    Open the AWS CloudFormation console, and then choose Create Stack to deploy the resources based on your updated template.

5.    To verify that your tasks can be resolved from within the VPC, run the following commands:

$ dig awsExampleService.awsExampleNamespace. +short
$ dig srv awsExampleService.awsExampleNamespace. +short
$ curl awsExampleService.awsExampleNamespace. -I

The commands return output similar to the following:

For $ dig awsExampleService.awsExampleNamespace. +short:

172.31.182.0
172.31.160.124
172.31.137.81
172.31.149.244

For $ dig srv awsExampleService.awsExampleNamespace. +short:

1 1 80 ffe95d27ea8d4f7aba0dfed87297fc5a.awsExampleService.awsExampleNamespace.
1 1 80 44a17fa781974a93bb563bc1826a8697.awsExampleService.awsExampleNamespace.
1 1 80 d640ecb3d283421bb2d1318caf4b0d66.awsExampleService.awsExampleNamespace.
1 1 80 65aff6fff33144b2ad79d283ab52cfe9.awsExampleService.awsExampleNamespace.

For $ curl awsExampleService.awsExampleNamespace. -I:

HTTP/1.1 200 OK
Server: nginx/1.15.12
Date: Wed, 15 May 2019 02:25:19 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 16 Apr 2019 13:08:19 GMT
Connection: keep-alive
ETag: "5cb5d3c3-264"
Accept-Ranges: bytes

Did this article help you?

Anything we could improve?


Need more help?