Amazon Elastic Container Service (ECS) is a fully managed container orchestration service that simplifies the deployment and management of containerized applications. AWS Fargate is a serverless compute engine for containers that works with ECS, allowing you to run containers without managing the underlying infrastructure.
In this article, I will explore how to use ECS and Fargate for deploying a sample application while integrating Amazon RDS for database management, using AWS KMS and Secrets Manager to securely handle sensitive information and managing Docker images with Amazon ECR.
I. Setting Up Your Development Environment
To get started, let’s create a simple application that we will containerize and deploy. For this example, we will use a Node.js application with a PostgreSQL database.
Example of simple app.js
:
const express = require('express');
const mysql = require('mysql');
const AWS = require('aws-sdk');
const secretsManager = new AWS.SecretsManager();
const app = express();
const port = process.env.PORT || 3000;
async function getDatabaseCredentials() {
const data = await secretsManager.getSecretValue({ SecretId: 'RDSMasterUserSecret' }).promise();
return JSON.parse(data.SecretString);
}
app.get('/', async (req, res) => {
const secret = await getDatabaseCredentials();
const connection = mysql.createConnection({
host: 'your-rds-endpoint', // Replace this with your actual RDS endpoint after creation
user: secret.username,
password: secret.password,
database: 'mydatabase'
});
connection.query('SELECT * FROM mytable', (error, results) => {
if (error) throw error;
res.json(results);
});
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
Initialize package.json
and Install Dependencies
Command to initialize package.json
: npm init -y
Command to install dependencies: npm install express mysql
II. Writing Dockerfile
Next step is creating a Dockerfile to containerize our application:
# Use the official Node.js image
FROM node:14
# Set the working directory
WORKDIR /usr/src/app
# Copy package.json and install dependencies
COPY package*.json ./
RUN npm install
# Copy the application code
COPY . .
# Expose the application port
EXPOSE 3000
# Command to run the application
CMD ["node", "app.js"]
III. Configuring AWS KMS and Secrets Manager
To securely manage your database credentials, we will be using AWS Secrets Manager and KMS.
- Create a KMS key (as shown in the CloudFormation template below).
- Store RDS credentials in Secrets Manager (as included in the template).
IV. Setting Up Amazon RDS
Create a template.yaml
file for your CloudFormation setup, which includes RDS configuration.
AWSTemplateFormatVersion: '2010-09-09'
Resources:
MyKMSKey:
Type: AWS::KMS::Key
Properties:
KeyPolicy:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
AWS: arn:aws:iam::<your-account-id>:root
Action: "kms:*"
Resource: "*"
MySecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: RDSMasterUserSecret
Description: RDS Master User Credentials
SecretString: !Sub |
{
"username": "${MasterUsername}",
"password": "${MasterUserPassword}"
}
KmsKeyId: !Ref MyKMSKey
MyDBInstance:
Type: AWS::RDS::DBInstance
Properties:
DBInstanceIdentifier: mydbinstance
AllocatedStorage: 20
DBInstanceClass: db.t2.micro
Engine: mysql
MasterUsername: !Join [ "", [ !GetAtt MySecret.SecretString, "username" ] ]
MasterUserPassword: !Join [ "", [ !GetAtt MySecret.SecretString, "password" ] ]
DBName: mydatabase
VPCSecurityGroups:
- !GetAtt MyDBSecurityGroup.GroupId
Run the following command in your terminal to deploy the stack, ensuring you have the AWS CLI configured. The template.yaml
file includes parameters such as MasterUsername
and MasterUserPassword
, which you must define in the command when deploying the stack. Here’s how to pass these parameters during deployment:
aws cloudformation create-stack --stack-name my-stack --template-body file://template.yaml --parameters ParameterKey=MasterUsername,ParameterValue=admin ParameterKey=MasterUserPassword,ParameterValue=mypassword --capabilities CAPABILITY_NAMED_IAM
These parameters will be used to create the RDS instance and store the credentials securely in AWS Secrets Manager.
V. Building and Pushing Docker Images
Now that we have our Dockerfile ready, let’s build and push our Docker image to ECR.
Step 1: Create an ECR Repository
First, log in to your AWS Management Console and navigate to ECR. Create a new repository named my-ecs-app.
Step 2: Authenticate Docker to ECR
Run the following command to authenticate Docker with your ECR registry (replace REGION with your AWS region):
aws ecr get-login-password --region REGION | docker login --username AWS --password-stdin <your_account_id>.dkr.ecr.<REGION>.amazonaws.com
Step 3: Build the Docker Image
Run the following command to build your Docker image:
docker build -t my-ecs-app .
Step 4: Tag and Push the Image
Tag the image for your ECR repository:
docker tag my-ecs-app:latest <your_account_id>.dkr.ecr.<REGION>.amazonaws.com/my-ecs-app:latest
Step 5: Push the image to ECR
docker push <your_account_id>.dkr.ecr.<REGION>.amazonaws.com/my-ecs-app:latest
VI. Deploying with Amazon ECS and Fargate
Define a task in ECS that references your Docker image stored in ECR. Make sure the image
parameter matches the name of the repository you created in ECR:
{
"family": "my-node-app",
"containerDefinitions": [
{
"name": "my-node-app",
"image": "<your-account-id>.dkr.ecr.<region>.amazonaws.com/my-node-app:latest",
"essential": true,
"memory": 512,
"cpu": 256,
"portMappings": [
{
"containerPort": 3000,
"hostPort": 3000
}
],
"environment": [
{
"name": "PORT",
"value": "3000"
}
]
}
]
}
You can now run your ECS task on Fargate, which manages the compute resources for you.
aws ecs create-service --cluster my-cluster --service-name my-node-app --task-definition my-node-app --desired-count 1 --launch-type FARGATE --network-configuration "awsvpcConfiguration={subnets=[<subnet-id>],securityGroups=[<security-group-id>],assignPublicIp='ENABLED'}"
VII. Permissions and IAM Roles
Last, but not least we have permissions. For the successful deployment of your application using Amazon ECS, RDS and Secrets Manager we must ensure the following IAM roles and permissions are configured:
a. IAM Role for ECS Task Execution
Role Name: ECS-Task-Execution-Role
Permissions:
-
AmazonECSTaskExecutionRolePolicy
(Allows ECS to pull images from ECR) -
SecretsManagerReadWrite
(Allows access to AWS Secrets Manager)
b. IAM Role for RDS Access
Role Name: RDS-Access-Role
Custom Permissions:
rds:DescribeDBInstances
-
rds:CreateDBInstance
(To create a new RDS instance) -
rds:DeleteDBInstance
(To delete an existing RDS instance) -
rds:ModifyDBInstance
(To modify settings of an RDS instance)
c. Amazon ECR Permissions
-
ecr:GetAuthorizationToken
(Required to authenticate Docker with Amazon ECR) -
ecr:BatchCheckLayerAvailability
(To check layers for Docker images) -
ecr:GetDownloadUrlForLayer
(To download layers of Docker images) -
ecr:BatchGetImage
(To retrieve Docker images
d. VPC Permissions (RDS and ECS should be within a VPC)
-
ec2:DescribeVpcs
(To describe VPCs) -
ec2:DescribeSubnets
(To describe subnets) -
ec2:DescribeSecurityGroups
(To describe security groups) -
ec2:CreateNetworkInterface
(If using awsvpc network mode)
e. CloudFormation Permissions
cloudformation:CreateStack
cloudformation:UpdateStack
cloudformation:DescribeStacks
cloudformation:DeleteStack
Adhere to the Principle of Least Privilege! Ensure that you grant only the permissions that are absolutely necessary for users or services to perform their required tasks.
Top comments (0)