# Deploying a Dockerised Web Application using AWS ECS and GitHub Actions

#### Objectives:

1. **Containerise a Web Application**: Dockerise a simple web application.
    
2. **Set Up AWS ECS**: Deploy the Dockerised application to AWS ECS (Elastic Container Service).
    
3. **Implement CI/CD Pipeline**: Use GitHub Actions to automate the deployment process.
    

### Step-by-Step Guide

#### Prerequisites:

* AWS Account, IAM user with programmatic access keys
    
* Basic knowledge of Docker, AWS, and GitHub Actions
    
* Installed tools: Docker, AWS CLI, Git, GitHub CLI
    

#### Step 1: Containerise the Web Application

1. **Create a simple Node.js web application**
    
    Create a new directory for your project:
    
    ```bash
    mkdir my-web-app
    cd my-web-app
    ```
    
    Initialise a new Node.js project:
    
    ```bash
    npm init -y
    ```
    
    Install Express:
    
    ```bash
    npm install express
    ```
    
    Create an `index.js` file:
    
    ```bash
    const express = require('express');
    const app = express();
    const PORT = process.env.PORT || 3000;
    
    app.get('/', (req, res) => {
        res.send('Hello World!');
    });
    
    app.listen(PORT, () => {
        console.log(`Server is running on port ${PORT}`);
    });
    ```
    
2. **Create a Dockerfile**
    
    ```bash
    FROM node:14
    
    WORKDIR /app
    
    COPY package*.json ./
    
    RUN npm install
    
    COPY . .
    
    EXPOSE 3000
    
    CMD ["node", "index.js"]
    ```
    
3. **Build and test the Docker image locally**
    
    Build the Docker image:
    
    ```bash
    docker build -t my-web-app .
    ```
    
    Run the Docker container:
    
    ```bash
    docker run -p 3000:3000 my-web-app
    ```
    
    Visit [`http://localhost:3000`](http://localhost:3000) to ensure the app is running.
    

#### Step 2: Push Docker Image to AWS ECR

1. **Create an ECR repository**
    
    Go to the AWS Management Console, navigate to ECR, and create a new repository named `my-web-app`.
    
2. **Authenticate Docker to ECR**
    
    Use the AWS CLI to authenticate Docker to your ECR registry:
    
    ```bash
    aws ecr get-login-password --region <your-region> | docker login --username AWS --password-stdin <your-aws-account-id>.dkr.ecr.<your-region>.amazonaws.com
    ```
    
    **Tag and push the Docker image**
    
    Tag the Docker image:
    
    ```bash
    docker tag my-web-app:latest <your-aws-account-id>.dkr.ecr.<your-region>.amazonaws.com/my-web-app:latest
    ```
    
    Push the Docker image to ECR:
    
    ```bash
    docker push <your-aws-account-id>.dkr.ecr.<your-region>.amazonaws.com/my-web-app:latest
    ```
    

#### Step 3: Set Up AWS ECS

1. **Create a new ECS cluster**
    
    Go to the ECS console, create a new cluster with AWS Fargate (serverless) option leaving the rest as defaults.
    
2. **Create a new task definition**
    
    Go to Task Definitions, create a new task definition:
    
    * Launch type: Fargate
        
    * Container: Add container
        
        * Select the Image pushed earlier to ECR:
            
            ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718807600902/5673da8b-3012-4e9a-a34a-ffa3a898ece4.png align="center")
            
3. **Create a service**
    
    Go to Services, create a new service:
    
    * Launch type: Fargate
        
    * Cluster: Select your cluster
        
    * Task definition: Select your task definition
        
    * Number of tasks: 1
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718807761966/adec33d4-b4e6-4ae8-a3e8-84a18fa79b42.png align="center")
        
        * Wait until the service is created and a task is deployed, this could take few minutes. Once done test the app by selecting the task and finding the public IP address, then paste in a new browser tab followed by port number 3000
            
            ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718808611453/8b892e74-984a-46b8-884f-ef9874d3dd7f.png align="left")
            

Finally, export the task definition file and paste it to the application working directory

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718810215738/c1b6edd8-925d-4046-b6bb-68204bc5c498.png align="center")

#### Step 4: Implement CI/CD Pipeline with GitHub Actions

1. **Create a**`.github/workflows` directory
    
    In your project directory, create the following structure:
    
    ```bash
    mkdir -p .github/workflows
    ```
    
2. **Create a GitHub Actions workflow file**
    
    Create a new file `.github/workflows/aws.yml` with the following content:
    
    ```yaml
    name: Deploy to Amazon ECS
    
    on:
      push:
        branches: [ "master" ]
    
    env:
    # set this to your preferred AWS region, e.g. us-west-1
      AWS_REGION: us-east-1
    # set this to your Amazon ECR repository name not the URI
      ECR_REPOSITORY: my-web-app	
    # set this to your Amazon ECS service name
      ECS_SERVICE: my-web-app           
    # set this to your Amazon ECS cluster name
      ECS_CLUSTER: my-web-app                 
    # set this to the path to your Amazon ECS task definition
    # file, e.g. .aws/task-definition.json
      ECS_TASK_DEFINITION: my-web-app.json 
    # set this to the name of the container in the                                           
    # containerDefinitions section of your task definition
      CONTAINER_NAME: my-web-app       
    
    permissions:
      contents: read
    
    jobs:
      deploy:
        name: Deploy
        runs-on: ubuntu-latest
        environment: production
    
        steps:
        - name: Checkout
          uses: actions/checkout@v4
    
        - name: Configure AWS credentials
          uses: aws-actions/configure-aws-credentials@v1
          with:
            aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
            aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
            aws-region: ${{ env.AWS_REGION }}
    
        - name: Login to Amazon ECR
          id: login-ecr
          uses: aws-actions/amazon-ecr-login@v1
    
        - name: Build, tag, and push image to Amazon ECR
          id: build-image
          env:
            ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
            IMAGE_TAG: ${{ github.sha }}
          run: |
            # Build a docker container and
            # push it to ECR so that it can
            # be deployed to ECS.
            docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
            docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
            echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT
        - name: Fill in the new image ID in the Amazon ECS task definition
          id: task-def
          uses: aws-actions/amazon-ecs-render-task-definition@v1
          with:
            task-definition: ${{ env.ECS_TASK_DEFINITION }}
            container-name: ${{ env.CONTAINER_NAME }}
            image: ${{ steps.build-image.outputs.image }}
    
        - name: Deploy Amazon ECS task definition
          uses: aws-actions/amazon-ecs-deploy-task-definition@v1
          with:
            task-definition: ${{ steps.task-def.outputs.task-definition }}
            service: ${{ env.ECS_SERVICE }}
            cluster: ${{ env.ECS_CLUSTER }}
            wait-for-service-stability: true
    ```
    
3. **Set up GitHub**
    
    Create a new repo in Github to host the code, and set it up to allow Github Actions to deploy to ECS by configuring the secret keys for the IAM user:
    
    Your-Repo&gt;Settings&gt;Environments&gt;Select your env&gt;Add environment secret
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718810700984/ba8913cb-ae68-4910-88c9-551b74e92b22.png align="center")
    

#### Step 5: Commit and Push Changes

Initialize a git repository and push to GitHub

1. ```bash
     git init
     git remote add origin <your-github-repo-url>
     git add .
     git commit -m "Initial commit"
     git push -u origin main
    ```
    

This will trigger the GitHub Actions workflow, which will build the Docker image, push it to ECR, and deploy it to ECS.

Congratulations! You have successfully set up a CI/CD pipeline to deploy a Dockerised web application to AWS ECS using GitHub Actions.

Test the workflow by committing a change to the index.js in the line:

```javascript
res.send('Hello World!');
```

Then push the change to Github, this should trigger the workflow to deploy the new change to the docker image and create a task based on this new image.

Once the workflow is finished, browse to ECS on the management console and find the IP address of the newly launched task to test it on the browser.
