- November 6, 2015
My one true layout
Recently I’ve been “evangelizing” Docker quite a bit among the Happy Cog developers. Sometimes that sounds like “zomg, Mark really loves Docker” and other times it’s closer to “omg, why is he over engineering this again.” What I’ve been working on, lately, is a way to use Docker containers to re-implement a more flexible version of Heroku. The end goal is a workflow that starts with a developer pushing code. That code, regardless of branch, is published to a unique URL that anyone can see, regardless of their setup or environment.
The reason for this workflow is to reduce the amount of time code is hidden away on developer computers. All too often it’s easy to hide behind Git and developer setup with claims such as “it works on my computer” or “oh, it’s not on staging yet.” With this workflow every push results in a URL that anyone can see. It enables our team to work quickly and collaboratively with team members that may not have a complete development environment setup.
So, how’s this all work? Glad you asked:
- First, we push code to Github. We can push any branch or any tag, it really doesn’t matter. The goal here was to leverage Github as best we can without affecting developer process or workflow. If developers have to remember to push to a second remote or run a second CLI command, they’re bound to forget and we wanted to reduce that.
- That code is picked up automatically by CircleCI and built. CircleCI has a fantastic circle.yml file that allows complete customization of the build process. For example we can configure Gulp in one project’s circle.yml and Grunt in another project’s circle.yml. What’s more, CircleCI has built in support for Docker.
- CircleCI runs `npm install` which in turn runs `bower install` and finally `grunt` and/or `gulp`. The real flexibility of CircleCI shines here by allowing you to prepend, append, or completely overwrite the inferred build process with your own custom scripts.
- After the build we get a complete public folder with everything we need to deploy to our staging server.
- Here, I’m beginning to run a few integration tests, such as PhantomCSS. Nothing has stuck yet, but again, the flexibility of CircleCI makes it possible to run just about anything here.
- Docker Compose then runs and builds everything into a series of Docker images. The benefit of using Docker Compose is that I can build a nginx server, a redis cluster, a MySQL server, and a Varnish server all in one go. This allows me to run virtually anything I want within a project. If Project A is written in Go, that’s fine. If Project B is written in Ruby, that’s fine too.
- After the images are built they are pushed to a private registry on Tutum.co. Tutum is a orchestration service for (née, by) Docker. Tutum exposes a robust API that allows you to build containers on your own infrastructure.
- CircleCI then works with the Tutum API to deploy each image out to a running container. Once each container is running it gets a generic domain name ending in cont.tutum.co.
- Finally, we have a private proxy (written in Node, backed by Redis) that receives a POST with the new container IP/port so we can proxy a cleaner URL matching {branch}.{repo}.domain.com.
This has been something I’ve been iterating on for a while, and, though it’s probably better than my hacked-together shell scripts, which, is certainly better than my blind edit via FTP it’s still not perfect. Spinning up an entire nginx server from scratch on every single push just to front Pattern Lab is a bit heavy handed. Ideally there’d be some way to update the running container faster than a fresh build, but the isolation and purity of the current approach has appeal too.
I’m curious how do you build development environments? How do you demonstrate deliverables to clients? Are you still hacking on FTP?