Distributing a Flask App as a Package

I’ve deployed many Flask applications to production servers. My current method is pretty awesome (Packer + Ansible + Terraform).
But how do you distribute Flask applications for users to run?

Recently, I helped write a Flask application called Postmaster for StackFocus. Since most web applications are full stack these days, they involve a lot of different moving parts.

We ran into the problem of having 20+ steps to install our application. That is no bueno. We made a Dockerfile for users to pull, but we didn’t want to force our users to use Docker.

Some research led me to Chef-Omnibus. Gitlab uses it to install their software. It takes a chef recipe and turns it into a deb, rpm, dmg, or msi package for various different operating systems.

I don’t use Chef. I’ve taken preference to Ansible for provisioning my applications, simply because it’s very easy and mostly everything is a core module. Ansible does not have a cool Omnibus tool to create packages for playbooks. So…I improvised using FPM!

FPM is a trivial way to create packages. Their tagline says it all:
>FUNDAMENTAL PRINCIPLE: IF FPM IS NOT HELPING YOU MAKE PACKAGES EASILY, THEN THERE IS A BUG IN FPM.

If you haven’t already, upgrade your application’s install script to an Ansible playbook! It’s really easy and you will kick yourself for not doing it from the start.

Create a Debian package for an Ansible Playbook

Requirements:

- Working Ansible playbook to deploy application to a server.

- gem install fpm

Just modify this script as needed, and save as build_release.sh in your repository

Beware - You cannot use apt: or pkg: statements in your playbook since you are installing this using your package manager, which creates a lock. Instead of shuffling the lock around, just mark the packages as dependencies and have your package manager take care of it! (It’s almost like that’s what they were made for!)

I use Vagrant for development, so I have all the packages in my playbook marked when: provision_type == "dev"

The trick here is the --after-install script, which is just a bash script to call the ansible playbook. You can get fancy and specify other options, like --after-upgrade.

Save this script in the directory with your playbook so it will run when the packge is installed.