Ever since Docker launched an updated version of the Docker Compose file format, Compose V3, there has been a bit of confusion around how to think about your Compose file(s). For Codeship, the confusion is often doubled because our own service's definition of file --
codeship-services.yml -- reuses a lot of Compose syntax to let you build your CI/CD environment.
Luckily, the two files share a lot of similar abstractions, which makes it easier to reason about them.
Recently Docker has spent a lot of time building out its products and services offering, giving you more and more things you can do with your containers. This is good, because containers aren’t really the point. Containers are just a way to get something done, and what you’re trying to get done is really the part Docker (and Codeship) care the most about.
Containers are a how or a method. Things like Docker Cloud, Docker Swarm-mode, and Docker EE increasingly seek to answer the why -- what are you trying to do with the containers you’re building?
What Is Compose V3 and How Is It Different?
It stands to reason, then, that we might see some changes in things like Docker Compose. Up until now, Compose has been a standalone product focused on enabling you to run applications with Docker. As Docker’s products expand to cover more use cases, though, Compose is likely going to be leaned on to start filling other roles.
With V3, that begins with knowing how to orchestrate and deploy your application to your Docker Swarm cluster, in addition to knowing how to run your containers locally. You may end up with multiple Compose files, and you may end up thinking of the Compose file as a general, Docker-syntax implementation schema for any one of a potential variety of use cases rather than a specific file for a specific tool named Compose.
So that’s the heart of Compose V3: deploying to Docker clusters, easily. Compose V3 allows you to also maintain a Compose V2 file in the same directory. That's great because the V2 spec is built out with more robust options for running applications locally or in development modes.
Compose V3 Can Be Somewhat Confusing with Codeship Pro
Now, onto the goal: running a CI/CD pipeline with Codeship Pro that deploys to a Docker cluster (Docker in Swarm Mode).
Presumably you know how to use Swarm, at least at a high level, and if you don’t, we’d recommend reading the introduction to using Docker in Swarm mode here.
Using Codeship Pro, you create a file named
codeship-services.yml to orchestrate your containers, as well as orchestrate the containers you need as a CI/CD environment. What can seem tricky is that we’ve reused a lot of the syntax and options from Compose to make it much easier to learn and get started, but as Compose continues to evolve, those similarities may lead to questions like does Codeship support Compose V3?
The answer to that is, it depends what you mean!
Question 1 - Will the codeship-services.yml do everything a Compose V3 file will do?
Nope! A lot of V3 wouldn’t make sense for
codeship-services.yml to support, since Codeship is about testing and running deployments, whereas Compose V3 is designed as a blueprint for deploying to a Swarm cluster.
codeship-services.yml may look similar to a Compose file, but the use case is ultimately CI/CD (not container reliability and readiness).
Question 2 - Can I use a Compose V3 file to run Swarm deployments from Codeship Pro?
Yes! A Swarm deployment is a deployment like any other, and a Compose V3 file is a configuration file like any other.
So just like your
codeship-steps.yml files can be used to deploy to and with Kubernetes, Chef, Puppet, Ansible, AWS, and so on, they can also be used to launch Swarm deployments based on a Compose V3 file.
!Sign up for a free Codeship Account
How Compose V3 Works with Codeship Pro
So how does it work?
For the purposes of this post, we’ll assume you already have your Swarm infrastructure itself set up, and we won’t cover the specifics of replicating a live environment.
So first, you’ll want to define a simple Compose V3 file with your Swarm deployment configuration. We’ll add a Swarm deployment to Google on a fork of Docker’s Example Voting App demo. You can see our final source code for this project here.
The first thing we’ll need to do is create our docker-compose version 3 file. This file is, again, used only for the purposes of deploying -- not for running our app locally or in CI/CD. In fact, it supports several directives and options that Codeship does not, as they would not be relevant for a CI/CD stage in your workflow.
version: "3" services: vote: build: ./vote command: python app.py volumes: - ./vote:/app ports: - "5000:80" networks: - front-tier - back-tier result: build: ./result command: nodemon --debug server.js volumes: - ./result:/app ports: - "5001:80" - "5858:5858" networks: - front-tier - back-tier worker: build: context: ./worker networks: - back-tier redis: image: redis:alpine container_name: redis ports: ["6379"] networks: - back-tier db: image: postgres:9.4 container_name: db volumes: - "db-data:/var/lib/postgresql/data" networks: - back-tier volumes: db-data: networks: front-tier: back-tier:
Once you have your Compose V3 file, which provides instructions for the production build and orchestration of your application -- specifically, to deploy it on a Swarm cluster -- we’ll move on to the Codeship side of the fence.
While the above Compose V3 file is useful for everything running a production application requires (such as more advanced use of ports, networks, and commands), we can create a couple of simpler files, one loosely modeled on earlier Compose formats, to run our CI/CD process.
These files are called codeship-services.yml and codeship-steps.yml and they will run your containers in order to execute your testing and deployment commands specifically for your Codeship build execution.
If you’re completely unfamiliar with how Codeship works, we have a short video demo that may make for a good intro. But at a high level, your
codeship-services.yml is used to define the orchestration of all your application containers as well as any custom containers you need for CI/CD (such as containers that authenticate with external infrastructure). Your
codeship-steps.yml file is used to provide those containers the commands you want to run in your CI/CD pipeline.
Note that the
codeship-services.yml file is a close analog to your existing Compose or Compose V2 file. If it wasn’t for this being a Codeship deployment scenario, you might have a Compose V2 file that looks like the below and a V3 file that looks like the above, simultaneously. But for this example, our
codeship-services.yml is taking the place of a V2 file (although you may have all three).
services: sut: build: ./result/tests/ links: - vote - result - worker vote: build: ./vote/ ports: ["80"] links: - redis - db result: build: ./result/ ports: ["80"] links: - redis - db worker: build: ./worker/ links: - redis - db redis: image: redis:alpine ports: ["6379"] db: image: postgres:9.4 codeship_googlecloud_deploy: image: codeship/google-cloud-deployment encrypted_env_file: ./ci/google-credentials.encrypted add_docker: true volumes: - ./:/deploy
As you can see, our codeship-services.yml is very similar to our separate Compose V3 file. But it is somewhat simplified and anticipates slightly different use cases.
Once this is in place, Codeship will know how to build your containers for CI/CD. You’ll then create your codeship-steps.yml to list all of the commands in your pipeline: your tests, image pushes, and deployments.
All of these commands run in the containers defined by the
codeship-services.yml file, so you can already see how
codeship-services.yml and Compose may look and feel similar but have divergent (though not dissimilar) uses.
- name: tests service: sut command: "/app/tests.sh" - name: google-cloud-deployment service: codeship_googlecloud_deploy command: ./deploy/ci/google-deploy
As you can see here, we’re instructing our
codeship_googlecloud_deploy service to run some scripts in our repo, specifically for deployment, but only after our test scripts finish successfully first. The tests use the
sut container built from your Services file, rather than the
codeship_googlecloud_deploy container. This lets us specify different authentications and different tooling needs per container for different steps in our pipeline.
The second step, the one calling
./deploy/ci/google-deploy, is where our Swarm deployment happens. So let’s take a look at that script:
#!/bin/bash # Authenticate with the Google Services codeship_google authenticate # switch to the directory containing your app.yml (or similar) configuration file # note that your repository is mounted as a volume to the /deploy directory cd /deploy/ # copy the application files # gcloud compute scp [!.]* user@swarm-mgr-1:./ --quiet --recurse --zone us-east4-c gcloud compute copy-files [!.]* user@swarm-mgr-1:./ --quiet --zone us-east4-c # deploy the application gcloud compute ssh user@swarm-mgr-1 --zone us-east4-c --command "sudo docker stack deploy --compose-file docker-stack.yml vote"
You can see that in order for it to authenticate with Google, it copies some files over and finally runs the
docker stack deploy command to leverage our Compose V3 file for a full Swarm deployment to Google Cloud Compute.
So at a high level, that’s Compose V3 and how it fits into the exciting and expanding world of Docker and how you might use it with Codeship Pro.