We’ve been using Docker in production for the last six months, and we’d like to share some impressions.

Docker has replaced our deployment scripts, but it has’t otherwise affected how we build or architect software.

There is a lot of hype around the product and technology, with many of the press and blog articles stating that containers are revolutionary. Revolutionary how? Well, that’s where we find many Docker advocates get caught up trying to explain how cool cgroups are or how they are lighter weight VM’s.

For us, the real innovation is the Dockerfile (and docker-compose) that has a single entry point. It is, for us, the best way to describe how to build a VM. The rest of Docker seems to get in the way.

Say we are building a new API service. We want the VM to have a compiled version of our code with all of its dependencies. Previously, we would spin up a new EC2 instance and hack together some kind of scripting language (via Chef or Puppet or Fabric):

  • That would run through various flavors of “apt-get update”
  • “apt-get install -y blahblahblah”
  • Ensure we have the right version of Python, Java, or Ruby
  • Then we have to find a way to get our compiled code from the intranet onto the EC2 instance securely

It was a pain every time. The scripts were brittle and hard to maintain. Deployment was hard.

In contrast, with the Dockerfile, we can do the following:

  • Start with someone else’s pre-built image that already has the right version of Java, Python, or Ruby
  • Within our private Jenkins instance on our intranet, copy our compiled binary into the VM
  • Take a snapshot of the VM, name the snapshot, and publish it to AWS.
  • Tell AWS to start a “VM” using our snapshot.
  • Describe everything within one file without a bunch of “clever” Ruby code

(VM is in quotes because AWS is really launching the VM within an existing EC2 instance)

How is this better?

  • Building Docker images is faster.
    • Maybe 2x faster than waiting for a new EC2 instance to start up and then running through all the “apt-get”.
  • Docker images can be debugged locally.
    • Have an issue with the VM? A developer can start up the same VM image running in AWS on a local dev machine.
    • This was previously not possible because EC2 AMI’s were proprietary.
  • Docker images can be built locally, within the intranet.
    • Not all code and dependencies can be published publicly, and not every organization has a VPN set up with AWS.
    • Also means development can be done on a developer’s laptop 100% in airplane mode.
  • Docker images are composable.
    • Have a standard image for the organization that is based on EC2? Great! Make that its own image, name it, and publish it. Then API services just reference the organization’s image as a starting point. Chef and Puppet claimed to offer this, but in practice I’ve rarely seen it realized.

Other people make claims about cost savings or security, but in our experience neither seems to be that much different or better than running services directly on EC2 instances.

For us, the main differentiation is the Dockerfile itself and being able to describe deployments reliably for all developers. Plus, as much as we love scripting languages, it’s nice that there isn’t any.

Last, a quick shout out: We switched the Jenkins slaves from VMs to Docker containers, and boy, what a wonderful change that is. The problems of mismatched nodejs versions, missing binaries on the right slaves, etc, have all gone away.

Let’s say that there isn’t a Jenkins slave image available, making a new one was “easy”. We prototyped the process for getting the blog re-published. Our Jenkins Jekyll Slave: https://hub.docker.com/r/hiramsoft/jenkins-slave-jekyll/.