Docker Compose: Orchestrating Multi-Container Applications


  Up until now, we've learned how to package a single application into a Docker container. However, modern applications are rarely monolithic; they are usually a collection of interconnected services (e.g., a backend, a database, a frontend, a caching service, etc.). Managing these multiple containers individually can become complex and tedious. This is where Docker Compose becomes an indispensable tool. Docker Compose allows you to define and run multi-container Docker applications with a single command.


What is Docker Compose?


Docker Compose is a Docker tool that allows you to define and run multi-container applications. It uses a YAML file to configure your application's services, networks, and volumes, and then with a single command, you can create and start all defined services. It's ideal for development and testing environments, and can also be used in smaller staging or production environments.


Why use Docker Compose?

  • Reproducible Environments: Define your entire application stack in a single file, ensuring that all team members (or CI/CD environments) work with the same configuration.
  • Simplified Deployment: Start or stop your entire application with a single command, instead of managing each container individually.
  • Inter-service Communication: Docker Compose creates a default network for your services, allowing them to communicate with each other using their service names as hostnames.
  • Dependency Isolation: Each service runs in its own container, which helps to isolate dependencies and prevent conflicts.

Key Concepts of Docker Compose


  • Services (`services`):

    Services are the individual components of your application (e.g., your web application, the database, a caching server). Each service corresponds to a container (or a set of containers from the same image).

  • Networks (`networks`):

    Docker Compose creates a default network for your application, allowing services to discover and communicate with each other using their service names as hostnames. You can also define custom networks.

  • Volumes (`volumes`):

    Volumes are the preferred mechanism for persisting data generated by and used by Docker containers. They are crucial for databases or other services that need to store information durably.


Creating a `docker-compose.yml` file


The `docker-compose.yml` (or `docker-compose.yaml`) file defines the configuration of your Docker Compose application. It should be in the root directory of your project.


Example: Node.js Application with MongoDB

Let's consider a simple Node.js application that connects to a MongoDB database.


# docker-compose.yml
version: '3.8' # Docker Compose syntax version

services:
  web: # Defines the Node.js application service
    build: . # Builds the image from the Dockerfile in the current directory
    ports:
      - "3000:3000" # Maps host port 3000 to container port 3000
    environment:
      NODE_ENV: development
      MONGO_URI: mongodb://db:27017/myapp # DB connection using the service name 'db'
    volumes:
      - .:/usr/src/app # Mounts the local directory to the container for development (hot-reloading)
      - /usr/src/app/node_modules # Prevents host's node_modules from overwriting container's
    depends_on:
      - db # Ensures 'db' starts before 'web'
    networks:
      - app-network # Assigns the service to a defined network

  db: # Defines the MongoDB database service
    image: mongo:latest # Uses the official MongoDB image
    ports:
      - "27017:27017" # Optional: exposes MongoDB port to the host (useful for DB tools)
    volumes:
      - db-data:/data/db # Persists DB data using a named volume
    networks:
      - app-network # Assigns the service to the same network

volumes: # Defines named volumes
  db-data:

networks: # Defines custom networks
  app-network:

Section Breakdown:

  • `version`: Specifies the Docker Compose syntax version. `3.8` is a common and stable version.
  • `services`: Contains the definition of each container that makes up your application.
    • `web`: Your service name (can be anything).
      • `build: .`: Tells Docker Compose to build the image for this service using the Dockerfile in the current directory.
      • `image: my-app:1.0` (alternative to `build`): If you already have a built image or want to use one from Docker Hub.
      • `ports`: Maps ports between the host and the container.
      • `environment`: Defines environment variables for the container.
      • `volumes`: Mounts volumes to persist data or for hot reloading during development.
      • `depends_on`: Defines the dependency between services (e.g., the web depends on the DB). It does not wait for the service to be "ready," only that it has started.
      • `networks`: Assigns services to specific networks.
    • `db`: Another service, in this case for MongoDB.
      • `image: mongo:latest`: Uses a pre-existing image.
      • `ports`: Exposes the database port.
      • `volumes`: Uses a named volume for database data persistence.
  • `volumes`: Declares named volumes that can be reused by different services or instances.
  • `networks`: Declares custom networks. By default, Compose creates a network for the entire project.

Main Docker Compose Commands

Once you have your `docker-compose.yml` file, you can manage it with the following commands (from the directory where the file is located):


  • `docker compose up` (or `docker-compose up` in older versions):

    Builds, (re)creates, starts, and attaches to containers for all services defined in the file.

    docker compose up              # Starts in the foreground
    docker compose up -d           # Starts in the background (detached mode)
  • `docker compose down`:

    Stops and removes containers, networks, and volumes (unless they are named volumes explicitly defined without `--volumes` or `-v`) created by `up`.

    docker compose down
    docker compose down --volumes  # Also removes named volumes
  • `docker compose ps`:

    Lists the containers for the current Compose project.

    docker compose ps
  • `docker compose logs [SERVICE_NAME]`:

    Displays the log output of the services.

    docker compose logs web
    docker compose logs -f         # Follows logs in real-time
  • `docker compose exec [SERVICE_NAME] COMMAND`:

    Executes a command in a running container of a service.

    docker compose exec web bash # Opens a shell in the 'web' container

  Docker Compose transforms the management of multi-container applications from a complex exercise into a simple and reproducible process. It's an essential tool for setting up identical development environments for all team members and for deploying complete application stacks with ease. Mastering Docker Compose is a crucial step towards a more efficient and robust development and deployment infrastructure.

JavaScript Concepts and Reference