Transformation

Creating a Fargate ECS Task in AWS using Terraform

This article explains how to run containers with the Fargate technology used in ECS. To carry out this task, Terraform ’s infrastructure software is used.

Containers are easily managed using the Amazon Elastic Container Service (Amazon ECS) provided by AWS. This tool makes containers scalable and faster, facilitating their running, stopping, and managing in a cluster. Fargate launch type is a specific ECS technology that enables cluster holding in a serverless infrastructure. For more control, a different type of launch is required (Amazon ECS).

What is Terraform and What are the Basic Files for Task Launching

Terraform is an open source software. It allows the creation of this infrastructure’s construction plan via another programming language. It enables infrastructure to be expressed as code (Infrastructure as Code). With this technology, infrastructure management is simplified using a basic and unified syntax. A great advantage of working with Terraform is that the implemented configurations can be reused and shared across various projects.

Before defining the Fargate type ECS Task, the basic necessary files for the task launching will be defined here. The task launching explanation will follow.

First, Terraform’s Provider file will be created. This file will be used to start AWS in our project on the required version. The file name will be provider.tf and will include the following information:

provider "aws" {
  version = ">= 1.58.0, <= 2.0.0"
  region = var.aws_region
  access_key = var.aws_access_key
  secret_key = var.aws_secret_key
}

After this, a variable definitions file will be required. The file’s name will be variables.tf and it will define both the authentication variables and the ones that the application needs:

variable "aws_access_key" {} 
variable "aws_secret_key" {} 
variable "aws_region" {}

Then, the value of the above defined variables will be added to another file named terraform.tfvars. Terraform will automatically load this file:

aws_access_key = "aws-access-key" 
aws_secret_key = "aws-secret-key" 
aws_region = "eu-west-1"

The next step is  the creation of all necessary network components: VPC, subnets, and cluster where our ECS task will be defined. For the sake of brevity, it will be assumed that all subnets are public. The file name is network.tf:

resource "aws_ecs_cluster" "cluster" {
  name = "cluster-name"
}
resource "aws_vpc" "aws-vpc" { 
  cidr_block = "10.0.0.0/16" 
  enable_dns_hostnames = true
}

Lastly, defining policies and roles based on the requirements of our task will be necessary for ECS task to correctly launch. This code will be added to a file named iam.tf with the defined roles and policies needed in our task:

resource "aws_iam_role" "ecs_task_execution_role" {
  name = "role-name"
 
  assume_role_policy = <<EOF
{
 "Version": "2012-10-17",
 "Statement": [
   {
     "Action": "sts:AssumeRole",
     "Principal": {
       "Service": "ecs-tasks.amazonaws.com"
     },
     "Effect": "Allow",
     "Sid": ""
   }
 ]
}
EOF
}

resource "aws_iam_role" "ecs_task_role" {
  name = "role-name-task"
 
  assume_role_policy = <<EOF
{
 "Version": "2012-10-17",
 "Statement": [
   {
     "Action": "sts:AssumeRole",
     "Principal": {
       "Service": "ecs-tasks.amazonaws.com"
     },
     "Effect": "Allow",
     "Sid": ""
   }
 ]
}
EOF
}
 
resource "aws_iam_role_policy_attachment" "ecs-task-execution-role-policy-attachment" {
  role       = aws_iam_role.ecs_task_execution_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}

resource "aws_iam_role_policy_attachment" "task_s3" {
  role       = "${aws_iam_role.ecs_task_role.name}"
  policy_arn = "arn:aws:iam::aws:policy/AmazonS3FullAccess"
}

Creating a Fargate Launch Type ECS Task 

AWS Fargate is a serverless compute engine that works with both ECS and Amazon Elastic Kubernetes Service (EKS). This technology removes the need to equip and manage servers.  This way we  only use the resources needed by the application and improve security throughout application isolation.

AWS Fargate isn’t available in all regions. To work with it, first verify its availability in your working region. Check the AWS documentation for more information regarding this matter.  This article uses the European (Ireland) region as an example: eu-west-1.

AWS

With Terraform, the ECS task definition will be implemented in order to run Docker containers:

resource "aws_ecs_task_definition" "definition" {}

For a task definition of an ECS task, there are a series of parameters that will be used. Some are mandatory and some optional but useful in this case:

  • family: is a mandatory string-type parameter. This parameter is the name of the task definition to which AWS will also assign a revision number.
  • taskRoleArn: is an optional and string type parameter. To define a task with this parameter an IAM role can be provided which enables the containers to have the required permissions and then to activate other AWS services.
  • executionRoleArn: an optional and string type parameter. A task execution role can be provided through this parameter to enable containers to  extract images and publish logs on CloudWatch on its behalf. 
  • networkMode: string type parameter which is not required. This parameter is the Docker network mode that is going to be used on this task’s containers.  There are different types, and in this case we will use awsvpc. With this type, an elastic network interface is assigned. 
  • cpu: integer type parameter which is not required The number of cpu units that Amazon ECS will reserve for the container is defined via this parameter.
  • memory: is an optional, integer type parameter. It defines the amount (in MiB) of memory that will be reserved for the container. 

To specify the type of launch that will be used in defining the task, the following parameter will be used:

  • requiresCompatibilities: it will be called FARGATE in this case. It is array type of string parameter which is not required. Through this it is possible to guarantee that all the used parameters on its definition are meeting their launch type requirements.
resource "aws_ecs_task_definition" "definition" {
  family                   = "task_definition_name"
  task_role_arn            = "${var.ecs_task_role}"
  execution_role_arn       = "${var.ecs_task_execution_role}"
  network_mode             = "awsvpc"
  cpu                      = "256"
  memory                   = "1024"
  requires_compatibilities = ["FARGATE"]
  }

Once all the optional requirements and parameters which will be used are defined, we then define the containers through which our task will be executed. It is a compulsory parameter type and a list type provided with a single JSON document. 

A series of permitted parameters will be specified in the container definition. The two most important, mandatory definitions  would be: 

  • name: a string type parameter. It is the name of a container that supports up to 255 characters.
  • image: a string type parameter. It will define the image that is used to start the container. In our case the URL of a previously uploaded Amazon ECR repository image and its version will be specified.

The image used by the container has been created from a Docker file. This image is stored in the docker container registry provided by Amazon through the Amazon Elastic Container Registry.

docker

Another optional but very useful parameter for any container definition is:

  • logConfiguration: an object type Log Configuration parameter. In order to configure the container registration, we have to take into account that for Fargate-type launch tasks,  additional software has to be installed outside the task.  In our case the registry controller awslogs will be used.
  • environment: an object array type parameter. Through this parameter we transfer the environment variables to our container.
  • secrets: an object array type parameter: name and valueFrom. The secrets parameter together with the valueFrom allows the transfer of a value to the container provided with a full ARN. It then allows us to make use of AWS Secrets Manager in our example.

Here a complete definition of a container as a JSON document can be seen:

container_definitions = <<DEFINITION
[
  {
    "image": "${var.account}.dkr.ecr.eu-west-1.amazonaws.com/project:latest",
    "name": "project-container",
    "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-region" : "eu-west-1",
                    "awslogs-group" : "stream-to-log-fluentd",
                    "awslogs-stream-prefix" : "project"
                }
            },
    "secrets": [{
        "name": "secret_variable_name",
        "valueFrom": "arn:aws:ssm:region:acount:parameter/parameter_name"
    }],           
    "environment": [
            {
                "name": "bucketName",
                "value": "${var.bucket_name}"
            },
            {
                "name": "folder",
                "value": "${var.folder}"
            }
        ]
    }
  
]
DEFINITION
}

Terraform Execution and Launch of the ECS Task

In order to launch the ECS task follow these steps:

  1. We position ourselves where our code is located and then run the terraform init command from the terminal: 
  2. The terraform plan command can then be executed, and we will obtain the execution plan as a result.  This is very useful to verify if it meets your expectations without making any changes.
  3. To conclude, we run the terraform apply command on the command line and therefore build  the entire infrastructure:

Conclusion

As we have seen, thanks to AWS Fargate together with the power provided by Terraform, an application inside a container can be lifted, managed, and launched very quickly and easy. This is just one example of one of the many benefits provided by AWS.

 References

open-apis-ebook

Grow without limits with Open APIs

The best option to improve the positioning of your company, making it more profitable in an increasingly competitive market.

Written By

Jose Manuel Martínez

Integration engineer