AWS CodePipeline for AWS Fargate — The Chicken and Egg problem

Prashant Kandathil
Four Nine Digital
Published in
2 min readMay 11, 2023
Screen with code on on it

Introduction

In this post, I will go over how to create a CI/CD pipeline that deploys code to a serverless container on AWS. I will be using AWS CodePipeline for my CI/CD, and AWS Fargate for the container deployment service. Unlike other tutorials on this issue, I will focus on the very first attempt to build the infrastructure and push your very first image to the Elastic Container Repository (ECR).

When you build your infrastructure for the first time, the ECR that holds your image doesn’t exist, nor does the Fargate service that needs the image setup serverless tasks. Here lies the chicken and egg problem that has not been solved by the AWS CDK.

In this tutorial, I will show you how to set up the CloudFormation stack and break the chicken and egg dependency between the AWS CodePipeline building the image building and storing it in the ECR, and the Fargate service using the image for deploying serverless containers.

Express Application

First let’s set up a simple ExpressJS Application that returns “Hello World”.

const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => {
res.send('Hello World!')
})

app.listen(port, "::", () => {
console.log(`Example app listening on port ${port}`)
})

Pay attention to:

app.listen(port, "::", () => {
console.log(`Example app listening on port ${port}`)
})

You need to set the host to “::” so that the health checks against the docker container pass.

CDK Code

When you first create the Fargate Service, the ECR will not have an image and the stack deployment will fail because task creation will keep failing.

The idea is to add a generic image and PORT mapping then build the stack. The stack build will complete successfully. You will log in to the console and see that the AWS CodePipeline might have failed at the deploy stage. It does not matter. You are now ready to go to the next step.

fargateTaskDefinition.addContainer(`${this.stackName}-Container`, {
// image: ecs.ContainerImage.fromEcrRepository(ecrRepository),
image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'),
containerName,
portMappings: [{
// containerPort: config.FRONTEND_PORT,
containerPort: 80
}],
logging: serviceLogDriver,
})

Redeploy a change to the task definition with the ECR image and correct PORT mapping.

fargateTaskDefinition.addContainer(`${this.stackName}-Container`, {
image: ecs.ContainerImage.fromEcrRepository(ecrRepository),
// image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'),
containerName,
portMappings: [{
containerPort: config.FRONTEND_PORT,
// containerPort: 80
}],
logging: serviceLogDriver,
})

By switching the image and port mapping for the first build, we have broken the chicken and egg problem between the Fargate Service requiring an image in the ECR repository and the ECR repository not being built because the Fargate Service is failing.

GitHub

You can find all the code here

--

--