Guide: Build and Deploy Docker Image to AWS ECS Cluster with Jenkins
This guide demonstrates how to build a Docker image, push it to AWS ECR, and deploy it to an ECS cluster using a Jenkins pipeline. AWS credentials are securely injected using AmazonWebServicesCredentialsBinding
. We'll also show how to use a notification tool.
Prerequisites
- AWS account with ECS and ECR permissions
- Jenkins with AWS Credentials plugin installed
- Docker installed on Jenkins agent
- Notification tool/library (e.g., Teams webhook, Slack, etc.)
1. Jenkins Pipeline Example
Below is a Jenkins pipeline script that covers the full process:
@Library('mylibrary') _
def ECR_ROOT = "<your-account-id>.dkr.ecr.ap-northeast-1.amazonaws.com"
def ECR_REPO_NAME = "my-app"
def ECS_CLUSTER = "my-cluster"
def ECS_SERVICE = "my-service"
def ECS_TASK_FAMILY = "my-task-family"
node("your-agent-label") {
stage("Checkout SCM") {
checkout scmGit(
branches: [[name: "main"]],
userRemoteConfigs: [[credentialsId: "your.git.credentials",
url: "git@github.com:your-org/your-repo.git"]]
)
}
withCredentials([
[$class: 'AmazonWebServicesCredentialsBinding', credentialsId: 'MY-AWS-ACCOUNT'],
]) {
stage("Build Docker Image") {
sh """
docker build -t ${ECR_REPO_NAME}:latest .
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin ${ECR_ROOT}
docker tag ${ECR_REPO_NAME}:latest ${ECR_ROOT}/${ECR_REPO_NAME}:\${BUILD_ID}
docker push ${ECR_ROOT}/${ECR_REPO_NAME}:\${BUILD_ID}
"""
}
stage("Deploy to ECS") {
sh """
TASK_DEFINITION=\$(aws ecs describe-task-definition --task-definition "${ECS_TASK_FAMILY}")
NEW_IMAGE="${ECR_ROOT}/${ECR_REPO_NAME}:\${BUILD_ID}"
echo \$TASK_DEFINITION | jq --arg IMAGE "\$NEW_IMAGE" '.taskDefinition | .containerDefinitions[0].image = \$IMAGE | del(.taskDefinitionArn) | del(.revision) | del(.status) | del(.requiresAttributes) | del(.compatibilities) | del(.registeredAt) | del(.registeredBy)' > new-task-def.json
NEW_TASK_DEFINITION_ARN=\$(aws ecs register-task-definition --cli-input-json file://new-task-def.json | jq -r ".taskDefinition.taskDefinitionArn")
aws ecs update-service --cluster ${ECS_CLUSTER} --service ${ECS_SERVICE} --task-definition \$NEW_TASK_DEFINITION_ARN --force-new-deployment
aws ecs wait services-stable --cluster ${ECS_CLUSTER} --service ${ECS_SERVICE}
"""
}
stage("Notification") {
def commitMessage = sh(script: "git log -1 --pretty=%B", returnStdout: true).trim()
msteams.sendSuccessToMyTeam(ECS_SERVICE, commitMessage)
}
}
}
2. Explanation of Each Jenkins Pipeline Stage
Let's break down what each stage in the pipeline does:
- Checkout SCM
Checks out your source code from the specified Git repository and branch, ensuring the pipeline works with the latest code. - Build Docker Image
Builds the Docker image using yourDockerfile
, authenticates Docker to AWS ECR, tags the image with the build ID, and pushes it to your ECR repository. - Deploy to ECS
Retrieves the current ECS task definition, updates the container image to the new version, registers a new task definition revision, and updates the ECS service to use this new revision. Waits for the ECS service to become stable. - Notification
Extracts the latest commit message and sends a deployment notification using your notification tool (e.g., Microsoft Teams, Slack).
3. Using Shared Libraries for Reusable Pipeline Functions
To avoid code duplication and promote maintainability, you should use Jenkins Shared Libraries for common functions such as notifications, code checkout, or deployment logic. Shared libraries allow you to define reusable Groovy scripts and import them into multiple pipelines with the @Library
annotation.
Example:
@Library('mylibrary') _
node {
// Now you can use functions like msteams.sendSuccessToMyTeam, commit.extractCommit, etc.
}
By centralizing common logic in a shared library, you ensure consistency and make updates easier across all your pipelines.
4. Notes
- AWS Credentials: The
AmazonWebServicesCredentialsBinding
injects AWS credentials as environment variables for the shell steps. - Notification: The example uses a custom
msteams.sendSuccessToMyTeam
function. Replace or adapt this for your notification tool. - Security: Never hardcode credentials. Always use Jenkins credentials binding.
Tip: Adjust image names, repository, and service names as needed for your environment.