March 3, 2020 · Docker

Foundational Overview of the Docker Compose file

No more "Well, it works on my machine" using Docker Compose

Keeping a team working efficiently can be a challenge when you have an application that has many dependencies and requires specific configuration in order to run correctly. You can install each dependency on your machine, but forgetting one step could give you behavior that's different from everyone else.  You could create VM with something like Vagrant and that can be possible, but that could put a lot of strain on your computer's resources and adding a new service is no simple matter. Or you could have a system where running a handful of commands (as little as one) can get you a server up and running, with the right dependencies, and configuration mostly hands free. That's what Docker Compose can do for you.

Docker Compose is essentially an abstraction on top of Docker where you could orchestrate the building and configuration of one or more containers in just one file. This file is named docker-compose.yml. Here's an example from the Docker documentation:

version: '3'

services:
  db:
    image: postgres
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    depends_on:
      - db

We'll break down the docker-compose.yml file soon, but before that I wanted to note something. All you need is that one file and then running the following command and you'll have a complete application running with it's dependencies:

docker-compose up

Yes, that's it. Just that one command. Docker Compose will do the rest for you. In the example above, what you'll have in the end is a Django app running on port 8000 with postgres configured (assuming you include the missing Dockerfile stated in the Docker documentation above).

Examining the docker-compose.yml file

Now lets break down the docker-compose.yml file. It's fairly straightforward once you understand it.

version: '3'

This denotes the version of docker-compose dialect that you'll use in the yaml configuration file. Over time, Docker adds to the dialect so specifying the version allows Docker to know if it can or can't run the directives inside of the yaml file.

services:

Here you list your containers. It's best practice to have one container per service (.i.e. mysql by itself, your app by itself, redis by itself, etc). That allows multiple services to interact with each other and you could scale each container by itself. Occasionally there are cases where you'd put more than one service in a container, but it's highly encouraged to keep it to one service per container.

db:
    image: postgres

The first key db is the name you want to put for your service. Docker Compose exposes all of the containers to each other so you could reference by their host name and their hostname will be the name you call the service in the compose file. The image key is the base image your container will be based off of. Basically an image is a cookie cutter and a container is the baked cookie. You only need one cookie cutter (image) to make many of the same cookies (containers based off of one image).

build: .

If you need to build your container in a very specific way and add your own dependencies you have the flexibility of doing that using a Dockerfile. The build key denotes where to find that file. In that Dockerfile you'll specify the base image you'll use, say ubuntu, redis, etc. By default, it pulls images from https://hub.docker.com/, but you could specify your own registry. Say, for instance, you need to install very specific libraries, maybe even compile a program manually, you would use a Dockerfile to delineate all of those steps.

command: python manage.py runserver 0.0.0.0:8000

This is the command that's run after the container has been built and is running without any errors. You could specify any command that will run inside of the container. It's important that the command runs in the foreground or else your container will stop immediately. You could even specify any command that doesn't exit immediately like tail -f /dev/null just to keep the container running.

volumes:
      - .:/code

This says to mount the local path . to the path /code inside of the container.

ports:
      - "8000:8000"

This means to forward calls from port 8000 on the host machine to port 8000 in the container. For instance, you could call the web service on your host machine with http://localhost:8000.

depends_on:
      - db

If you need other services that you depend on like a database you can use depends_on. This will bring up those containers in the listed order, but not specifically wait for them. There's also the similar links key which waits until the containers listed under links are actually running before it runs.

And there you go, that's an overview of how easy it is to use Docker Compose to set up your application very easily for you and for others in a repeatable and predictable fashion.

Subscribe by Email

Get my latest content straight to your email

    We won't send you spam. Unsubscribe at any time.
    Powered By ConvertKit

    Liked this article? Share it on your favorite platform.

    • LinkedIn
    • Tumblr
    • Reddit
    • Google+
    • Pinterest
    • Pocket
    If you have any questions about this article