How to Package python applications as debian packages

By Mike Manuthu
iHub
  Published 08 May 2018
Share this Article

Code: https://github.com/iHub/simple-debianisable-app

This is a walkthrough to shipping a simple python system using the debian package management system.

For our case, we'll build, package and deploy a simple python application on an ubuntu 16-xenial.

Why package?

A package is a combination of metadata, configuration, and software that is prepared in a way that a package management program (for example: apt on Ubuntu, yum on Redhat Enterprise Linux, pip for Python packages and gem for RubyGems) can use to properly and reliably install software and related configuration data on a computer.

The main aim of packaging is to allow for consistency in distribution of packages, bundling of software and its configurations and providing for easily installable / uninstallable artifacts.

Without further ado, let’s dive in. The assumption is that you have some experience deploying software on ubuntu.

All the source code to the post can be found here.

A simple flask app

We shall use a simple python application structured as follows

Note the setup.py file and the requirements.txt file.

Debianisation

Here we’ll use dh-virtualenv (by spotify) which is a means of shipping python virtualenvs remotely. It leverages the debian packaging system with self contained python virtualenvs.

Prepare the box

To prepare the box for debian packaging run the following commands

[email protected]:~ sudo apt-get update && sudo apt-get upgrade -y
[email protected]:~ sudo apt-get install devscripts python-virtualenv git equivs dh-make python-dev git-buildpackage dh-virtualenv -y

Debianise the package

Debianising a package involves including a set of configurations in the root directory of the project.

|── debian
│ ├── changelog - Contains a log of the changes made to the Debian package.
│ ├── compat - Specifies the compatibility level for debhelper tool
│ ├── control - Describes the source and binary package giving information about them
│ ├── install - Copies package specific configurations
│ ├── postinst - A script to execute after package installation has happened
│ └── rules - A makefile for the package

Deployment configs

A common way to deploy a complex python application is to use

We’ll include the same configs in the package.

|── etc
│ ├── nginx
│ │ └── sites-available
│ │ └── simple-app.conf - Nginx site configs
│ ├── simpleapp
│ │ └── server_conf.py - Gunicorn configs
│ └── supervisor
│ └── conf.d
│ └── simple-app.conf - Supervisor configs

Putting it all together

Merging the application, the deployment configs and the debian configs yields the structure:

├── bin
│ └── run_simple_app.py
├── debian
│ ├── changelog
│ ├── compat
│ ├── control
│ ├── files
│ ├── install
│ ├── postinst
│ └── rules
├── etc
│ ├── nginx
│ │ └── sites-available
│ │ └── simple-app.conf
│ ├── simpleapp
│ │ └── server_conf.py
│ └── supervisor
│ └── conf.d
│ └── simple-app.conf
├── lib
│ └── simple_app
│ ├── app.py
│ └── __init__.py
├── requirements.txt
└── setup.py

Build the package

Tag the package for release

This is a way of versioning the software. The idea is to have stable releases and increment the number as more features are added to the package.

You can replace the --release with --snapshot if you dont want to ship the package to production

Building the package

This is a one line command.


This builds a bundled artifact (.deb) ../simple-app_1.0_amd64.deb

Installing the package

The generated artifact is then copied to the intended server and installed using the command

[email protected]:~ sudo dpkg -i simple-app_1.0_amd64.deb

 

Testing the package

[email protected]:~$ curl localhost -v
* Rebuilt URL to: localhost/
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.10.3 (Ubuntu)
< Date: Mon, 07 May 2018 04:32:03 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 11
< Connection: keep-alive
<
* Connection #0 to host localhost left intact
Hello world

Hosting the package

While copying the artifact to the intended server works, the ideal way of shipping packages is to host them. You can build your own reprepro server or host in a third party host. Some options out there are https://packagecloud.io, https://www.aptly.info and https://gemfury.com/

Conclusion

We have looked at deploying a simple python application using the debian packaging system. This provides a faster and efficient way of installing, uninstalling and scaling software deployment. The build process can be easily integrated to any continuous integration system with minimal effort.

Want to know more about building and shipping software? Ping us at consulting[at]ihub.co.ke.

comments powered by Disqus