DemocracyOS (YC-W15) and Deis on Azure: A TED Case Study

DemocracyOS (YC-W15) and Deis on Azure: A TED Case Study

Steven Edouard, Tim Park

The Problem 

Who is Democracy OS?

DemocracyOS (DOS) is a Y-Combinator Winter 2015 cohort non-profit startup that aims to redefine how organizations make decisions, from government to academic organizations. DOS aims to redistribute decision making in organizations by making it easy for members to participate in policy-making, encouraging democracy within their group.

 

DOS's product is completely open source and takes the form of an Express/Node.js application, backed by MongoDB for persistent data. You can think of the Democracy OS app similar to WordPress in that it's free and open to use; however, to monetize DOS intends to host instances of the application for organizations and charge a subscription fee.

 

The Problem

The high level problem that Democracy OS has is that they want to deploy their application on Azure with a highly productive developer workflow (like one that Heroku provides and similar to our Azure Websites workflow) on top of a Linux based infrastructure. This paper describes the work we did with them and the Deis open source project on Azure to enable this very common pattern we see across startup companies using open platforms on Azure.

 

In their solution, Democracy OS must provision a new instance of the application as well as a new database to back the instance. Each application is hosted on a URL with the form:

<organization_name> .democracyos.com

Azure Websites didn't solve this problem for 2 reasons:

1) Azure Websites runs on Windows and we hit Windows-specific issues such as native modules not building on Windows or paths being too long which was not seen in their OSX & Linux development environments.  This is a common problem with open stack oriented companies with our Azure Websites platform.

2) DOS wanted to skip building their application on customer deployment and deploy only the prebuilt application bits per instance. At the same time they needed to easily push built versions of the application for each release and make those updates readily available for each instance. Out-of-the-box this wasn't as easy with Azure websites.

Overview of the Solution

What Democracy OS needed was infrastructure that would allow their customers to dynamically create Democracy OS instances quickly. It turns out that a Docker-based solution could solve their problem by distributing a prebuilt application via the Docker hub and using Dockerfiles to deploy their applications.

 

However, DOS also needed container orchestration and HTTP traffic routing. Because they were already using Heroku, they loved the idea of Deis, an open source cloud which aims to mimic Heroku-style deployments. Powered by Docker containers and the NginX web server, Deis allows easy implementation of the required deployment URL scheme and each customer instance can easily be scaled by any number of Docker containers making each instance horizontally scalable.

 

The figure below shows the application deployment workflow for a new customer DemocracyOS instance:

The Democracy OS management application uses Deis controller API to automate the deployment of new DemocracyOS.com hosted DemocracyOS instances. They use the Docker hub to deploy the prebuilt version of their app and each customer app pulls the base image and is customized using deployment-specific configuration variables set through the controller api.

 

Deis runs on CoreOS, a new Linux distribution which is very small, automatically patches itself with minimal downtime and most importantly, runs in a warehouse computing style over an entire cluster of virtual machines. A CoreOS cluster can power an entire Azure Cloud Service however, the Deis platform itself has had a few issues deploying to CoreOS on Azure and documentation & support was still in its infancy.

 

In particular, they ran into a number of clock skew issues with CoreOS on Azure that caused the distributed config system (etcd) to think the cluster had fatally lost quorum and fail. We engaged the CoreOS team and partnered on a solution that resulted in a bug fix and pull requests to solve the NTP issue in CoreOS build 626. We verified the fix with CoreOS 626, load tested it, and chaos monkeyed the cluster and feel confident in its performance now for future startups. As an aside, and as part of this work, we also migrated the nitrogen.io cluster we are using internally to Deis to get additional operational experience with the Deis/CoreOS/Docker stack for future customers and partners.

How to Programmatically Deploy a 'Wordpress' Style Application on Deis

Democracy OS used the Deis controller api to deploy a the democracy OS base image with deployment-specific variables to control which monogdb database backed the instance as well as other things such as the organization name.

 

We created an example application which is what the actual Democracy OS instance manager implementation (found here) uses. This walk-through, with more detail can be found here.

We want to use the Deis Controller API because we want the ability to plug the power of deis-scalable apps to any existing infrastructure we have.

 

For example - if you have a company that hosts an app for people such as Wordpress.com, Drupal or DemocracyOS this would be super useful to plug into your user-facing application.

 

This repository has an example application using the node.js Deis controller wrapper.

First you need to instantiate a client object and login to the cluster:

 

var DeisAPI =require('deis-api');

var client =newDeisAPI({

    controller : nconf.get('deis_host'),

    secure :false, // Optional

    username : nconf.get('deis_user'),

    password : nconf.get('deis_password')

});

 

We'll use the Inquirer module to extract a few command-line parameters like the Organization Name, Background Color and cpu & memory limits of the application. In a real-world integration you may replace this with a configuration from your database for the specific user or organization you're hosting the app for.

 

inquirer.prompt([{

  type:'input',

  name:'appName',

  message:'Please specify a name for the application instance to deploy'

},

{

  type:'input',

  name:'orgName',

  message:'Please specify a name for the organization'

},

{

  type:'input',

  name:'bgColor',

  message:'Please specify a background color'

},

{

  type:'input',

  name:'memory',

  message:'Please specify the maximum memory allocated to the instance'

},

{

  type:'input',

  name:'cpu',

  message:'Please specify the maximum cpu time allocated to the instance'

}]

 

Calling the API

Now that we have all of our information needed to call the api we'll go ahead and call the api wrapper functions, remember this uses a plain old REST API hosted by your deis cluster so you can do this from any language:

Authenticate

Authentication is easy and this is the equivalent as doingdeis login on the cluster:

 

  console.log('creating app: '+ answers.appName);

  var appName = answers.appName;

 

  // authenticate

  client.auth.login()

Create the App

This registers the App on deis and allocates a virtual host for the app in the form of<app_name>.<your_domain>.com:

 

  .then(function() {

    console.log('sucessfully logged into deis');

    return client.apps.create(appName);

  })

 

However this step just allocates the app space on Deis but doesn't deploy anything. We'll do that in a later step.

Setting Deployment-specific Variables

Now we'll use the questions from the user of the example deployer application to set environment variables for this specific deployment:

  // setup instance-specific environment variables

  // this could be things such as the organization's name

  .then(function(results) {

    console.dir(results);

    console.log('successfully created app: '+ answers.appName);

    console.log('setting deployment specific variables');

    return client.config.set(results.id, {

        ORGANIZATION_NAME: answers.orgName,

        BG_COLOR: answers.bgColor

      },

      {

        memory: { cmd: answers.memory },

        cpu: { cmd:parseInt(answers.cpu) }

      });

  })

 

Notice how we're setting the environment variables ORGANIZATION_NAME as well as BG_COLOR to the variables collected from the user of this example app. This data however can come from a database, a json file, or anywhere else for your specific use case.

 

Deploying the Docker Image to the Application

Finally to deploy the image, (in our case, our registry is the Docker hub) we simply specify the image name and Deis will automatically deploy the application. Deis knows when your Docker image exposes an endpoint and will automatically route port 80 or 443 to the virtual host name:

 

  .then(function(){

    console.log('successfully set deployment-specific variables');

    return client.builds.create(answers.appName, nconf.get('docker_hub_username') +'/simple-node:latest');

  })

  .then(function(results) {

    console.dir(results);

    returnconsole.log('successfully deployed node.js application');

  })

 

Now after a couple minutes (this application specifically deploys its npm packages on startup) you should see the customized app which is setup to change the background color and display the organization name set in the app settings.

Code Artifacts

The primary artifacts are contributions to external open source projects. We made a contribution of tooling and documentation to the Deis project about how to spin up a Deis cluster on Azure, continue to make enhancements to our CoreOS Linux agent, and helped diagnose issues with both on Azure.

 

We also created a generic example on how to use the Deis controller api to do 'Wordpress' style deployments on Deis using Docker hub.

 

Democracy OS also open-sourced their instance manager which handles deploying to Deis via controller apis.

Opportunities for Reuse

There are many opportunities for reuse by any company interested in moving workloads from Heroku (Salesforce) to Azure. Deis also provides a solid devops foundation for running open source workloads from scratch on Azure through its developer friendly 'git push' development model. Developers can learn more about the Deis platform and how to deploy it on Azure at https://deis.io.

 

Steven Edouard is a full-time hacker & Software Engineer on the Partner Catalyst Team in San Francisco. Most of what he does is open-sourced on github and you can learn more about him at stevenedouard.com.

 

Tim Park is a Principal Engineer and Silicon Valley site lead for Microsoft. Tim works in the Partner Catalyst Team, which works with customers, partners, and open source communities to get the platforms they use to running on Azure.