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 . && docker tag :latest ____________.dkr.ecr._________.amazonaws.com/:latest && docker push ____________.dkr.ecr._________.amazonaws.com/: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 *sed*s: ``` 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 " cd ../database && docker build -t . && docker tag :latest ____________.dkr.ecr._________.amazonaws.com/:latest && docker push ____________.dkr.ecr._________.amazonaws.com/: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 " cd ../api1 && docker build -t . && docker tag :latest ____________.dkr.ecr._________.amazonaws.com/:latest && docker push ____________.dkr.ecr._________.amazonaws.com/: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 " cd ../api2 && docker build -t . && docker tag :latest ____________.dkr.ecr._________.amazonaws.com/:latest && docker push ____________.dkr.ecr._________.amazonaws.com/: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 ```