Your own private cloud (PaaS) – part II: Converting an existing Django app to run on Stackato

Note: If you haven't read it already, see Part I: Understanding PaaS for some background on private PaaS solutions.

What is Stackato?

As mentioned in Part I, Stackato is based off the Open Source project CloudFoundry.org. Stackato provides free images for VirtualBox, VMWare, AWS and KVM. I have heard they may be making a Vagrant box as well but until then it shouldn't be too hard to convert the VirtualBox image into your own Vagrant box. Along side the VM image Stackato provides a command line tool called kato in order to interact with your environment and deploy your apps.

Stackato

Deploying Django to Stackato

How easy is it to take an existing Django application that was not architected for a PaaS environment, and port it to run on Stackato? Thankfully, it is actually pretty easy. This post details the required steps.

1. The YAML file

Configuration options for Stackato are stored in the stackato.yml file in the top level application directory. The basics for a Django app are:

  • name
  • framework
  • min_version
  • env
  • requirements
  • services
  • processes
  • hooks
  • ignores
name: stackto-demo
framework:
type: python
runtime: python27
min_version:
client: 1.5.1
env:
DJANGO_SETTINGS_MODULE: settings.production
requirements:
pip:
- mysql-python
- django
- south
- django-bootstrap-forms
- mock
- gdata
- django-mobile
- pycrypto
- django-compress
- django-recaptcha
- django-cache-machine
- django-extensions
- gunicorn
- python-memcached
services:
${name}-db: mysql
${name}-memcached: memcached
processes:
web: $STACKATO_UWSGI --check-static $HOME/static --check-static $HOME/media
hooks:
post-staging:
- python manage.py syncdb --noinput
- python manage.py migrate --noinput
- python manage.py collectstatic --noinput
ignores:
- .git
- dev.db

2. Environment Variables

All PaaS services make use of environment variables for application settings, and Stackato is no different. See Chapter III in Heroku's great online book called The Twelve-Factor app for why this is a good thing. The first step is to determine the settings that you need to set in the environment and the ones you need to get from the environment. Django already looks for the environment variable DJANGO_SETTING_MODULE if your are using non default module for your settings file. This should be specified in the stackato.yml file under the env: section. If you are looking for a tool to simulate this in your local dev environment check out AutoEnv.

Stackato will set an environment variable (or two actually) for the database settings. That will be in DATABASE_URL and VCAP_SERVICES. Stackato docs provide 2 different methods to read in the database from the environment variable. The first example sets the appropriate engine type from the URL which makes it very flexible and is what I would recommend to do.

import urlparse
DATABASES = {}
if 'DATABASE_URL' in os.environ:
    url = urlparse.urlparse(os.environ['DATABASE_URL'])
    DATABASES['default'] = {
        'NAME': url.path[1:],
        'USER': url.username,
        'PASSWORD': url.password,
        'HOST': url.hostname,
        'PORT': url.port,
        }
    if url.scheme == 'postgres':
        DATABASES['default']['ENGINE'] = 'django.db.backends.postgresql_psycopg2'
    elif url.scheme == 'mysql':
        DATABASES['default']['ENGINE'] = 'django.db.backends.mysql'
else:
    DATABASES['default'] = {
        'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'dev.db',                      # Or path to database file if using sqlite3.
        'USER': '',                      # Not used with sqlite3.
        'PASSWORD': '',                  # Not used with sqlite3.
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
        }

Another option would be to use the dj-database-url package which would simplify this for you.

3. Dependencies

The standard way in the Python world to install dependencies is with PIP and a requirements.txt file. Stackato supports reading a requirements.txt file from the root of the project directory. Stackato also allows you to specify the requirements in the stackato.yml file under requirements: and allows you to use the python.org package index PyPi or Active State's own Python package repository PyPM.

4. Web Process

The web process used to serve the application and the static files is specified under processes: web: and uses the environment variable $STACKATO_UWSGI (this is the equivalent to Heroku's Procfile). The web processes for a Django app expects your wsgi.py file in the root directory of the project. Note that the—check-static flag in the example will serve static files with uwsgi. For large production environments a content delivery network would be recommended.

5. Hooks

Hooks allow you to run command pre or post staging. In the example above Django management commands syncdb, migrate and collectstatic are run when the application is staged (deployed).

6. Fire it up

Installing Stackato is trivial, just download the micro cloud of the Virtualization method you want to use and start it up, or follow the simple AWS instructions. Then add an entry in your hosts file for the server name that is displayed at boot. After that install the stackato command line client and connect it to your VM with the following commands.

​stackato target api.stackto-xxxx.local

​Then you can deploy your app with the command below. This will prompt you with a few questions and some defaults that are automatically filled in from your stackato.yml file.

stackato push

When you make updates and changes to your app you can deploy them by running the following:

​stackato update

NOTE: If it is already running, the update command will update and restart your application. If your app is not running you will need to start it. That is done with the start command. I'm not sure I would call this a feature, I ran a lot of update and start commands trying to figure everything out. It would be more logical if the push command was idempotent. 

stackato start

To troubleshoot your app, Stackato provides an ssh command to connect to the shell on your VM. From here you can do normal command line stuff, run management commands, look at files to debug your app, etc.

​stackato ssh

I found an project called django-deployer that is meant for deploying Django apps to PaaS and has support for Stackato. I tried to use it for my existing app, but it is too opinionated and didn't like how we had set up our existing application. If I was starting a Django application from scratch I'd definitely take a look at it.

7. Switching environments

If you have one setup as a development or staging on a small VM then want to deploy to a Stackato production server on AWS, it is a simple as changing the target then doing an push or an update.

​stackato target api.stackto-aws-url.com
stackato push

Thoughts on Stackato

While Stackato provides a lot out of the box, it does not yet provide the same seamless experience that a hosted PaaS like Heroku provides. There have been a couple quirky things that I was able to solve with a reboot or two, my guess would be things are not starting in the order they are expected to start in, but I don't know enough about the system to be sure. The other big gripe I have with it is the user interface and the overall user experience. Here at OpenRoad I have learned a lot from our user experience team and as such I have become less tolerant of poor UX. One basic example are scroll boxes with a scroll bar that you can't scroll (odd). I was able to work around these little issues, but they add up and reduce ones confidence in the platform.

Is Stackato production ready?

Depending on your risk tolerance, I think it is. There are some large companies making extensive use of it like HP and Mozilla.

Would I recommend it?

That would depend on the nature of the project. While it is stable, it is a fast moving target. Unless you're able to spend a decent amount of time keeping up to date with the changing platform, you may find yourself with a fair amount of technical debt to resolve in a very short time frame.

It looks like Active State's is focusing on large enterprises, which is understandable for a startup, to me it does seem like a miss. For one, the target demographic for PaaS is developers. Developer culture these days is startup oriented and startups are usually shops that don't have a large operations team, therefore none of these companies would be able to afford support from ActiveState. I think that a company like dotCloud, with their newly open sourced Docker is going to be strong competitor, especially if they (or someone else) steps up to provide an affordable support option to a solid open source platform. There are many other ways to monetize a PaaS without solely going after the Fortune 500, and I hope that ActiveState finds a way to support a range of development team sizes.

The first private PaaS product that is as simple to use as Heroku, is stable and has good support for both the 1-2 person developer shop and large teams will be very successful in the marketplace.

Bottom Line

This is definitely the direction the industry is heading and I think Stackato has a good head start on the other solutions. I'll be watching them and other interesting projects like docker and deis. ActiveState seems to be doing the right thing trying to get as much feedback as they can to continue to improve and add polish to the platform. These tools definitely make my life easier—it's a good time to be a developer.