Register EC2 instance to ECS cluster using Terraform CDK

As we can deploy containerised applications to ECS (Elastic Container Service), using both the launch types - EC2 and Fargate.

It is very simple to create an ECS cluster and attach an ECS compatible EC2 instance to it from the AWS console itself (registration of EC2 instance to ECS cluster is done by amazon while creating a cluster).

But if you are using terraform or terraform CDK, then you need to specify every single attribute (required only) and if you feel all this is painful, then this article is for you. We are going to make it easy.

Not going in depth for the ECS concepts. If you want to go through the concepts, this article will help you understand ECS. We are using EC2 instance to run container service in our ECS cluster.

First we need to create an ECS container. The container creation and EC2 instance creation are independent on each other. You just need to be careful of container name while passing it with user data to the instance (user data will attach instance to the cluster).

Create and ECS container:

We can create and ECS container using ecs provider. Import the provider first.

import { EcsCluster } from "./.gen/providers/aws/ecs";

And then create the cluster.

new EcsCluster(this, 'test-ecs-nginx', {
	name: "test-ecs-nginx",
});

Secondly, to create EC2 instance, an instance profile must be created with AmazonEC2ContainerServiceforEC2Role as the policy and must be attached to EC2 instance

Create IAM role:

To create an IAM role, we can use Iam resource from the AWS provider.

We'll be needing few more resources for role and policy attachment (IamRolePolicyAttachment, IamInstanceProfile).

Add the following line to import the resources from the provider.

import { IamRole, IamRolePolicyAttachment, IamInstanceProfile } from "./.gen/providers/aws/iam";

Add the following code to create a new IAM role.

const ecsRole = new IamRole(this, "test-ecs-nginx-role", {
      name: "test-ecs-nginx-role",
      assumeRolePolicy: Fn.jsonencode({
        "Version": "2012-10-17",
        "Statement": [
          {
            "Action": "sts:AssumeRole",
            "Principal": {
              "Service": "ec2.amazonaws.com"
            },
            "Effect": "Allow",
            "Sid": ""
          }
        ]
      })
    });

Attach IAM policy to the IAM role:

The IAM role we have created must be attached to AmazonEC2ContainerServiceforEC2Role policy. The policy is provided by AWS.

new IamRolePolicyAttachment(this, "role-attachment", {
      role: ecsRole.name,
      policyArn: "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role"
    });

Create an instance profile:

Create an instance profile using the IAM role created in the step above.

const instanceProfile = new IamInstanceProfile(this, "ecs-instance-profile", {
      name: "ecs-instance-profile",
      path: "/",
      role: ecsRole.id
    });

Get the latest ECS compatible EC2 instance AMI:

Amazon time to time updates its AMI's. We want the latest ECS compatible EC2 ami.

You can get the ami directly from the AWS console. But we want to do it through code. For that, we are going to use AWS AMI data source and add a filter to it to get the required ami.

const dataAwsAmiOutput = new DataAwsAmi(this, "data-aws-ami", {
      mostRecent: true,
      owners: ["amazon"],
      filter: [{
        name: "name",
        values: ["amzn2-ami-ecs-hvm-2.0.202*-x86_64-ebs"]
      }]
    });
  • mostRecent: Flag to get the most recent image
  • owners: Owner of the image, in this case, "amazon" is the owner.
  • filter: Multiple filters can be provided. We are providing regex filter on the image name.

Create EC2 instance:

We have created all the required resources. We are good to go ahead and create an EC2 instance.

const ec2Instance = new Instance(this, "ec2-ecs-instance", {
      ami: dataAwsAmiOutput.id,
      subnetId: subnet.id, // change this to your subnet id
      instanceType: "t3.micro",
      ebsOptimized: true,
      userData: "#!/bin/bash \n" +
          "cat <<'EOF' >> /etc/ecs/ecs.config \n" +
          "ECS_CLUSTER=test-ecs-nginx \n" +
          "EOF",
      iamInstanceProfile: instanceProfile.name,
      securityGroups: [],
      tags: {
        Name: "Test EC2 ECS instance"
      }
    });
  • ami - The ECS compatible ami id.
  • subnetId - The subnet in which you want to launch your EC2 instance.
  • instanceType: Type of the instance.
  • ebsOptimized:
  • userData: Script to run while bringing up the instance. Here, we need to update the ECS cluster name in the instance's ECS config so that the instance get registered to the cluster.
  • iamInstanceProfile: The instance profile with the required role and policy.
  • securityGroups: The required security groups.
  • tags: Tags of the image

Deploy the changes:

Use CDKTF to deploy the resources. This will create and register EC2 instance to the ECS cluster.

cdktf deploy
Kiran Kamalakar

Kiran Kamalakar

Design and development enthusiast.
Pune, India