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.

  1. No ability to create dependencies on system packages
  2. Packaging static files was a bit cumbersome
  3. 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 fabric, chef or 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 .deb, .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.

Next do:

$: 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.

  1. -s dir: This tells fpm what is the "source" of the package. In this case a directory.
  2. -t deb: This is the output format. Can be deb, rpm, python or gem,
  3. -v 0.1: This is the version of the package fpm will create.
  4. -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.
  5. /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.

  1. 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.
  2. Install gdebi and install it from the .deb directly.

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 /home/ubuntu/food_truck-build.

Thats it!

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 /etc files, 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.

Happy deploying!

Want more info on effective deployment practices every week? Signup below for more articles direct to your email, or follow Plank and Whittle on Twitter

Subscribe to our mailing list

* indicates required

We wont send you spam. Unsubscribe at any time.

comments powered by Disqus