Back to the front page

Deploying Ember Applications with Divshot

At AlphaSights, we were recently faced with finding a solid deployment setup for all our Ember applications. I’d like to briefly describe the process that brought us from Heroku to Divshot.

In the beginning there was Heroku

Heroku was our natural first choice. We have the majority of our applications there, and we all love the simplicity of git push.

tonycoco maintains a very good heroku buildpack suited for this case, so deploying just meant creating the applications with that buildpack and running git push.

Since we need our websites to be served securely we set the FORCE_HTTPS env var to "true".

We also wanted to cache and distribute our assets around the world, so we added CloudFront as an extra layer. Once we set up CloudFront with the appropriate origin, all we had to do was prepend all our asset urls with the CloudFront url. This is very easy with ember-cli:

// Brocfile.js
var EmberApp = require('ember-cli/lib/broccoli/ember-app');

var app = new EmberApp();

if (app.env === 'production') {  
  app = new EmberApp({
    fingerprint: {
      prepend: 'https://YOUR_CLOUDFRONT_ID.cloudfront.net/'
    }
  });
}

Behind the scenes the Heroku build pack uses Nginx to serve the assets. The first visitor will get them from Heroku and after that everything will be served from CloudFront. Whenever you deploy, the assets will get a new digest and so the cache will expire.

This setup works, but it creates an overly complex structure for something that is just serving static files.

Divshot!

While looking around for simpler solutions, we ran into Divshot.
Divshot provides a very simple and powerful platform to deploy static applications. It caches assets, distributes them globally, and has the concept of environments. Environments allow us to build once for staging and then “promote” that build to production. This means that no rebuilding is involved and staging assets are simply transferred to the production environment. The end result is that deploying to production is a very easy and risk free step because you have already tested your staging environment.

The whole deployment process is made even easier by the ember-cli-divshot addon. All we need to do is run ember divshot push staging --token $DIVSHOT_TOKEN at the end of our CI build, and we will have our Ember app in staging ready to test.

Environment variables

Another neat feature Divshot offers is environment variables.
In order to leverage them we had to use my fork of ember-cli-divshot, which adds the script containing Divshot environment variables to the body of the page. We then moved our app specific env vars from ENV.APP to ENV.EmberENV. This is because EmberENV is exposed globally and can be updated at runtime. We then extended EmberENV with Divshot environment variables in app.js like so:

// app/app.js
if (typeof __env !== 'undefined' && __env != null) {  
  _(EmberENV).extend(__env);
}

This setup allows us to build only once for the staging environment and then promote that build to production. Previously, we had those variables specified directly in the environment.js file, but that forbid us from using the promotion feature because the staging build would have its env vars hardcoded inside.

Chat OPS

In order to make the whole process as transparent and secure as possible we manage every task from our chat, a technique that was first popularized by GitHub with hubot. For this purpose I’ve built a hubot plugin which allows us to write hubot divshot promote app-name and app-name will be promoted from the staging to the production environment.

We also get notified in our Flowdock chat when a new build is released. We set up a webhook in the Divshot settings that points to a Zapier URL (e.g. https://zapier.com/hooks/catch/xxxxx/). Zapier is then setup to communicate with our Flowdock chat every time it receives a call to the specified URL by Divshot.

Possible improvements

Although we're pretty happy with our current setup, there is always room for improvement. For example, we could create a custom Heaven provider that would let us deploy with hubot deploy app-name, which is more in line with the way we deploy all our apps. We plan on experimenting with this in the future.

Comments

comments powered by Disqus