Docker Compose is a program that simplifies the building of Docker applications by allowing you to define all the service components of the application in a single yaml file.

Unlike Docker Swarm or Kubernetes, it does not provide orchestration or any infrastructure level support around your application. However, it does simplify defining services that are intended to run on a single-node Docker node. Rather than starting Docker containers from the command line, where volumes and network linking can get complicated, the entire application can be laid out in a yaml file and the entire application can be deployed using the docker-compose command.

Installation[edit | edit source]

To use Docker Compose, download the latest binary and stick it in your PATH. Get the binary from:

Usage Example[edit | edit source]

For instance, if a LAMP stack is required, a docker-compose configuration file would define each of the components making up the LAMP stack (Apache+PHP, MySQL, optionally a Load Balancer). Rather than manually creating/removing each of the Docker containers and networks manually, the entire service can be brought up or down with one command.

An example docker-compose.yml file containing such a LAMP stack:

version: '3.3'

services:
  traefik:
    image: traefik:latest
    restart: always
    command: --web --docker --docker.watch --docker.exposedbydefault=false
    volumes:
      - /var/volumes/lamp/traefik/traefik.toml:/traefik.toml
      - /var/volumes/lamp/traefik/acme.json:/acme.json
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      external_net:
        ipv4_address: 1.1.1.1
      backend:

  web:
    build: web/.
    restart: always
    volumes:
      - /var/volumes/lamp/data:/export/data
      - /var/volumes/lamp/config:/export/config
    networks:
      backend:
    ports:
      - "8080:8080"
    depends_on:
      - db
    labels:
      - "traefik.enable=true"
      - "traefik.port=8080"
      - "traefik.frontend.rule=Host:hello.steamr.com"

  db:
    image: mariadb:10
    restart: always
    volumes:
      - /var/volumes/lamp/db:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=xxxx
      - MYSQL_DATABASE=web
      - MYSQL_USER=web
      - MYSQL_PASSWORD=xxxx
    networks:
      - backend
        aliases:
          - mysql

networks:
  external_net:
    external: true

  backend:
    ipam:
      config:
        - subnet: 192.168.246.0/24

To bring this LAMP service up, run:

# ls
docker-compose.yml

##  the '-d' is for detached mode
# docker-compose up -d

docker-compose will then read the configuration file and set up the Docker networks and bring up the Docker containers with the required configs (image, volumes, network settings, environment variables, etc.) as defined in the file. Networking between different containers within the same service are done using dynamic linking automatically (rather than static links with hosts files) since individual containers can be recreated without bringing the entire stack down. The stack can be brought down using

# docker-compose down

If any changes are made to the docker-compose.yml file later on, the stack can be brought up to date by running docker-compose up again:

# docker-compose up -d

Networking[edit | edit source]

Some notes on networking in docker-compose:

Ports[edit | edit source]

Expose ports. Either specify both ports (HOST:CONTAINER), or just the container port (a random host port will be chosen).

  • Ports listed in docker-compose.yml will be accessible among all containers within this service.
  • These ports will be exposed to the host machine to a random port or a given port.

For example, we can start a MySQL server on port 3306. Any other container in this stack will be able to reach mysql:3306 (container-name:port). The DNS name is resolved by Docker's internal DNS service. The host machine is also able to reach the container, though its port will be randomized.

mysql:
  image: mysql:5.7
  ports:
    - "3306"

If you need MySQL exposed to the host on a specific port, such as 3306, pass in the HOST:CONTAINER port numbers. Since this binds to a specific port, be mindful of any existing ports in use either as containers or services running on the host.

mysql:
  image: mysql:5.7
  ports:
    - "3306:3306"

If the host machine has no firewall restricting access to port 3306, other machines that can reach the host machine will be able to talk on port 3306 to reach the MySQL service. If your host machine has multiple addresses, you may also bind to a specific address:

mysql:
  image: mysql:5.7
  ports:
    - "10.1.2.3:3306:3306"

Expose[edit | edit source]

Exposed ports will only be accessible to other containers within this stack. Like above, other containers can reach the MySQL server at mysql:3306 (container-name:port). Since this port is not exposed and bound to the host machine's network address, you may have multiple containers exposing the same ports without running into conflicts.

mysql:
  image: mysql:5.7
  expose:
    - "3306"

Networks[edit | edit source]

Provide a list of networks that the container should be connected to. In the example above, 'traefik' (the load balancer/proxy) is connected to the backend network (used to communicate to the web server), as well as the internet with a defined IP address.

If a private network is used (eg. the backend network in the example above), it is necessary to define the subnet that network is on by specifying the ipam subnet. Ensure that this subnet does not conflict with any other subnets that are running on the same docker host.