Using Amazon ECS Fargate with AWS SAM CLI
Dependencies
This pattern uses the AWS SAM CLI for deploying CloudFormation stacks on your AWS account. You should follow the appropriate steps for installing SAM CLI.
About
AWS SAM CLI streamlines the deployment of your containerized applications and necessary infrastructure resources efficiently. An extension of AWS CloudFormation, SAM CLI simplifies serverless application deployment and management by allowing you to define infrastructure as code. This facilitates version control and reproducibility, simplifying the packaging and deployment of your application code, dependencies, and configurations.
This pattern will show how to deploy a simple nodeJS application to AWS Fargate using AWS SAM CLI. The following resources will be created as part of the provided templates:
- Fargate Cluster
- Amazon Elastic Container Registry
- Fargate Service
- Fargate Task Definition
- Amazon VPC
- Internet Gateway
- 2 Public Subnets
- 2 Private Subnets
- Application Load Balancer
Architecture
The following diagram shows the architecture that will be deployed:
Define your Infrastructure
The following AWS SAM CLI template.yml creates a simple Amazon ECS cluster using AWS Fargate.
As part of the template.yml
, the following resources will be created:
- Amazon ECS Cluster
- ECR Repo
- Log Group
- All IAM related roles/policies
In addition to the template.yml
, you will also need a vpc.yml
, where the necessary network resources are defined.
Finally, AWS SAM CLI will also look for a samconfig file, which contains default parameters for your Infrastructure as Code.
- template.yml
- vpc.yml
- samconfig.toml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS Fargate with VPC, ALB, and ECR
Parameters:
ImageTag:
Description: tag name for image
Type: String
Default: latest
Globals:
Function:
Timeout: 3
MemorySize: 128
Resources:
VPC:
Type: AWS::Serverless::Application
Properties:
Location: ./vpc.yml
ECRRepo:
Type: AWS::ECR::Repository
Properties:
EmptyOnDelete: true
Cluster:
Type: AWS::ECS::Cluster
Properties:
CapacityProviders:
- FARGATE
Service:
Type: AWS::ECS::Service
Properties:
ServiceName: "hello-world"
Cluster: !Ref Cluster
LaunchType: FARGATE
EnableExecuteCommand: true
HealthCheckGracePeriodSeconds: 5
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
Subnets: [!GetAtt "VPC.Outputs.PublicSubnet1", !GetAtt VPC.Outputs.PublicSubnet2]
SecurityGroups: [!GetAtt VPC.Outputs.SG]
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 50
DesiredCount: 1
TaskDefinition: !Ref "TaskDefinition"
LoadBalancers:
- ContainerName: "hello-world"
ContainerPort: 3000
TargetGroupArn: !GetAtt VPC.Outputs.LB
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: HelloWorld
Cpu: 1024
Memory: 8192
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn
TaskRoleArn: !Ref ECSTaskRole
RuntimePlatform:
CpuArchitecture: X86_64
ContainerDefinitions:
- Name: hello-world
Cpu: 1024
Memory: 8192
Image: !Sub
- ${RepoUrl}:${ImageTag}
- RepoUrl: !GetAtt ECRRepo.RepositoryUri
PortMappings:
- ContainerPort: 3000
LogConfiguration:
LogDriver: awslogs
Options:
mode: non-blocking
max-buffer-size: 25m
awslogs-group: !Ref LogGroup
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: containerlog
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: /fargatelogs
ECSTaskExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [ecs-tasks.amazonaws.com]
Action: ['sts:AssumeRole']
Condition:
ArnLike:
aws:SourceArn: !Sub arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:*
StringEquals:
aws:SourceAccount: !Ref AWS::AccountId
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
ECSTaskRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [ecs-tasks.amazonaws.com]
Action: ['sts:AssumeRole']
Condition:
ArnLike:
aws:SourceArn: !Sub arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:*
StringEquals:
aws:SourceAccount: !Ref AWS::AccountId
Path: /
Outputs:
ClusterName:
Description: Amazon ECS Cluster Name
Value: !Ref Cluster
ServiceName:
Description: Amazon ECS Service Name
Value: !GetAtt Service.Name
FQDN:
Description: URL for your application
Value: !GetAtt VPC.Outputs.PublicLBFQDN
RepositoryUrl:
Description: URL of the repo
Value: !GetAtt ECRRepo.RepositoryUri
You will also need an application you can deploy to your infrastructure. For the purpose of this demo, a simple Hello World nodeJS application is provided for you.
- index.js
- package.json
- Dockerfile
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => {
res.send('Hello World!')
res.status(200).json
})
app.listen(port, () => {
console.log(`Access your application at`, `http://localhost:${port}`)
})
module.exports = app
Once you have the files downloaded, you can deploy your infrastructure using the following commands:
sam build && sam deploy
Test it Out
After the provided templates are deployed, you can find the the following AWS CloudFormation outputs using the following commands:
RepositoryUrl=$(aws cloudformation --region us-east-1 describe-stacks --stack-name nodejs-sam --query "Stacks[0].Outputs[?OutputKey=='RepositoryUrl'].OutputValue" --output text) && echo $RepositoryUrl
FQDN=$(aws cloudformation --region us-east-1 describe-stacks --stack-name nodejs-sam --query "Stacks[0].Outputs[?OutputKey=='FQDN'].OutputValue" --output text) && echo $FQDN
WARNING
Note: You will want to build and push your container image prior to deploying this application to Fargate.
The default template will look for the image in your provisioned Amazon Elastic Container Registry with the tag "latest". Once the image exists, you will be able to test your application using the output retrieved from the FQDN command.
TIP
In Production, it's not best practice to use the latest
tag for your containerized application images. Instead, you'll want to tag your images per release as part of your CI/CD workflow or pipeline.