cd ..
DOCKER

Docker Compose: Orchestrating Multiple Containers

Docker Compose: orchestrating multiple containers

In previous parts of this series, we manually created networks, volumes, and containers, one command at a time. It works, but it doesn’t scale: a docker run command with network, ports, environment variables, and resource limits becomes a giant line that’s hard to repeat without errors. Docker Compose solves this by describing everything in a single file.

What is Docker Compose

Compose is used to bring up multiple containers together using a compose.yaml (or docker-compose.yaml) file:

docker compose up

If the file has a different name or is in another path, the -f (for file) flag tells it which one to use — “Docker Compose, use this file here”:

docker compose -f meu-arquivo.yaml up

A first service

version: "3"
services:
  nginx:
    image: nginx
    ports:
      - "8080:80"

A service in Compose is essentially equivalent to a docker run command: image defines the image, ports publishes ports — the same -p we’ve used multiple times in this series, just declared in YAML.

When the service needs a build

If the application doesn’t have a ready-made image published in a registry, Compose needs a Dockerfile in the repository — someone needs to teach Docker how to build that image before running it:

services:
  app:
    build: .
    ports:
      - "5000:5000"

build: . tells Compose to build the image from the Dockerfile in the current directory, instead of downloading a ready-made image.

Connecting multiple services

Here, in a single file, we reproduce exactly what we did manually in the previous part with docker network:

version: "3"
services:
  giropops-senhas:
    image: cesarsantos96/giropops-senhas:1.0
    ports:
      - "5000:5000"
    environment:
      - REDIS_HOST=redis
    networks:
      - giropops

  redis:
    image: redis
    ports:
      - "6379:6379"
    networks:
      - giropops

networks:
  giropops:
    driver: bridge

Volumes in Compose

Named volumes are also declared at the root level and referenced within the service:

services:
  giropops-senhas:
    image: cesarsantos96/giropops-senhas:1.0
    environment:
      - REDIS_HOST=redis
    volumes:
      - strigus:/strigus
    networks:
      - giropops

networks:
  giropops:
    driver: bridge

volumes:
  strigus:

Reserving and limiting CPU and memory

Just like --cpus and --memory in docker run, Compose allows declaring resource limits per service, with the added advantage of also being able to reserve a guaranteed minimum:

services:
  app:
    build: .
    volumes:
      - strigus:/strigus
    deploy:
      resources:
        reservations:
          cpus: '0.25'
          memory: 128M
        limits:
          cpus: '0.5'
          memory: 256M

Conclusion

With a single file, it’s now possible to describe the build, ports, environment variables, networks, volumes, and resource limits for an entire application — and bring everything up with docker compose up. One last question remains, applicable to both a manually run image and one orchestrated by Compose: is this image secure? This is the closing of this series, in the final part.

References

What did you think?