blog

Making shell scripts for deployment on AWS

Long gone are the days which deploying a website meant simply uploading .php files via FTP to your favourite web host. Now, if you are using any of those new, fancy technologies such as Node.js, Docker, and Cloud Hosting, you will have to perform several tasks in order to put the new version of your website online. Luckily, these services often allow you to do this via command line - not that it makes things easier at first glance, but it allows us to automate these processes. Our application is built on Node.js, it uses 3 Docker containers (2 APIs and 1 Database), and they are all deployed as a single task on Amazon Web Services (AWS); in this post I am going to describe how our deployment currently done, and what I did to automate it.


1- Logging in

To make any changes on AWS, you first have to log in. For this, we use the command that they provided us:

aws ecr get-login

Run this in the command line and it will give you another command; copy and paste the new command, and you are logged in. Or, if you want to be lazy:

aws ecr get-login | bash -e


2- Building, tagging, and pushing the container repositories

For these tasks, AWS provides you the required commands - when you use their website to upload a new version of the repository, they will tell you to run commands similar to these:

docker build -t <name> . &&
docker tag <name>:latest ____________.dkr.ecr._________.amazonaws.com/<name>:latest  &&
docker push ____________.dkr.ecr._________.amazonaws.com/<name>:latest


3- Stopping the current tasks

For the new containers to be run, the current tasks will have to be stopped. There is no quick and easy way to do this, as far as I know, so this is what I did:

  • List all the current tasks running on the cluster
aws ecs list-tasks --cluster default

This will give you a list of tasks in JSON format, like this:

{
    "taskArns": [
        "task1",
        "task2",
        "task3"
    ]
}
  • Extract the tasks

For extracting the tasks, I piped the output into two seds:

sed '/\([{}].*\|.*taskArns.*\| *]\)/d' | sed 's/ *"\([^"]*\).*/\1/'

This is the result:

task1
task2
task3
  • For every line (task), stop the task with that name

Now we can use the command provided by AWS: aws ecs stop-task. I just used a for-loop to go through every line and stop the task:

while read -r task; do aws ecs stop-task --cluster default --task $task; done


4- Wrapping up

With the basic pieces done, I wrapped them in a shell script:

#!/bin/bash


###############################################################################
# LOGGING IN
###############################################################################
login()
{
    aws ecr get-login | bash -e

    deployDatabase
}


###############################################################################
# DEPLOYING DATABASE
###############################################################################
deployDatabase()
{

    echo -e "Ready to deploy the database? (Y/n)"
    read shouldDeploy

    if [ "$shouldDeploy" = "Y" ];then
        echo -e "Deploying the database\n"
        cd ../database &&
        docker build -t <name> . &&
        docker tag <name>:latest ____________.dkr.ecr._________.amazonaws.com/<name>:latest  &&
        docker push ____________.dkr.ecr._________.amazonaws.com/<name>:latest
    fi

    deployAPI1
}


###############################################################################
# DEPLOYING API 1
###############################################################################
deployAPI1()
{

    echo -e "Ready to deploy API 1? (Y/n)"
    read shouldDeploy

    if [ "$shouldDeploy" = "Y" ];then
        echo -e "Deploying API 1\n"
        cd ../api1 &&
        docker build -t <name> . &&
        docker tag <name>:latest ____________.dkr.ecr._________.amazonaws.com/<name>:latest &&
        docker push ____________.dkr.ecr._________.amazonaws.com/<name>:latest
    fi

    deployAPI2
}


###############################################################################
# DEPLOYING API 2
###############################################################################
deployAPI2()
{

    echo -e "Ready to deploy API 2? (Y/n)"
    read shouldDeploy

    if [ "$shouldDeploy" = "Y" ];then
        echo -e "Deploying API 2\n"
        cd ../api2 &&
        docker build -t <name> . &&
        docker tag <name>:latest ____________.dkr.ecr._________.amazonaws.com/<name>:latest &&
        docker push ____________.dkr.ecr._________.amazonaws.com/<name>:latest
    fi

    stopTasks
}


###############################################################################
# STOPPING CURRENT TASKS
###############################################################################
stopTasks()
{
    echo -e "Stop the current tasks? (Y/n)"
    read shouldDeploy

    if [ "$shouldDeploy" = "Y" ];then
        aws ecs list-tasks --cluster default | \
        sed '/\([{}].*\|.*taskArns.*\| *]\)/d' | sed 's/ *"\([^"]*\).*/\1/' | \
        while read -r task; do aws ecs stop-task --cluster default --task $task; done
    fi

    echo -e "Done"
}


###############################################################################
# STARTING POINT
###############################################################################
clear

echo -e "Are you sure you want to deploy on AWS? This cannot be undone. (Y/n)"
read shouldDeploy

if [ "$shouldDeploy" = "Y" ];then
    login
else
    echo "Not deployed"
fi