Docker Compose
Введение
Docker Compose - это инструмент для определения и запуска многоконтейнерных приложений Docker.
Он использует файлы YAML для настройки служб приложения и выполняет процесс создания и запуска всех контейнеров с помощью одной команды.
Утилита docker-compose CLI позволяет пользователям выполнять команды на нескольких контейнерах одновременно, например, создавать
образы, масштабировать контейнеры, запускать контейнеры, которые были остановлены, и многое другое.
Команды, связанные с манипулированием образами или пользовательскими интерактивными опциями, не актуальны в Docker Compose,
поскольку они адресуются одному контейнеру.
Файл
docker-compose.yml
используется для определения служб приложения и включает в себя различные параметры конфигурации.
Например, параметр build определяет параметры конфигурации, такие как путь к файлу
Dockerfile
, параметр command позволяет
переопределять команды Docker по умолчанию и многое другое.
Первая публичная бета-версия Docker Compose (версия 0.0.1) была выпущена 21 декабря 2013 года.
Первая готовая к производству версия (1.0) была доступна 16 октября 2014 года.
Параллельно существуют две версии: с дефисом и без.
Более старая запускается как
docker-compose
Новая
docker compose
В системе могут быть одновременно установлены обе версии compose
Первый вариант этой статьи был написан во времена docker-compose поэтому могут попадаться как старая так и новая версия.
Установка
Подробно про установку docker compose читайте
здесь
В
Debian
,
Ubuntu
и подобных
sudo apt-get -y update
sudo apt-get install -y docker-compose-plugin
В CentOS , Red Hat , Rocky и подобных
sudo yum -y update
sudo yum install -y docker-compose-plugin
Проверить версию
docker compose version
Docker Compose version v2.28.1
Или
docker-compose -v
docker-compose version 1.27.4, build 40524192
Проверить статус
Чтобы проверить состояние запущенных контейнеров нужно выполнить
docker compose ps --all
Если конейнеры запущены из нестандартоного файла
docker compose -f ./docker-compose-custom.yaml ps --all
Если установлен старый docker-compose (через дефис)
docker-compose ps
РЕКЛАМА от Яндекса. Может быть недоступна в вашем регионе
Конец рекламы от Яндекса. Если в блоке пусто считайте это рекламой моей телеги
Простейшая структура проекта
Рассмотрим следующую структуру
lesson0 ├── docker-compose.yml ├── ubuntu-pytest │ └── Dockerfile └── ubuntu-web └── Dockerfile
Два докерфайла со стандартным названием Dockerfile лежат каждый в своей директории.
docker-compose.yml
По умолчанию файл с настройками проекта для compose называется
docker-compose.yml
Команда
docker compose
требует наличие такого файла.
Если файл с настройками назвается по-другому, например
docker-compose-custom.yml
, то нужно указать путь до него с помощью опции -f
docker compose -f ./docker-compose-custom.yml
Пример простейшего compose файла который поднимет контейнер с Alpine Linux
services: client: image: alpine restart: always command: tail -F /dev/null
docker compose up -d
docker compose ps -a
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS alp-client-1 alpine "tail -F /dev/null" client 13 seconds ago Up 2 seconds
При работе с compose нужно чётко различать SERVICE и NAME.
client - это имя сервиса.
alp-client-1 - это имя контейнера.
В этом примере оно выдано автоматически и не совпадает
с именем сервиса, но иногда может возникнуть следующая ситуация.
services: alpine_client: image: alpine container_name: alpine_client restart: always command: tail -F /dev/null
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS alpine_client alpine "tail -F /dev/null" alpine_client 13 seconds ago Up 2 seconds
Никаких осложнений я в этой связи не встречал, но если вы планируете кому-то объяснять структуру, для простоты рекомендую иметь разные названия.
build
build это команда, которой compose создаёт контейнеры по рецептам непосредственно
из
>docker-compose.yml
или из указанных в нём докерфайлов.
Также build - это парамет в
docker-compose.yml
который показывает на директорию с докерфайлом.
Чтобы показать compose где находится задуманный для данного сервиса докерфайл
нужно с помощью параметра build указать директорию в которой этот докерфайл лежит
services: pytester: build: ubuntu-pytest web: build: ubuntu-web
Пример докерфайла для ubuntu-pytest.
Он просто создаёт контейнер с
Ubuntu
, обновляет её и устанавливает несколько утилит.
# getting base image ubuntu FROM ubuntu:22.04 LABEL maintainer="andreyolegovich.ru" CMD ["echo", "Ubuntu-pytest image is creating"] RUN apt-get -y update \ && apt-get install -y dialog \ && apt-get install -y apt-utils \ && apt-get install -y tree vim \ && apt-get install -y curl gcc g++ make \ && apt-get -y update \ && apt-get -y upgrade
Сбилдить контейнеры можно командой
docker-compose build
Если это первый раз, то придётся подождать пока закончатся все операции
up
Когда контейры созданы, их нужно запустить
Запустить все контейнеры в проекте
docker compose up
Чтобы запустить в фоновом режие (daemon) используется опция -d
docker compose up -d
Чтобы запустить из нестандартного файла
docker compose -f ./docker-compose-custom.yml up -d
В старой версии:
docker-compose up
Creating network "lesson0_default" with the default driver Creating lesson0_pytester_1 ... done Creating lesson0_web_1 ... done Attaching to lesson0_pytester_1, lesson0_web_1 pytester_1 | Ubuntu-pytest image is creating web_1 | Ubuntu-pytest image is creating lesson0_pytester_1 exited with code 0 lesson0_web_1 exited with code 0
Автоматически создаётся сеть lesson0_default, в которой наши контейнеры могут обмениваться данными.
Разберём имя lesson0_pytester_1
lesson0 - это имя проекта, полученное из имени корневой директории.
pytester - это имя контейнера
1 - это номер экземпляра контейнера.
Для запуска в режиме демона используйте опцию -d
docker-compose up -d
Creating network "lesson0_default" with the default driver Creating lesson0_web_1 ... done Creating lesson0_pytester_1 ... done
Эти контейнеры видны после выполнения обычной команды docker ps -a
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4dcaba2ace93 lesson0_pytester "echo 'Ubuntu-pytest…" 3 minutes ago Exited (0) 3 minutes ago lesson0_pytester_1 2339db49d582 lesson0_web "echo 'Ubuntu-pytest…" 3 minutes ago Exited (0) 3 minutes ago lesson0_web_1
Изучить статус можно также одной из команд:
docker compose ps --all
docker compose -f ./docker-compose-cusom.yml ps --all
docker-compose ps
Name Command State Ports -------------------------------------------------------------------- lesson0_pytester_1 echo Ubuntu-pytest image i ... Exit 0 lesson0_web_1 echo Ubuntu-web image is c ... Exit 0
РЕКЛАМА от Google. Может быть недоступна в вашем регионе.
Конец рекламы от Google. Если в блоке пусто считайте это рекламой моей телеги
down
Остановить все контейнеры проекта можно командой
docker compose down
Если запуск был из нестандартного файла:
docker compose -f ./docker-compose-custom.yml down
В старой версии:
docker-compose down
Removing lesson0_pytester_1 ... done Removing lesson0_web_1 ... done
Индивидуальная работа с сервисами
В compose возможно работать с каждым сервисом по отдельности.
Указывать нужно имя сервиса в таком виде, в каком оно задано в docker-compose.yml а не имя контейнера (иногда они совпадают но это не обязательно)
Пересобрать только один контейнер
Если вы внесли изменения только в один
Dockerfile
нет смысла выключать все контейнеры и собирать всё вместе.
Можно указать имя нужного сервиса и воспользоваться командой
up с опциями --detach и --build
Допустим пересобрать нужно сервис
postgres
# docker-compose.yml services: postgres: …
docker-compose up --detach --build postgres
Чтобы остановить и удалить только один контейнер а также удалить все связанные с ним безымянные образы нужно выполнить
docker-compose rm -s -v service_name
В новом compose не нужно -
docker compose up --detach --build service_name
Если нужно использовать build, это можно сделать как из кэша так и без него.
docker compose build postgres
docker compose build --no-cache postgres
Перезапустить только один сервис
Для перезапуска одного сервиса достаточно указать его имя после команды restart
docker compose restart worker
Можно задать таймаут с помощью -t
docker compose restart -t 30 worker
Пример проекта
qa-demo-project ├── docker-compose.yml ├── dockerfiles │ ├── Dockerfile.ubuntu │ ├── Dockerfile.ubuntu.js │ ├── Dockerfile.ubuntu.playwright │ └── Dockerfile.ubuntu.pytest ├── flask-service │ ├── Dockerfile │ ├── requirements.txt │ ├── src │ │ └── app.py │ └── venv │ ├── GNUmakefile ├── logs ├── README.md └── src ├── dev │ ├── app │ │ ├── __init__.py │ │ ├── file_helper.py │ │ ├── main.py │ │ ├── prod.py │ │ ├── psum.py │ │ ├── quadratic.py │ │ └── test_example.py │ └── __init__.py ├── GNUmakefile └── tests ├── js │ └── src ├── pytest │ ├── requirements │ └── src └── robot ├── requirements └── src
docker-compose.yml
version: '3.7' services: ubuntu: # аналог docker run --name container_name: pytest_ubuntu image: pytest_ubuntu build: context: ./dockerfiles dockerfile: Dockerfile.ubuntu args: buildversion: 1 ports: - "3000:3000" volumes: - ./src:/opt tty: true command: tail -F /dev/null flaskservice: build: flask-service ports: - "5000:5000"
flask-service Dockerfile
# set base image (host OS) FROM python # set the working directory in the container WORKDIR /code # copy the dependencies file to the working directory COPY requirements.txt . # install dependencies RUN pip install -r requirements.txt # copy the content of the local src directory to the working directory COPY src/ . # command to run on container start CMD [ "python", "./app.py" ]
docker-compose build docker-compose up -d docker exec -it 7e3d2711b4ab bash python -m pytest -v tests/pytest/src/tests/app
# docker-compose.yml version: '3.8' services: pytest_ubuntu: container_name: pytest_ubuntu image: pytest_ubuntu # priveleged: true # user: root build: context: ./dockerfiles dockerfile: Dockerfile.ubuntu.pytest args: buildversion: 1 ports: - "3000:3000" networks: net1: ipv4_address: 10.5.0.2 extra_hosts: - flask.andrei.com:10.5.0.3 - jenkins.andrei.com:10.7.0.6 volumes: - ./src:/opt tty: true command: tail -F /dev/null flask_service: build: flask_service ports: - "5000:5000" networks: net1: ipv4_address: 10.5.0.3 extra_hosts: - jenkins.andrei.com:10.7.0.6 web: build: nginx ports: - "80:80" networks: net1: ipv4_address: 10.5.0.4 extra_hosts: - flask.andrei.com:10.5.0.3 - jenkins.andrei.com:10.7.0.6 robot_ubuntu: container_name: robot_ubuntu image: robot_ubuntu build: context: ./dockerfiles dockerfile: Dockerfile.ubuntu.robotfw args: buildversion: 1 ports: - "3001:3001" networks: net1: ipv4_address: 10.5.0.5 extra_hosts: - flask.andrei.com:10.5.0.3 - jenkins.andrei.com:10.7.0.6 volumes: - ./src:/opt tty: true command: tail -F /dev/null jenkins: # image specified in Dockerfile # image: jenkins/jenkins:lts restart: always privileged: true user: root build: context: ./dockerfiles dockerfile: Dockerfile.jenkins args: buildversion: 1 ports: - "8080:8080" - "50000:50000" container_name: jenkins networks: net1: ipv4_address: 10.5.0.6 jenkins: ipv4_address: 10.7.0.6 extra_hosts: - flask.andrei.com:10.5.0.3 volumes: - /var/run/docker.sock:/var/run/docker.sock - ./jenkins:/home networks: net1: driver: bridge ipam: config: - subnet: 10.5.0.0/16 gateway: 10.5.0.1 jenkins: driver: bridge ipam: config: - subnet: 10.7.0.0/16 gateway: 10.7.0.1
РЕКЛАМА от Google. Может быть недоступна в вашем регионе.
Конец рекламы от Google. Если в блоке пусто считайте это рекламой моей телеги