You can support us by downloading this article as PDF from the Link below. Download the guide as PDF

This article is part 1 of a 4 part guide to running Docker containers on AWS ECS. ECS stands for Elastic Container Service. It is a managed container service that can run docker containers. Although AWS also offers container management with Kubernetes, (EKS) it also has its proprietary solution (ECS). The guide will cover:

  • Creating the ECS Cluster.
  • Provision an Image Registry (ECR) and push docker images to the registry.
  • Deploying Containers to the cluster using Task and Service Definitions.
  • Creating a Pipeline to Update the services running on the ECS Cluster.

This guide will cover how to create the ECS cluster.

Requirements/Prerequisites

Before proceeding with this guide, the reader/user must have:

  • An AWS Account.
  • Created a User on the account with Permissions to provision resources on the account.
  • Generated an EC2 SSH Key-Pair.
  • Created a VPC and Subnets (Optional).

A guide to create VPC and Subnets (AWS Network Architecture) can be found on the link below:

Creating the AWS ECS Cluster

There are two types of ECS clusters we can create.

  • ECS with Fargate cluster: This is a cluster that allows the user to run containers without the need to worry about provisioning and managing EC2 instances/servers. It is basically a serverless architecture.
  • ECS with EC2 Instances cluster: This cluster allows a user to run containers on provisioned EC2 instances. Hence the need to manage the servers.

Create an AWS ECS Cluster with Fargate Option

To create the cluster we can do so manually or automatically using either CloudFormation or Terraform. For this article, I will create the cluster using CloudFormation and manually.

CloudFormation:

The below CloudFormation Template creates an ECS cluster with a capacity provider as Fargate and Container Insights enabled. The reader should modify the template settings to customize to their specific requirements. Key aspects to change will be:

  • Tags.
  • The Cluster Settings.
AWSTemplateFormatVersion: "2010-09-09"
Description: "Create ECS fargate cluster"
Parameters:
    Name:
        Type: String
        Description: The name of the ECS Cluster

Resources:
    ECSCluster:
        Type: 'AWS::ECS::Cluster'
        Properties:
           ClusterName: !Ref Name
           ClusterSettings:
             - Name: containerInsights
               Value: enabled
           CapacityProviders:
             - FARGATE
           Tags: 
              - 
                Key: "Name"
                Value: "test-ecs"
              - 
                Key: "CreatedBy"
                Value: "Maureen Barasa"
              - 
                Key: "Environment"
                Value: "test"

Outputs:        
    ECS:
        Description: The created ECS Cluster
        Value: !Ref ECSCluster

Manually:

To manually create the cluster follow the below steps.

On the Elastic Container Services console, click create cluster.

Create Cluster

Then, for the cluster template, select Powered by Fargate as your option. Click next step.

Select Cluster Template (Powered by Fargate)

Finally, configure cluster setting and click create cluster. N/B: You can create a new VPC for the cluster. But this is optional.

Configure Cluster Settings

You now have your ECS Fargate cluster running.

Create an AWS ECS Cluster with EC2 Option

We can also do this using CloudFormation, Terraform, or manually.

CloudFormation:

For CloudFormation, use the below template.

AWSTemplateFormatVersion: "2010-09-09"
Description: "Create ECS fargate cluster"

Parameters:
    Name:
        Type: String
        Description: The name of the ECS Cluster

    VPC:
        Type: String
        Description: The vpc to launch the service
        Default: vpc-ID

    PrivateSubnet01:
        Type: String
        Description: The subnet where to launch the ecs instances
        Default: subnet-ID

    PrivateSubnet02:
        Type: String
        Description: The subnet where to launch the ecs instances
        Default: subnet-ID

    InstanceType:
        Type: String
        Description: The EC2 instance type
        Default: "t2.micro"

    MinSize:
        Type: String
        Description: The subnet where to launch the ec2
        Default: 1

    MaxSize:
        Type: String
        Description: The subnet where to launch the ec2
        Default: 2

    DesiredSize:
        Type: String
        Description: The subnet where to launch the ec2
        Default: 1

Resources:
    IAMInstanceRole:
        Type: 'AWS::IAM::Role'
        Properties:
          Description: The ECS Instance Role
          RoleName: ecsInstanceRole2
          AssumeRolePolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Principal:
                  Service:
                  - ec2.amazonaws.com
                Action:
                  - 'sts:AssumeRole'
          ManagedPolicyArns:
            - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role
            - arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy
            - arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
          Tags: 
            - 
              Key: "Environment"
              Value: "test"
            - 
              Key: "createdBy"
              Value: "Maureen Barasa"
            - 
              Key: "Name"
              Value: "ecsInstanceRole2"

    IAMInstanceProfile:
        Type: AWS::IAM::InstanceProfile
        Properties: 
            InstanceProfileName: ecsInstanceRole2
            Roles: 
             - !Ref IAMInstanceRole

    ECSSecurityGroup:
        Type: "AWS::EC2::SecurityGroup"
        Properties:
            GroupDescription: "Security Group to control access to the ECS cluster"
            GroupName: "test-ECS-SG"
            VpcId: !Ref VPC
            SecurityGroupIngress: 
              - 
                CidrIp: 0.0.0.0/0
                FromPort: 80
                IpProtocol: "tcp"
                ToPort: 80
              - 
                CidrIp: 0.0.0.0/0
                FromPort: 443
                IpProtocol: "tcp"
                ToPort: 443 
            Tags: 
              - 
                Key: "Name"
                Value: "test-ECS-SG"
              - 
                Key: "CreatedBy"
                Value: "Maureen Barasa"
              - 
                Key: "Environment"
                Value: "test"        

    ECSCluster:
        Type: 'AWS::ECS::Cluster'
        Properties:
           ClusterName: !Ref Name
           ClusterSettings:
             - Name: containerInsights
               Value: enabled
           Tags: 
              - 
                Key: "Name"
                Value: "test-ecs"
              - 
                Key: "CreatedBy"
                Value: "Maureen Barasa"
              - 
                Key: "Environment"
                Value: "test"

    ECSAutoScalingGroup:
        Type: AWS::AutoScaling::AutoScalingGroup
        Properties:
            VPCZoneIdentifier: 
              - !Ref PrivateSubnet01
              - !Ref PrivateSubnet02
            LaunchConfigurationName: !Ref LaunchConfiguration
            MinSize: !Ref MinSize
            MaxSize: !Ref MaxSize
            DesiredCapacity: !Ref DesiredSize
            HealthCheckGracePeriod: 300
            Tags: 
              - 
                Key: "Name"
                Value: "test-ecs"
                PropagateAtLaunch: true
              - 
                Key: "CreatedBy"
                Value: "MaureenBarasa"
                PropagateAtLaunch: true
              - 
                Key: "Environment"
                Value: "test"
                PropagateAtLaunch: true

    LaunchConfiguration:
        Type: AWS::AutoScaling::LaunchConfiguration
        Properties:
            ImageId: "ami-ID"
            SecurityGroups: 
              - !Ref ECSSecurityGroup
            InstanceType: !Ref InstanceType
            IamInstanceProfile: !Ref IAMInstanceProfile
            KeyName: "test-key"
            UserData:
              Fn::Base64: !Sub |
                #!/bin/bash
                echo ECS_CLUSTER=test-ecs >> /etc/ecs/ecs.config;echo ECS_BACKEND_HOST= >> /etc/ecs/ecs.config;
            BlockDeviceMappings: 
              - 
                DeviceName: "/dev/xvda"
                Ebs: 
                    Encrypted: false
                    VolumeSize: 20
                    VolumeType: "gp2"
                    DeleteOnTermination: true
            
            
Outputs:
    IAMProfile:
        Description: The created EC2 Instance Role
        Value: !Ref IAMInstanceProfile

    AutoScalingGroup:
        Description: The ECS Autoscaling Group
        Value: !Ref ECSAutoScalingGroup    

    ECS:
        Description: The created ECS Cluster
        Value: !Ref ECSCluster

On the parameter section of the template, enter the specific customized inputs for your cluster. This include:

  • The VPC and Subnets.
  • The Instance Type and Auto Scaling Group Scaling Requirements.

Under the resources section. Take note to customize:

  • Resources Names and Tags.
  • The Key Name of your EC2 launch configuration (Use a Key-Pair you have generated).
  • The AMI-ID for your EC2 Instances. (Use an Amazon ECS-optimized AMIs on your account).

After the CloudFormation finishes executing the stack, You should now have an ECS cluster with a registered active EC2 container instance. See below:

ECS Cluster with a Container Instance

Manually:

To create the cluster manually follow the below steps:

Create an ECS Instance Role with the following AWS Managed Policies:

  • AmazonS3ReadOnlyAccess
  • CloudWatchAgentServerPolicy
  • Amazon EC2ContainerServiceforEC2Role

Edit the role trust relationship and add the below JSON trust policy.

{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

Then, on the Elastic Container Service console, click create cluster. This time on the select cluster template window, instead of opting for Powered by Fargate, choose EC2 Linux + Networking option. Click next step.

Select Cluster Template

Next, you need to configure your cluster. On cluster configuration, we have 3 main sections:

  • Cluster Name
  • Instance Configuration
  • Networking

Cluster Name:

Cluster Name

Instance Configuration:

Instance Configurations

Ensure you select the correct instance configurations specific to your requirements.

Networking:

Networking Configurations

Here, there is an option to create a new VPC, and Subnets should the user not have created his/her own. If they had already created a Network Architecture, the reader can use the existing setup. The same applies to the security group for the cluster. A new one can be created or we can choose an existing one.

Then, for the container instance IAM Role, select the role you created above. Enable container insights by checking the box next to enable container insights.

Configure IAM Role and Container Insights

Finally click, create cluster. You will have a cluster up and running in a few minutes.

Below is a link to part 2 of this series where I discuss deploying containers to the cluster using Task and Service Definitions.

Running Docker Containers on AWS ECS – Upload Docker Images to ECR – Part 2

AWS ECS: Deploying Containers using Task and Service Definitions – Part 3

Tags:

  • How to create AWS ECS Cluster manually
  • How to create AWS ECS Cluster with CloudFormation
  • How To Run Docker containers on AWS With ECS – Part 1

More guides on AWS:

Mount AWS EFS File System on EC2 Instance

How To Create AWS EFS Filesystem With CloudFormation

Happy Building!!!

You can support us by downloading this article as PDF from the Link below. Download the guide as PDF