Introduction to Fargate with CloudFormation

TOC

Configuration for Getting Started with Fargate with CloudFormation

AWS Fargate is a serverless service that allows you to run Docker containers.
In this introduction to Fargate, I’ll show you how to configure CloudFormation to run a container on Fargate.

Environment

Diagram of Introduction to Fargate with CloudFormation.

Create an ECS cluster and associate a Fargate-type ECS task with the public subnet.
The tasks will be created using the following two types of images:

  1. an image that is publicly available on DockerHub
  2. an image that we created ourselves and pushed to ECR

In both containers, we will start Nginx, give it a public address, and run it as an HTTP server.

CloudFormation template files

We will build the above configuration using CloudFormation.
We will place a sample CloudFormation template at the following URL

https://github.com/awstut-an-r/awstut-fa/tree/main/018

Explanation of key points of template files

We will cover the key points of each template file to configure this architecture.

ECR Repository

Define ECR.

Resources:
  Repository:
    Type: AWS::ECR::Repository
    Properties:
      RepositoryName: !Ref Prefix
Code language: YAML (yaml)

Container 2 uses a self-made image.
Therefore, you need to prepare a repository to store your own images.

No special configuration is required, just set the repository name in the RegistoryName property.

Define ECS cluster

Create ECS cluster-related resources.
The first is a cluster.

Resources:
  Cluster:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: !Sub "${Prefix}-cluster"
Code language: YAML (yaml)

A cluster is a group of services and tasks.
It is the foundation on which containers are launched.

No special configuration is required, just specify the cluster name in the ClusterName property.

Define permissions required to execute task as IAM role

Executing a task, i.e., starting a container, is itself not allowed by default.
For example, actions such as pulling an image from ECR are included in the task execution.
Therefore, it is necessary to prepare a dedicated IAM role and grant permissions to it.

Resources:
  FargateTaskExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ecs-tasks.amazonaws.com
            Action:
              - sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
Code language: YAML (yaml)

AWS management policy provides “AmazonECSTaskExecutionRolePolicy” which summarizes the minimum privileges for task execution.
We will use this policy this time.
The following actions are allowed in this policy.

  • ecr:GetAuthorizationToken
  • ecr:BatteryCheckLayerAvailability
  • ecr:GetDownloadUrlForLayer
  • ecr:BatchGetImage
  • logs:CreateLogStream
  • logs:PutLogEvents

We can see that the content permits ECR to retrieve images and the layers that make up the images, and to write data to CloudWatch Logs.

Task Definition

Create task definitions and services.
First, check the task definitions for the two containers.
A task definition is a set of parameters to execute a container.
It specifies the image to be executed, CPU, memory, etc.

Resources:
  TaskDefinition1:
    Type: AWS::ECS::TaskDefinition
    Properties:
      RequiresCompatibilities:
        - FARGATE
      Cpu: !Ref TaskCpu
      Memory: !Ref TaskMemory
      NetworkMode: awsvpc
      ExecutionRoleArn: !Ref FargateTaskExecutionRole
      TaskRoleArn: !Ref TaskRole
      ContainerDefinitions:
        - Name: !Sub "${Prefix}-task1-container"
          Image: nginx:latest

  TaskDefinition2:
    Type: AWS::ECS::TaskDefinition
    Properties:
      RequiresCompatibilities:
        - FARGATE
      Cpu: !Ref TaskCpu
      Memory: !Ref TaskMemory
      NetworkMode: awsvpc
      ExecutionRoleArn: !Ref FargateTaskExecutionRole
      TaskRoleArn: !Ref TaskRole
      ContainerDefinitions:
        - Name: !Sub "${Prefix}-task2-container"
          Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${RepositoryName}:latest"
Code language: YAML (yaml)

The two resources are almost identical.

The difference between the two is the image that the container is based on.
The former is the official nginx image available on Docker Hub.
Specify the image name in the Image property in ContainerDefinitions.

Specify “FARGATE” for the RequiresCompatibilities property.
This means that the task defined in this resource needs to run on a Fargate-type service.

Specify the CPU and memory allocation for a single task in the Cpu and Memory properties.
In this case, we specified 512 (0.5vCPU) for CPU and 1024 (1GB) for memory.
Please note that if you set the values lower than these values, the task will not start properly in the container to be run this time.

The NetworkMode property specifies the network mode of the task; in the case of Fargate, it should be “awsvpc”.

If you are using the Fargate launch type, the awsvpc network mode is required.

AWS::ECS::TaskDefinition NetworkMode

In the task definition, there are two IAM role-related parameters: the ExecutionRoleArn property and the TaskRoleArn property.
The former has been described earlier, and is organized again as follows.

  • Task execution IAM role (ExecutionRoleArn): Permissions required to execute the task itself, such as the permission to pull the Docker image from the ECR.
  • Task Roles (TaskRoleArn): Permissions assigned to the containers to be executed in the task. This will be described later.

Specify the ARN of the IAM role you prepared for each.

Prepare services

The next step is to define a service for the two containers.
A service is a function that manages and adjusts the number of tasks.
For example, scaling of tasks can be configured for a service.

Resources:
  Service1:
    Type: AWS::ECS::Service
    Properties:
      Cluster: !Ref Cluster
      LaunchType: FARGATE
      DesiredCount: 1
      TaskDefinition: !Ref TaskDefinition1
      ServiceName: !Sub "${Prefix}-service1"
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: ENABLED
          SecurityGroups:
            - !Ref ContainerSecurityGroup
          Subnets:
            - !Ref PublicSubnet1

  Service2:
    Type: AWS::ECS::Service
    Properties:
      Cluster: !Ref Cluster
      LaunchType: FARGATE
      DesiredCount: 1
      TaskDefinition: !Ref TaskDefinition2
      ServiceName: !Sub "${Prefix}-service2"
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: ENABLED
          SecurityGroups:
            - !Ref ContainerSecurityGroup
          Subnets:
            - !Ref PublicSubnet2
Code language: YAML (yaml)

In the Cluster property, specify the cluster in which this service will be launched.

Specify the launch type of the service in the LaunchType property.
In this case, we will use the Fargate type, so we will use “FARGATE”.

The DesiredCount property allows you to specify the desired number of tasks to be launched on the service.
In this case, we will set it to “1” so that one task will be started.
If a task is stopped for some reason, a new task will be automatically started and the service will adjust to meet the desired number.

Specify the task definition to be executed in the TaskDefinition property.
Specify the security group that will be assigned to the task and the subnet on which it will be placed in the AwsvpcConfiguration property in the NetworkConfiguration property.
In this case, we will create two public subnets, and we will specify to place one container on each.

Prepare IAM roles for what the task will do

Finally, define the IAM role for the task.

Resources:
  TaskRole1:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ecs-tasks.amazonaws.com
            Action:
              - sts:AssumeRole
Code language: YAML (yaml)

The container is empty.
This is because the container we are going to create will only run as a web server and will not access any AWS services.

Dockerfile, etc

Prepare a file for the image you will create.

This is the Dockerfile.

FROM nginx:latest

COPY index.html /usr/share/nginx/html

EXPOSE 80
Code language: Dockerfile (dockerfile)

Using the official image of nginx as a base, place your own index.html file on the main page.

This is index.html.

<html>
  <head>
  </head>
  <body>
    <h1>fa-018 index.html</h1>
  </body>
</html>
Code language: HTML, XML (xml)

This is a simple HTML file.

Architecting

We will use CloudFormation to build this environment and check its actual behavior.
In this article, we will create a CloudFormation stack in two parts.

Create ECR repository

First, create an ECR repository.
The following is an example of creating a stack from a template file placed in an S3 bucket.

$ aws cloudformation create-stack \
--stack-name fa-018-ecr \
--template-url https:/[bucket-name].s3.[region].amazonaws.com/fa-018-ecr.yaml
Code language: Bash (bash)

The next step is to push the Docker image to the ECR repository you created. The necessary commands can be found in the AWS Management Console.

Detail of ECR Repository 1.

The result of executing the above command is as follows.

Detail of ECR 2.

You can confirm that the image has been pushed successfully.

Create rest of CloudFormation stacks

Create a CloudFormation stack.
Please continue to check the following pages for more information on creating stacks and how to check each stack.

あわせて読みたい
CloudFormation’s nested stack 【How to build an environment with a nested CloudFormation stack】 Examine nested stacks in CloudFormation. CloudFormation allows you to nest stacks. Nested ...

After checking the resources for each stack, the information for the main resources created this time is as follows

  • ECS cluster: fa-018-cluster
  • ECS service 1 name: fa-018-service-1-service
  • ECS Service 2 name: fa-018-service-2-service

Check the created resources from the AWS Management Console.
First, check the cluster.

List of ECS clusters that have been created.

You can see that the cluster has indeed been created.

Next, let’s check the details of the cluster.

Detail of ECS Cluster 2.

You can see that there are two services running in the cluster.

Check the details of the tasks running on each service.

Detail of ECS Cluster 3.
Detail of ECS Task 2.

You can see the public address assigned to each task.

Access to Containers

Now that you are ready, you can actually access the site from your browser.

Result of ECS 1.
Result of ECS 2.

I was able to access each container normally.
The former is the top page of the official Nginx image, and the latter is the HTML file of the self-made image.

Summary

Using CloudFormation, we were able to create a Fargate-type ECS container.

TOC