Quick Start: Build & Deploy Your Application with AWS Fargate

Donnie Prakoso
Developer, self-proclaimed barista and cafe racer enthusiast. This blog is a collection of my writings on technology.
Published
Monday, September 17, 2018
Info
views
Category
article
Translations

There are two AWS services that have been the core foundations for all my (previous) works, AWS Lambda, and Amazon API Gateway. The idea of not managing infrastructure and only have to upload my code into the cloud is invaluable for me. I only have to code my business logic and let Lambda does the rest. Then, I only have to connect it with Amazon API Gateway to route all requests to specific Lambda function. It’s simply a joy.

However, there’s also a need to have a containerized application running to support a business. In a normal case, we can easily configure Amazon ECS to run our Docker-based application. Amazon ECS is a high-performance container orchestration service for Docker containers. To simply put it, you can run your Docker application with Amazon ECS and let it manage and scale it for you. With Amazon ECS, you can have a fleet of EC2 instances in which Amazon ECS will manage the installation and placing your containers into EC2 instances.

A Serverless Container Service

Yet, the idea of having everything in a serverless architecture is still intriguing for me as I’m not a fan of doing much on operations. I’d rather focus on building features. I want to write my code, Dockerized my application, and just deploy it. I want to have something similar when I do development for my applications with Lambda. This approach is particularly useful if you have a finite number of a development team, like what I had in my previous startup. By minimizing the need to maintain operations on your infrastructure, it gives us more room to focus more on our product.

If my case sparks your interest, you will definitely find AWS Fargate is useful for you. With AWS Fargate, you can run your containerized application without having to manage any servers. Sounds like a serverless way to run a containerized application? Yes, it is. With AWS Fargate, I no longer need to manage the infrastructure on my own and I only need to focus on development.

In this post, I want to share with you how I usually build applications for my demos by utilizing Fargate. My objective is for you to have a foundation on how you can build and deploy using Fargate.

Let's Rock!
This post is an introductory post to AWS Fargate. Also, this post can be a guide for you to deploy an application with AWS Fargate using a simple application that I wrote and frequently use.

1. Requirements

There are various ways on how we can run through this tutorial. For an example, I’m going to use AWS CLI to create all AWS resources needed as I found it more straightforward but you can also use AWS console. Below are tools that I’ll use throughout this post, so you might want to install these packages before you follow this tutorial.

What do I need? Why? Where I can download it?
Hello Racer code Code repository that used for this tutorial. You can fork or clone this repo. Github
AWS CLI To interact with AWS resources AWS CLI
JQ To make processing JSON file a lot easier 1 JQ
Git If you want to clone my code, you’ll need it for sure Git
Python3 Just in case you are feeling adventurous Python
Docker To package your application Docker
Vim My favorite, besides Sublime Cheatsheet!

1.1 Upgrading AWS CLI

Don’t forget to get the latest version of your AWS CLI. To upgrade your AWS CLI, you can run the following command on your terminal.

pip install awscli --upgrade --user

After you run this command, you’ll have the latest AWS CLI command equipped with latest features to interact with AWS resources.

2. Write Your Code

For the sake of simplicity, I will use a simple application that I wrote as a demo which you can find it after you cloned my code repository on Github.

2.1 Code

from flask import Flask, render_template
from flask import jsonify


app = Flask(__name__,static_url_path='/assets',static_folder='assets',template_folder='assets/templates')

@app.route("/ping/")
def ping():
 data = {}
 data["text"]="pong"
 return jsonify(data),200

@app.route("/")
def hello():
 service = {}
 service["text"]="Hello, Racer!" 
 return render_template("index.html", service=service)

if __name__ == "__main__":
 app.run(debug=True, host='0.0.0.0', port=80)

As you can see, it’s a simple Python3 application using Flask Microframework. Obviously, you can use write your own application and still using the following steps to deploy it using AWS Fargate.

3. Dockerize It!

After we are sure that our application runs as what we expected, now it’s time to do some work on building Docker image.

3.1 Create Dockerfile

This Dockerfile use base image from python:3.6-slim and set the workdir to /app and after that, it copies every file needed into /app directory. To make sure that our application satisfies all requirements, we have to run pip install. This application runs on port 80.

FROM python:3.6-slim
WORKDIR /app
COPY . /app
RUN pip install --no-cache-dir -r requirements.txt
EXPOSE 80
CMD ["python", "app.py"]

3.1 Build, Tag and Push Docker Image

In this section, what we are going to do is to build a Docker image based on what has been instructed on Dockerfile. After we’ve finished building the Docker image, we need to push the image into container repository. This container repository will act as a registry that holds our Docker images. In this post, I use Docker Hub to host my Docker image.

Below are the commands that you can use to build, tag and push your Docker image into Docker Hub.

docker build -t hello-racer .
docker tag hello-racer:latest <YOUR_DOCKER_ID>/hello-racer:latest
docker push <YOUR_DOCKER_ID>/hello-racer:latest

You can also pull my Docker image that I’ve made it available as public hosted on Docker hub with the following command.

docker pull donnieprakoso/hello-racer:latest
Amazon ECR
If you’re looking for a fully managed container registry, check out Amazon ECR. Amazon ECR will be your option if you want to have better integration with Amazon ECS and other AWS services.

4. Deploy Application with AWS Fargate

4.1 Create IAM Roles

This step will guide you on how you can create an IAM role that you’ll need to use in your task definition 2. This IAM role will help Amazon ECS to find a suitable permission when it executes your application. There’s nothing fancy here, in this tutorial we only need to have 2 existing policies, AmazonECSTaskExecutionRolePolicy and CloudWatchLogsFullAccess. If you’ve cloned my repository, you can find all the required files needed under /aws.

export HELLO_RACER_IAM_TASK_ROLE=`aws iam create-role --role-name "helloRacer-executionRole" --assume-role-policy-document file://aws/iam-trustPolicy-task.json | jq -c '.Role.Arn'`
Important
One thing if you’re working with CLI is sometimes you have a tendency to forget few values that are required in the next step. So, you need to take note all of those values. Those commands above will help you to record all required value with a little help from JQ and then the value is being exported to environment variables so you can retrieve the values if you need it.

In this step, you will have all the required IAM roles. Now, we need to attach the policy to those IAM roles so Amazon ECS can run our application.

aws iam attach-role-policy --role-name helloRacer-executionRole --policy-arn "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"

aws iam attach-role-policy --role-name helloRacer-executionRole --policy-arn "arn:aws:iam::aws:policy/CloudWatchLogsFullAccess"

4.1 Create Task Definition

Now comes the fun part. Remember about task definition 2? It’s essential to create a task definition prior deploying your application so Amazon ECS understands the configuration for your application.

Under /aws folder, you’ll find a task definition in JSON format. If you take a look into the file, you’ll find one variable that you’ll need to replace with your own IAM role ARN value. You can either edit it directly or to make it more simple, you can use sed for this purpose. Below is a simple sed command that you can use:

sed -e "s|REPLACE_ME_WITH_HELLO_RACER_IAM_TASK_ROLE|$HELLO_RACER_IAM_TASK_ROLE|g" aws/ecs-task-definition.json > output/ecs-task-definition.json

After you make necessary changes, it will generate the output in /output folder that you can use it to register this task definition into Amazon ECS.

aws ecs register-task-definition --cli-input-json file://output/ecs-task-definition.json

4.2 Create A Cluster

Now we have our task definition. What we need to do next is to create a cluster. This simple command below will create a cluster in which we want to put our application.

export HELLO_RACER_CLUSTER_ARN=`aws ecs create-cluster --cluster-name "hello-racer" | jq -c '.cluster.clusterArn'`

4.3 Prepare Your VPC and Security Group

For this demo, as there are no special needs for networking, we can use our default VPC. You can easily get your VPC ID by using the following command

aws ec2 describe-vpcs

However, if you’ve installed JQ, you’re in luck because you can use the following command to easily get your default VPC ID.

export HELLO_RACER_VPC_ID=`aws ec2 describe-vpcs | jq -c '.Vpcs[] | select(.IsDefault == true) | .VpcId'`

Now we need to create a security group and allow port 80 as an inbound rule so we can access it.

export HELLO_RACER_SECURITY_GROUP_ID=`aws ec2 create-security-group --group-name "securityGroup-helloRacer" --description "Security Group for helloRacer" | jq -c '.GroupId'`
aws ec2 authorize-security-group-ingress --group-name "securityGroup-helloRacer" --protocol tcp --port 80 --cidr 0.0.0.0/0

4.3 Deploy using AWS Fargate

We’re now in the final stage and what we need to do now is to deploy our application with AWS Fargate. Service in Amazon ECS, allows you to run and maintain a specified number of instances of a task definition simultaneously in an Amazon ECS cluster. I’d always like to think that creating a service also means that gluing altogether, starting from your container defined in task definition, security groups, subnets and also desired count of your tasks.

To create a service, we need to populate /aws/ecs-create-service.json file with all variables needed. First, we need to get the subnet ID and store it as an environment variable.

export HELLO_RACER_SUBNET_ID=`aws ec2 describe-subnets | jq -c "[.Subnets[] | select(.VpcId==$HELLO_RACER_VPC_ID)][0] | .SubnetId"`

Now you have all required environment variables if you do

echo $HELLO_RACER_

…and double tab it, you’ll see that you have following variables:

  • HELLO_RACER_CLUSTER_ARN
  • HELLO_RACER_IAM_TASK_ROLE
  • HELLO_RACER_SECURITY_GROUP_ID
  • HELLO_RACER_SUBNET_ID
  • HELLO_RACER_VPC_ID

You can edit and replace it manually one by one all variables on /aws/ecs-create-service.json file, or you can use following command to prepare your file for creating service:

sed -e "s|REPLACE_ME_WITH_HELLO_RACER_SUBNET_ID|$HELLO_RACER_SUBNET_ID|g"  -e "s|REPLACE_ME_WITH_HELLO_RACER_SECURITY_GROUP_ID|$HELLO_RACER_SECURITY_GROUP_ID|g" aws/ecs-create-service.json > output/ecs-create-service.json

That’s it, now you can create a service using following command:

aws ecs create-service --cli-input-json file://output/ecs-create-service.json

Now it’s currently creating the service for you. You can monitor the progress by using aws ecs wait command as follow:

aws ecs wait services-stable --services svc-hello-racer --cluster hello-racer

If you’re doing every step correctly, you have deployed an application using AWS Fargate. Nicely done!

4.4 Test Your Application

It’s time to test our application! This tutorial only deploys one task and Fargate will allocate a public IP address for your newly created task. We now need to get the public IP address for your task and open the URL using your browser.

Every task in Amazon ECS has its own ARN, as we only deployed one task, we can get it by retrieving the value for the first index and modify it to get the task ID. From there, we’ll need to get Elastic Network Interface which attached to the task in order to get the public IP address. Following commands will help you to get it.

export HELLO_RACER_TASK_ARN=`aws ecs list-tasks --cluster hello-racer --output json --query "taskArns[0]"`
export HELLO_RACER_TASK_ID=`echo $HELLO_RACER_TASK_ARN | sed -e 's|"||g' | cut -f 2 -d "/"`
export HELLO_RACER_TASK_ENI_ID=`aws ecs describe-tasks --tasks $HELLO_RACER_TASK_ID --cluster hello-racer | jq -c '.tasks[0].attachments[0].details[] | select(.name=="networkInterfaceId") | .value'`
aws ec2 describe-network-interfaces --network-interface-ids "[$HELLO_RACER_TASK_ENI_ID]" | jq -c '.NetworkInterfaces[].PrivateIpAddresses[].Association.PublicIp'

The last command, aws ec2 describe-network-interfaces will give you an output, which is the public IP address associated with your task. Now you only need to open the address using your browser. It would show you something like this.

Web screenshot

4.5 Cleaning Up

Once you have finished with this tutorial, please don’t forget to delete all resources or you will incur additional charges. To help you remember all those resources used in this tutorial, I’ve prepared a checklist so you won’t miss out a thing. You can easily use the AWS console to remove all resources created with this tutorial.

What We’ve Learned

If you followed the tutorial correctly, now you have a running Docker application and deployed it using AWS Fargate. Congratulations! As for the summary, below are the required steps for you to deploy your application using AWS Fargate.

Next Steps

Understanding how to deploy your application with AWS Fargate will give you a good foundation to bring your application to the next level. So, few ideas on how you can extend your application are configuring CI/CD with AWS Fargate, Code Pipeline, and Code Build, or configuring ELB and also auto-scaling with AWS Fargate.

For those who want to learn more, here are a few links that might be useful for you:

If you have any questions or you want to discuss this topic further with me, feel free to ping me on Twitter @donnieprakoso.

GO BUILD!


  1. AWS CLI also has a built-in JQ for a simple query. However, as we’re going to use several custom queries, it’s highly advised to install JQ. [return]
  2. Task definition is a set of instructions that tells Amazon ECS how to run Docker containers. Simply put, task definition is the blueprint for your application. [return]
Like this article?
Give this article a love or you can share this article with others.
Previously
It's a Secret!

AWS Secrets Manager is a handy tool that you can use to store your credentials, secrets or sensitive information to be used in your applications.

Read More

Published
Monday, September 17, 2018
Info
views
Category
article
Translations

Donnie Prakoso
Developer, self-proclaimed barista and cafe racer enthusiast. This blog is a collection of my writings on technology.

Codes & Notes. by Donnie Prakoso
© @donnieprakoso · 2019