Packaging a Flask app in a Debian package
Previously I showed how to package a python Flask app into a python source distribution for repeatable deployments. This works reasonably well but has a few draw backs.
- No ability to create dependencies on system packages
- Packaging static files was a bit cumbersome
- Installation at deployment time takes too long due to installing packages into a virtual env at deployment time.
The first of these is an issue when trying to create repeatable deployments with a minimum of fuss. One answer to this is to deploy using automated deployment tools such as
puppet. This is a valid approach, but as you already have a way to specifiy dependencies through the system package management system, why not use that?
The second is really just an annoyance. Once sorted out you shouldnt have any issues with this. But it didnt exactly make me feel great about the packaging method.
The third has a few points to it. In a native package you can package up an entire installed virtualenv. The advantage of this is the install time of python packages is moved to the package build time, rather than at deploy time. This can be advantagous if your rolling a service and you want to minimise the downtime of individual nodes. The second is that once the build is completed there isnt any reliance during deploy on outside services working, which drastically reduces your exposure to a bad deploy. Its all nicely packaged up in a native package ready to be quickly installed. On top of this a whole lot more parts are frozen in one package to reduce the amount of moving parts to a deployment.
You've convinced me, how do we do it?
As usual we will be using a clean ubuntu 12.04 image, and because of that we will be packaging our flask app into a
.deb file. We will be using the same example app for finding all the food trucks in San Francisco found here.
To accomplish the packaging we will be using a nifty little app called
fpm from https://github.com/jordansissel/fpm. This is actually a ruby utility so we need ruby 1.8 and ruby gems installed.
$: sudo apt-get install ruby1.8 $: sudo apt-get install rubygems $: sudo gem install fpm
Once thats installed we can clone our repository to somewhere helpful and setup a build directory.
$: sudo apt-get isntall git python-dev python-setuptools python-virtualenv $: git clone https://github.com/mlakewood/food_truck.git $: mkdir food_truck-build
fpm is a neat little tool that allows you to easily build
.rpm, python packages and also ruby
gems all from the commandline. Its super useful although sometimes the documentation is a bit sparse. This is also complicated by the
.deb documentation being a little hard to navigate and comprehend, but its certainly the easiest and quickest way to package up a
.deb package from arbitrary files.
$: virtualenv ~/food_truck-build/virt $: cd ~/food_truck $: ~/food_truck-build/virt/bin/python setup.py install $: fpm -s dir -t deb -n food-truck -v 0.1 -d "python,python-dev,postgresql" /home/ubuntu/food_truck-build/=/home/ubuntu/foodtruck.com
This is the meat of the package build. We first create a virtualenv inside the build directory, and then we install our python package into the virtualenv. This builds nicely on top of what we did in the previous article and handles all of our python dependencies well.
The last thing we do is to use
fpm to package it all up for us. I'll step us through each argument.
-s dir: This tells
fpmwhat is the "source" of the package. In this case a directory.
-t deb: This is the output format. Can be
-v 0.1: This is the version of the package
-d "python,python-dev,postgresql,nginx": This is the dependency flag. This means when you install with apt-get it will make sure all these packges are installed. This is the real advantage of doing a native package.
/home/ubuntu/food_truck-build/=/home/ubuntu/foodtruck.com: This specifies the files you want to include in the package(on the left of the
=sign) and where they will be installed at (on the right side of the
=sign). You can specify multiples of these pairs, just leave a space between them.
Once you have run this command, you will have a .deb file called
food-truck_0.1_amd64.deb. This should be a fully working installable
.deb file. You can test installing it on your local machine. There are two ways to do this.
- You can install your own PPA server (see previous article on how to do this), upload your package to that and apt-get install it.
- Install gdebi and install it from the
The reason for having to go to these lengths is that
dpkg -i doesnt resolve dependencies. To use
gdebi install it like so:
$: sudo apt-get install gdebi $: sudo gdebi food-truck_0.1_amd64.deb
This will install all dependencies specified in the package (from the
fpm -d parameter) and then install the food-truck package.
Now you should then have a directory called
/home/ubuntu/foodtruck.com that contains the contents of
fpm is a pretty nifty package and combined with some of the control files that are available in debian packaging you are able to specify
upstart configurations and more. In an upcoming article I will expand on this further.
As always comments, suggestions and clarifications are always welcome in the comments section below.
Want more info on effective deployment practices every week? Signup below for more articles direct to your email, or follow Plank and Whittle on TwitterFollow @PlankAndWhittle