Как я говорил ранее контейнеры как правило живут не долго, причин на это немало, начиная от простого обновления образа контейнера заканчивая простой выкладкой нового приложения. И если каждый раз пересоздавать контейнер вручную, то придётся писать, как минимум три команды для каждого контейнера (стоп, удалить, старт). Помимо этого, нужно еще вспомнить какой образ используется. Ну а если у вас проект, который состоит из нескольких контейнеров одновременно то всё становится еще сложнее.

Еще одно преимущество использования Docker Compose это быстрая изоляция одних контейнеров от других и связь контейнеров по сети. У меня уже есть статьи про сети и про DNS псевдонимы. Используя Docker Compose вы можете автоматически объединить несколько контейнеров в одну общую сеть и обращаться внутри сети по dns именам.

Также используя Docker Compose можно управлять и хранилищем для контейнеров.

docker-compose-benefits

И всё это можно получить просто, описав весь конфиг в одном файле. В качестве конфиг-файла используется yaml файл, по умолчанию имя файла docker-compose.yaml. И всё что вам нужно для работы с кучей контейнеров вы можете получить в одном файле, что даёт возможность управлять контейнеризацией быстрее и проще.

Для управление всем этим добром используется утилита docker-compose. Скорее всего вы уже слышали или еще услышите, что docker-compose не рекомендуется к использованию в боевой середе, мол только для разработки или тестов. Говорят, так потому что считается что лучше использовать для боевой среды kubernetes. И я с этим согласен, но что если вам нужно поднять всего с десяток контейнеров? Разве стоит ради этого создавать кластер kubernetes? Как по мне нет и вместо того чтобы вручную создавать каждый контейнер проще использовать docker-compose, ничего страшного я здесь не вижу.

файл docker-compose.yaml

Первое на что стоит обратить при разговоре про файл docker-compose.yaml это версионность. Файл docker-compose.yaml имеет версии, на данный момент это - 1, 2, 2.1, 3.2, 3.8. Каждая версия указывает на то какие ключи вы можете использовать при написании файла и какой синтаксис.

docker-compose-versioning

🥶docker-compose.yaml.version

version: '3.9'
services:
  web:
    image: nginx:latest
    ports:
      - "8080:80"

  db:
    image: postgres:15
    environment:
      POSTGRES_PASSWORD: example

С конца 2021 года Docker объединил Compose V2 и ввёл единый стандартCompose Specification. Теперь версию можно вовсе не указывать, пи обращению к файлу Docker сам определяет формат по структуре YAML-файла.

😊docker-compose.yaml

services:
  web:
    image: nginx:latest
    ports:
      - "8080:80"

  db:
    image: postgres:15
    environment:
      POSTGRES_PASSWORD: example

Но если вы просто пишите версию в файле наугад, то делаете неправильно. Версия файла, которую вы можете использовать зависит от версии вашего docker-compose.

docker compose version
Docker Compose version v2.27.0

Если же вдруг в выводе будет версия v1.x, то у меня для вас плохие новости новые версии использовать вы не сможете и придётся указывать версию руками в файле. А вообще сидеть сейчас на старом docker-compose нет никакого смысла.

Имя файла конечно же может быть и другим, но в таком случае при использовании команды docker-compose необходимо передать имя файла используя опцию -f.

Зачастую многие разработчики софта создают уже готовый docker-compose.yaml и размещают его на github. В таком случае конечному пользователю всего лишь необходимо скачать этот файл и создать все необходимые контейнеры для работы приложения, очень удобно и быстро.

файл docker-compose.yaml

Рассмотрим базовый docker-compose.yaml, который создаст два контейнера (app, db) в одной сети backend.

Обратите внимание на отступы, если не соответствовать иерархии (отступам), то при попытке создания контейнеров вы получите ошибку. Лучше использовать редакторы с возможностью анализировать структуру yaml файлов.

docker-compose-file-structure

🪲docker-compose.yaml

# 📦 Раздел "services" — описывает контейнеры, которые будут запущены.
services:
  app:
    image: python:3.11-slim               # образ контейнера
    container_name: myapp                 # имя контейнера (опционально, dns name)
    build:                                # если хочешь собрать из Dockerfile
      context: .                          # путь к Dockerfile
      dockerfile: Dockerfile
    command: python app.py                # команда, выполняемая при старте
    working_dir: /usr/src/app             # рабочая директория внутри контейнера
    volumes:
      - .:/usr/src/app                    # монтирование локальной папки
      - app_data:/data                    # подключение именованного volume
    ports:
      - "8080:80"                         # проброс портов (host:container)
    environment:                          # переменные окружения
      - DEBUG=True
      - DATABASE_URL=postgres://user:pass@db:5432/mydb
    depends_on:                           # зависимости между контейнерами
      - db
    networks:                             # указание сетей
      - backend

  db:
    image: postgres:15
    restart: always                       # политика перезапуска
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb
    volumes:
      - pg_data:/var/lib/postgresql/data  # подключение именованного volume
    networks:
      - backend

# 🗃️ Раздел "volumes" — хранение постоянных данных (не удаляются при stop).
volumes:
  pg_data:
  app_data:

# 🌐 Раздел "networks" — настройка сетей между контейнерами.
networks:
  backend:
    driver: bridge                        # тип сети (по умолчанию — bridge)

Создание контейнеров с помощью docker compose

Теперь когда есть готовый файл docker-compose.yaml нужно как-то создать контейнеры используя его. Для создания контейнеров используется docker compose, в более старых версиях docker-compose. Если у вас не установлен docker compose, то выполните установку docker-compose-plugin, более подробнее для RHEL и Ubuntu.

Для начала проверим что что можно сделать, используя docker compose вызвав справку ````docker compose –help```. Вот список наиболее часто используемых команд:

  • down - остановка и удаление контейнеров и сетей
  • exec - выполнение команды внутри контейнера
  • logs - просмотр логов контейнера
  • ps - просмотр списка контейнеров
  • pull - скачивание образа для контейнера
  • restart - перезапуск контейнера
  • start - запуск контейнера
  • stop - остановка контейнера
  • top - просмотр процессов
  • up - создание и запуск контейнеров

Как вы поняли из списка команды выше для создания контейнеров используется команда docker compose up.

Для начала я создам файл docker-compose.yaml с одним контейнером использующим образ nginx и выполню команду создания и запуска контейнеров.

🪲docker-compose.yaml

services:
  mynginx:
    image: nginx: 1.18
    ports: 80:80
docker compose up -d
  Network dockerfile_default      Created                                                                                              
  Container dockerfile-mynginx-1  Started 

Теперь я проверю что контейнер действительно запустился. Обратите внимание что docker compose ps и просто docker ps выведут разные списки. Дело в том, что docker compose работает только с контейнерами, которые описаны в файле.

docker compose ps
dockerfile-mynginx-1   nginx:1.18
docker ps
dockerfile-mynginx-1   nginx:1.18
ome-postgresql2				postgres:17.6

Остановка и удаление контейнеров с помощью docker compose

Если нужно просто остановить контейнеры, но сохранить их так же как ив аналогии с командой docker используется stop.

docker compose stop
  Container dockerfile-mynginx-1  Stopped 

Если же нужно еще и удалить созданные контейнеры с помощью docker compose используется down, созданные volume при этом не удаляются.

docker compose down
  Container dockerfile-mynginx-1  Removed
  Network dockerfile_default      Removed

docker-compose-lifecycle