Quick intro to docker-compose

What is docker-compose

Like docker itself allows managing single container, docker-compose makes it easy to control not just one, but all containers that make distributed app. This includes containers, networks, volumes and all related settings.

If you think about it, starting an app that has more than one container is less than trivial task and it gets exponentially harder as you add more or them. Let’s check out simple example: distributed web-application that consists of two containers – one with web content and one with database.

It will require at least three startup steps:

  1. create user-defined network (to allow containers talk to each other by name),
  2. launch container with database, providing its name (e.g. “db”) and newly created network to attach to,
  3. launch container with web content, also providing its name (e.g. “web“) and target network.

And here are some problems. Firstly, order of execution matters. Obviously, you cannot connect to non-existing network, and web-container might fail, if its database service doesn’t exist. Secondly, some of components may or may not exist. E.g. web may need to be built first, and user-defined network doesn’t have to be created if it’s already there.

Any self-respecting programmer can create a script to automate that, but why bother, if there’s docker-compose.

With compose you can create docker-compose.yml, which acts like Dockerfile, but for whole application. Once it contains description of all services-containers that make an app, compose will infer startup order, create or reuse missing dependencies during the launch and even will perform proper cleanup after application is shut down.

Installing docker-compose

Mac and windows users are in for a treat: Docker installer includes compose by default. Linux users are less lucky today and have to consult installation guide.

docker-compose.yml

As I mentioned, docker-compose.yml acts like a Dockerfile, but at application level. Coming back to distributed web-app example we started with, let’s assume we need to build web server container from Dockerfile, and database layer is good old mysql. Here’s how compose file would look like:

Pretty cool, right? The file literally says that application consists of two services: web and db. First one needs to be built from Dockerfile located at ./web-app and it needs db to run. The second container is clean mysql image from official repo, and we even specified its root password in environmental variables.

As a free bonus, compose creates new user-defined network and connect all containers to it. It will use default network driver (bridge), but it’s changeable.

There’s one caveat, though. depends_on  will make sure that container starts immediately after dependency is started, but this doesn’t mean that dependency will be ready, whatever that means for you application. For instance, when I start mysql container, container itself will start almost immediately. However, mysql server inside it usually takes several seconds to start. During that seconds container is started. But as a service, it’s not ready. Because ‘ready’ means different things for different applications, compose waits for ‘started’ state only.

Starting and stopping app with compose

Compose has two sets of commands for starting and stopping an app. up  and down  affect whole application, whereas start  and stop  control individual services.

docker-compose up

The command starts application from the ground up: creates network, builds Dockerfiles and starts services. Adding -d  argument will start application in background.

Compose will prefix container names with application name (current folder name), but within application network original names like web and db are still available.

docker-compose ps

…will show which application services are running. It’s very similar to  docker ps .

docker-compose down

…undoes everything that up  did: shutdowns and deletes containers, networks, etc.

docker-compose start/stop

When application is running sometimes it’s necessary to suspend certain components without deleting them. This is where start/stop come in handy.

However, if I wanted to upgrade the container, just stopping, building and starting it wouldn’t work. This would –  docker-compose up --no-deps --build web

Conclusion.

docker-compose is a tool to have nearby when number of application containers becomes greater than one. Its docker-compose.yml file format is simple and it has way more options than we’ve just covered, such as build parameters, networks and volumes, environment vars imports, etc.. Compose itself is not limited with start/stop commands, but also allows app monitoring, executing arbitrary commands against services, and few others.

3 thoughts on “Quick intro to docker-compose

Leave a Reply

Your email address will not be published. Required fields are marked *