I’ve spent the past couple of weeks at my new job doing a couple of things: hiring kick ass Python and UI engineers and getting some build-and-deploy infrastructure set up so the team can hit the ground running.
Long story short: I wanted a way to deploy pre-built Docker images from any repository to hosts running in OpsWorks.
I chose Docker because it would let me get a repeatable, consistent environment locally and on various non-production and production environments. And I’d get there a lot quicker than writing Puppet or Chef recipes and using Vagrant.
When it came time to get a non-local environment spun up I turned to AWS due to some networking and security issues around my team’s first project.
Time was of the essence, so I first turned to Beanstalk but found its Docker support problematic. Amazon announced but hasn’t yet released their Elastic Container Service. I ended up picking OpsWorks.
I couldn’t find a lot of advice on the 21st century version of man pages, so I’m writing this up in the hope it helps others, and that wiser folks tell me what I can do better!
Brief OpsWorks primer
You start by defining a layer, which is a group of machines that do similar tasks like serve your Web app, run memcache, or host Celery workers.
Then for that layer you define which recipes fire whenever a machine is setup, or an app is deployed to it, or it’s shutdown, etc.
AWS OpsWork and Docker deployment strategy
The best strategy I could find was on an AWS blog post.
Chris Barclay sets up a layer with recipes that install Docker. Application deployments require the OpsWorks instance to pull your code, including its Dockerfile from a git repo and build it locally before running it.
I didn’t like building the Docker images locally from git sources. It ruled out using pre-built community images and opened the door to random build issues on a subset of the boxen.
What I wanted was a way to deploy pre-built Docker images from any repository to hosts running in OpsWorks.
Improved OpsWorks and Docker deployment
I took the code from Chris Barclay and adopted it. You set some key environment variables in your OpsWork application definition and that tells the chef recipe what registry, image and tag to pull and, optionally, the registry username and password to authenticate with.
Here’s the instructions and source to get up and running:
- Set up a new stackinOpsWorks. Under Advanced set the following:
- Chef version: 11.10
- Use custom Chef cookbooks: https git url to a repo containing the recipes
- Manage Berkshelf: Yes
- Berkshelf version: 3.1.3
- Add a layer
- Type: Other
- Setup: owdocker::install
- Deploy: owdocker::docker-image-deploy
- Add an App
- Type: Other
- Repository type: Other
- Environment variables:
- registry_image: The path portion of a docker pull command ala: docker pull $registry_image
- registry_tag: The tag of the image that should be pulled from the registry ala quay.io/yourusername/yourimage:$registry_tag
- layer: The shortname of the layer the image should be deployed to
- service_port: The port on the HOST that will be connected to the container
- container_port: The port on the CONTAINER that will be connected to the service port
- registry_username: OPTIONAL username to login to the registry
- registry_password: OPTIONAL password to login to the registry
- registry_url: OPTIONAL url to a non hub.docker.com registry ala quay.io