With the recent launches of ImageLayers and Lorry, the CTL Labs team has been thinking a lot about the deployment of containerized applications. Over the past month we've prototyped a few ideas that tackle container deployment in different ways. Today we're happy to announce our first project, Zodiac. Built with small teams and single developers in mind, it is designed to be lightweight and plug into the existing Docker tooling. Zodiac makes it easy to deploy and rollback containerized applications. Our focus is on simplicity and ease of adoption, not features. We welcome your feedback in helping us to chart the future path for Zodiac.
Standing on the shoulders of giants, on the shoulders of other giants
At this point Zodiac is more or less a wrapper around Docker Compose. This is very much intentional, and, we encourage developers to use Docker Compose for specifying application configuration. Many applications are already described with a Docker Compose file, so it seemed natural to leverage that for remote deployments. Since we're just wrapping Docker Compose, you can do a remote deployment with Zodiac by simply pointing the client at a remote Docker endpoint. Similarly, if you want to deploy to a cluster you can reference a Docker Swarm endpoint. Zodiac has the same limitations with Docker Swarm as Docker Compose does.
Minimal pre-requisites and dependencies
Zodiac only requires that a Docker endpoint is exposed via TCP. Docker Machine can fulfill this pre-requisite, and we recommend using it, as Zodiac was designed to play nicely with Docker Machine managed endpoints. On the client machine Zodiac will rely on Docker Compose being installed, along with the Zodiac binary. Installation Instructions can be found in the Zodiac README.
Zodiac in action
Let's walk through a simple example of deploying with Zodiac. With Docker Compose and Zodiac installed locally, and a Docker Machine-provisioned endpoint set up remotely, I can do my first deploy.
So, in my local environment, I have a simple docker-compose.yml file:
#docker-compose.yml demosite: build: . ports: - "80:80"
And the following Dockerfile for the demosite service:
FROM nginx MAINTAINER Alex Welch ADD . /usr/share/nginx/html CMD ["nginx", "-g", "daemon off;"]
And in an index.html file we just have a string of text:
$ cat index.html Initial Deployment.
The above compose and Dockerfile are intended to be brief and simple for example purposes. Real-world applications will often have multiple services, options, etc.
Zodiac offers a
verify command to ensure the endpoint is responding and using the correct version of Docker or Swarm.
$ eval "$(docker-machine env qa)" # tell both Docker and Zodiac to interact with my "qa" docker machine endpoint $ zodiac verify Successfully verified endpoint: tcp://188.8.131.52:2376
With that we can do our first deploy.
$ zodiac deploy Deploying your application... Creating zodiac_demosite_1 Successfully deployed 1 container(s)
Now let's list the deployments
$ zodiac list ID DEPLOY DATE SERVICES MESSAGE 1 2015-08-03 16:49:11 zodiac_demosite_1
At this point we can curl the endpoint, and if we do a
docker ps against the remote Docker host we'll see the running containers:
$ curl http://184.108.40.206 # confirm the site is responding Initial Deployment. $ echo $DOCKER_HOST tcp://220.127.116.11:2376 # i.e. we are pointing at the remote Docker endpoint $ docker ps # against remote docker endpoint CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 547957411d17 a01d3f72d8e76e883f894cacd651769facb46252678f3d998db677d0e532ca60 "nginx -g 'daemon of 41 seconds ago Up 40 seconds 0.0.0.0:80->80/tcp, 443/tcp zodiac_demosite_1
We can see here the Image is not what we would've expected. This is because Zodiac snapshots the image's actual layer id at the time of deploy, enabling accurate rollbacks. This is probably the most important component of Zodiac. If an image tag is updated to point at a new layer ID after the deployment has happened, the rollback history would be inaccurate. By recording the actual layer ID we preserve the ability to rollback.
I'll update some of the my source files, and deploy again, but this time with a message.
$ echo "Now with updated text." > index.html # update a file that comprises part of the image $ zodiac deploy -m "updated copy" Deploying your application... Creating zodiac_demosite_1 Successfully deployed 1 container(s) $ zodiac list ID DEPLOY DATE SERVICES MESSAGE 2 2015-08-03 16:51:59 zodiac_demosite_1 updated copy 1 2015-08-03 16:49:11 zodiac_demosite_1
Okay, now we've got two deployments in the history (the top being the current deployment). If we curl the endpoint or look at the containers we'll notice our updates.
$ curl http://18.104.22.168 Now with updated text. $ docker ps # against remote docker endpoint CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 723169939fa0 46af78669c27d86601c7b1ed30dda5d012032777473d9698bcc83c1ed74787de "nginx -g 'daemon of About a minute ago Up About a minute 0.0.0.0:80->80/tcp, 443/tcp zodiac_demosite_1
Notice the IMAGE for zodiac_demosite_1 has a different name now (77e9f456...). This is because we built a new image with the edits to the README.md baked in.
Let's say the change to index.html was a bad idea, and we need to rollback.
$ zodiac rollback Rolling back your application... Creating zodiac_demosite_1 Successfully rolled back to deployment: 1 $ zodiac list ID DEPLOY DATE SERVICES MESSAGE 3 2015-08-03 16:54:02 zodiac_demosite_1 Rollback to: #1 2 2015-08-03 16:51:59 zodiac_demosite_1 updated copy 1 2015-08-03 16:49:11 zodiac_demosite_1
Notice the additional entry and message in the list output. $ curl http://22.214.171.124 Initial Deployment.
$ docker ps # against remote docker endpoint CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b78ab6773a2d a01d3f72d8e76e883f894cacd651769facb46252678f3d998db677d0e532ca60 "nginx -g 'daemon of 3 minutes ago Up 3 minutes 0.0.0.0:80->80/tcp, 443/tcp zodiac_demosite_1
Now the IMAGE for zodiac_demosite_1 is back to the same as it was in the initial deploy. Rollback successful!
From here, I recommend kicking the tires yourself. We had specific use cases in mind for Zodiac, but have tried to leave it open-ended. Again, community feedback is welcome via Github Issues.
Stay tuned. Next in our deployment series, Brian Dehamer will talk about another take on deployment, one that we use for our Production Docker deployments.