A handy deployment script for your pipeline
Tags: devops, webdev, tutorial, docker
Published: 2021-07-16 12:15:25

Just after GitHub Actions was launched, I was pretty excited to try it out. So I did what any other developer would have done, I wrote an workflow file to deploy my API's automatically to my server.

After a few tries and catch blocks, ;-), I was able to get it to work properly. Back then, my idea of the pipeline was, the script would ssh into my server, build the dockerfile locally and then deploy it.

However, after talked with a few people, turns out that's not the correct way to use it. I started reading a few articles and I was indeed wrong in thinking the building process is supposed to be done locally on the host machine.

## So how to do it then?

> If you want to get a proper idea of how to setup a pipeline, read my [other article on it](https://blog.deepjyoti30.dev/github-actions-pipeline)

I will just go through the workflow in brief as of now.

Since the pipeline might deploy the docker image in various containers (which obviously adds the possibility of multiple platforms, also in the case of releases), the building process should be rather done in the pipeline.

After the building is done, the image should be pushed to a container hub , yep, you guessed it, **Docker Hub** or in my case **GHCR** (since it's free). After the image is pushed, the workflow should deploy the image in various platforms.

I personally do it by using the [ssh-action](https://github.com/appleboy/ssh-action) package that allows my workflow to ssh into my server(s), pull the latest image from the hub and deploy it.

Here's where my article comes in place, how do you deploy locally?

Obviously a simple `docker pull` and `docker run` won't cut it right? There are ports to be taken care of, volumes mapping, environment files.

I had the same question and I came across an article (that I am unable to find right now), that had a pretty nice script.

## Deployment Script

> The script I am sharing here is not mine. It was created by someone else and I merely just edited it a bit to fit my requirements. I am unable to find the article of the original author of the script.

```sh
#!/bin/bash
########################################
# Put this on a Server
# run chmod +x deploy_app.sh to make the script executable
# 
# Execute this script:  ./deploy_app.sh docker-username/docker-appname:$TAG
# Replace the $TAG with the actual Build Tag you want to deploy
#
########################################

set -e

DOCKER_IMAGE=$1
CONTAINER_NAME="container-name"

# Check for arguments
if [[ $# -lt 1 ]] ; then
    echo '[ERROR] You must supply a Docker Image to pull'
    exit 1
fi

echo "Deploying $CONTAINER_NAME to Docker Container"

#Check for running container & stop it before starting a new one
if [ $(docker inspect -f '{{.State.Running}}' $CONTAINER_NAME) = "true" ]; then
    docker stop $CONTAINER_NAME
fi

# Pull the latest image
echo "Pulling latest image for $DOCKER_IMAGE"

docker pull $DOCKER_IMAGE

echo "Starting $CONTAINER_NAME using Docker Image name: $DOCKER_IMAGE"

docker run -d --rm=true -p 80:5000 --env-file ~/Scripts/.env --name $CONTAINER_NAME $DOCKER_IMAGE

# Show the running processes
docker ps
```

The above script is basically pulling the latest image and deploying it according to the passed flags like `--env-file`. However, this also checks if the container is already running. If so, the container is first removed and after the new container is **run**.

You can directly copy the script to your server, just do the following changes:

- Change the `CONTAINER_NAME` value.
- Make the script executable using `chmod +x <script_path>`

> Don't forget to pass the name of the image while running the script, eg: `sh script.sh ghcr.io/deepjyoti30/ytmdl-web-v2:latest`

It is important to pass the `latest` tag or the exact tag because otherwise a cached image of the container is used. This means the image is not updated at all. So make sure the tag is passed.

## Example workflow with the script

Once you have the script setup nice and cozy on your server, you can setup a workflow like following to ssh into the server and run the script. We will use `ssh-action` as mentioned above to ssh into the server. Once done, that action will just run the script.

```yaml
name: Build app and deploy docker

on:
  push:
    branches:
      - "production"

jobs:
  push-to-docker:
    # Write actions here to build and push the image
    # to a hub like Docker Hub or Github Container Registry
    # NOTE: Don't leave these lines as such, the workflow will fail.

  deploy:
    needs: push-to-docker
    runs-on: ubuntu-latest
    steps:
      # SSH into the server
      - name: SSH into server
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.SERVER_IP }} # Pass server IP
          username: ${{ secrets.SERVER_USERNAME }} # Pass server username
          key: ${{ secrets.KEY }} # Pass server ssh private key
          script: /bin/bash Scripts/deploy_ytmdl_web.sh ghcr.io/deepjyoti30/ytmdl-web:latest
```

You can see the above workflow in action in [my ytmdl-web repo](https://github.com/deepjyoti30/ytmdl-web-v2).

If you happen to come accross the article that had the above script originally, feel free to comment. I will update the post with credits (and links) to that!

##[This article was originally posted on my personal blog](https://blog.deepjyoti30.dev/handy-deployment-script)