Deployment with Fabric
Fabric is a fantastic tool written in Python that we can utilize to execute shell commands on a remote computer via SSH, so any commands we would run locally on our computer we can run on remote servers without much effort. With Fabric, we create a local utility program to define local commands that will execute the remote ones.
We can execute anything with Fabric, so everything from deployment to complex server management is possible. In this post, I want to focus on web application deployment and creating a simple and automated deployment process with Fabric.
Let’s first think of how the deployment of our example application can work:
- The source code is stored in a remote git repository. Our server can access it and pull the new sources, which means our code hosting platform, like Github or Github, is configured with that server’s SSH key.
- The release branches are named
releases/<version>
where version is the version we want to deploy, e.g., 3.2.0. - We have access to the server from our computer or computer where we want to run Fabric via SSH, so that means our SSH key is allowed to be used as an authentication mechanism on that server.
- The web application is run using a systemd service called
serverapp
, which is configured to start it from a specific folder/home/serverapp
. However, instead of running a systemd service, we can start or restart our application in any other way. Fabric can run any commands we might need.
The best way would be to create a project with its Python virtual environment using Pipenv or Poetry, but we can also use the system Python for simplicity. Let’s start by installing Fabric:
pip install fabric
We need to prepare our Fabric file, where we will define our deploy command. Let’s save it in fabfile.py
:
from fabric import Connection
from invoke import task
HOST = 'user@IPADDRESS'
GIT_DIR = '/home/git/.'
APP_DIR = '/home/serverapp'
@task
def deploy(ctx, version):
"""Deploy specific version of serverapp"""
connection = Connection(HOST)
branch = f'releases/v{version}'
# Checkout and pull changes from releases/<version> branch
connection.run(f'git -C {GIT_DIR} fetch origin {branch}')
connection.run(f'git -C {GIT_DIR} checkout {branch}')
connection.run(f'git -C {GIT_DIR} pull origin {branch}')
# Copy all files from GIT_DIR to APP_DIR
connection.run(f'rsync -av --progress {GIT_DIR} {APP_DIR} --exclude .git')
# Run any deployment scripts we need, e.g. update dependencies using Pipenv
connection.run(f'cd {APP_DIR} && pipenv sync')
# Restart application, assuming we have 'serverapp' systemd service defined
connection.run(f'sudo systemctl restart serverapp')
# Check the status of the service if deployment worked well
connection.run(f'sudo systemctl status serverapp --no-page')
This Fabric script defines one command called deploy, taking one argument called version. It will:
- Connect to our server HOST (where we have server login and address of our server)
- Check out our release branch from Git in the GIT_DIR folder (we have to pull this folder first before running our Fabric deploy command as here we are already working in the existing git directory)
- Copy all files from our release branch to APP_DIR from where we run our application
- Restart our serverapp using a systemd service (here we can put any other command to stop & start the application)
All there is left to do is to start our deployment! Run:
fab deploy -v 0.1.18
The command above will call our deploy command with 0.1.18 as our version argument. We can define any number of commands we want and run them individually like this. There is also a way to show all commands we have defined via Fabric:
fab --list
Another thing we will get for free with Fabric is that it will show us the output of the commands automatically, so when we run our deploy, we will see the output of git, rsync and systemd status commands on our command line, which is neat.
Fabric can be a great tool for many situations where writing pure shell scripts or using more heavy-weight tools is not desirable. Check out the documentation and make great stuff. I hope it will work well for you as well!
Last updated on 16.1.2020.