One of the worst parts about working with python is how to share your code, or deploy it on another machine. If you’re following preferred practices, then you’re probably developing using a virtual environment. But that means you need a way to have the same environment where your app is going to run. Either your users need to go through several steps to create a virtual environment and then install your app and its dependencies to it, or you need to ship the environment along with your app. Or you start having to use containers.
For most python web apps, there is little or no advantage to kubernetes (or Docker Swarm). You want to run your app using something like gunicorn, uvicorn, hypercorn, and possibly have these running behind nginx or apache. You probably also want a database and some other services to be running as well. Your deployment environment may well be a single VM that you’ve created just for this purpose, so having to get kubernetes up and running seems redundant.
Assuming you’re running something like Ubuntu, or CentOS, then why can’t you use your package manager to install your app for you? Inspired by this blog post by nylas, I decided to have a look at whether this would be possible for an internal web app that I’ve developed.
The application to deploy
The app has a simple web interface that talks to a DB, and a couple more system services that need to be running as well. The DB is postgresql, as that’s my DB of choice.
For the web app, I’m using Sanic. The framework is very developer friendly, it supports async for handling large amounts of traffic, and it comes with its own high performance web server (including experimental http/3 support. While the performance of the web server is a good feature, it’s the fact that it simplifies deployment that really helps.
The deployment plan
The aim is to create a deb
file that will contain the app, its virtual
environment, and all other assets. The deb
will specify other packages the
app depends on (e.g. postgresql). Installing it will also install appropriate
systemd
units that launch the app and allow it to be controlled with
systemctl
. Logs will ship to journald
. We will also create new users for
the app to run under, and make sure that we’re running with least privileges.
Installing the app will also create the database it will use in postgres, and
create all necessary tables and relations. Future upgrades will allow us to run
schema migrations, either as our own SQL, or using our own python script.