docker deployment

Recently I found myself wanting to deploy a docker-compose file to a server. I wanted to automate this process as much as possible, so I decided to write a shell script to do it. This post will go through the process of writing a shell script to deploy a docker-compose file to a server.

TLDR, if you just want to check out the script and how to use it, you can find it here


As I started deploying more and more services to my server using docker compose, I kept just copying the whole file, sshing into the server, deleting the file and creating a new one, pasting the content. As you can imagine, that got old fast. Realising I was losing an extra minute or two every time I wanted to re-deploy my docker-compose.yml file, I created a simple git repository, and cloned it on both hosts. This meant I could simply push on my laptop and ssh into the server and run git pull, and I would never have to mess around with copying the whole file manually again.


Now I was still having to ssh in and stop all the containers, pull the repo and then start them again, and I though it would be nice if I could just do this from the terminal in the VSCode editor I used to edit the docker-compose.yml file, so I wrote a simple script which does all of it for me.


#!/bin/bash
git add .
git commit -m "updated docker-compose.yml"
git push

ssh -o "StrictHostKeyChecking=no" -i ssh.key $CD_USER@$CD_HOST << EOF
sudo su
cd $CD_PATH
docker compose down
git pull
docker compose up -d
exit
EOF

So what's going on here? Firstly we commit and push all the changed files to the repository, this means that the docker-compose.yml and any other files, for example config files for services you may be running, are now on the remote repository.


Next, it simply connects to the server via ssh, and runs the commands listed. Firstly, stopping the containers so that the docker-compose.yml and any other config files can be updated safely, then pulling the git repo to update the files. Finally restarting the docker compose services, and then exiting so the ssh session closes.


Now to make the commit history not look like groundhog day, and to add some commit messages, we can use Gum, a tool for easily making interactive bash scripts. It works by installing the application onto your system which can then be called inside your bash scripts to invoke user prompts, for example we can use the code below to get a commit message from the user in the terminal and store it as a variable.


#!/bin/bash
message=$(gum input --placeholder "Commit message")
git add .
git commit -m "${message}"

Finally, putting all the pieces together and adding a quick check to see if gum is installed, and trying to install it if not, we can arrive at the following script:


#!/bin/bash

# A script to redeploy this docker infrastructure using ssh

if [ -f .env ]; then
    source .env
else
    echo ".env file not found. Please create it and set the necessary environment variables."
    exit 1
fi

check_gum() {
    if command -v gum &> /dev/null; then
        return 0
    else
        echo "Gum not found, installing..."
        return 1
    fi
}

install_gum() {
    if [[ "$OSTYPE" == "darwin"* ]]; then
        /bin/bash -c "$(curl -fsSL 
https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
        brew install gum
    elif [[ -f /etc/os-release ]]; then
        source /etc/os-release
        if [[ $ID == "ubuntu" ]] || [[ $ID == "debian" ]]; then
            sudo apt update
            sudo apt install -y gum
        elif [[ $ID == "fedora" ]] || [[ $ID == "centos" ]] || [[ $ID == "rhel" ]]; then
            sudo dnf install -y gum
        else
            echo "Unsupported Linux distribution. Please install Gum 
manually."
            exit 1
        fi
    else
        echo "Unsupported operating system. Please install Gum manually."
        exit 1
    fi
}

# Main script execution
if ! check_gum; then
    if ! install_gum; then
        echo "Failed to install Gum. Please install it manually and run 
the script again."
        exit 1
    fi
fi

message=$(gum input --placeholder "Commit message")

git add .
git commit -m "${message}"
git push

ssh -o "StrictHostKeyChecking=no" -i ssh.key $CD_USER@$CD_HOST << EOF
sudo su
cd $CD_PATH
docker compose down
git pull
docker compose up -d
exit
EOF