Глава 8

Настройка Docker Compose

Книга
Docker: Up & Running

Shipping Reliable Containers in Production (O'Reilly Media)

Практическое руководство по созданию, запуску и масштабированию надежных контейнеров в продакшене. Книга охватывает весь спектр работы с Docker — от базовых команд до оркестрации, сетевых настроек и безопасности.

Программа вечера

Настройка Docker Compose
Запуск сервисов
Принципы работы Rocket.Chat
Применение Docker Compose
Управление конфигурацией

Что такое
Docker Compose

Инструмент оркестрации для определения и запуска многоконтейнерных Docker-приложений.

docker-compose.yaml
Dockerfile
(Mongo)
Dockerfile
(RocketChat)
Dockerfile
(Hubot)

История версий

v1
Эпоха Python
Изначально Docker Compose был отдельным приложением на Python.
docker-compose
v2
Переход на Go
Полностью переписан на Go. Поставляется как плагин для клиента Docker.
docker compose
Проверка установки
Убедитесь, что команда возвращает результат. Если нет — установите.
docker compose version
setup-env.sh
#!/bin/bash
# Не запускайте этот скрипт.
exit 1
# Сам скрипт #
# Примечание. Скрипт не обновляется в соответствии с файлом docker-compose
# и приводится только для информации.
set -e
set -u
if [ ${1:-""} = "down" ] ; then
  docker rm -f hubot || true
  docker rm -f zmachine || true
  docker rm -f rocketchat || true
  docker rm -f mongo-init-replica || true
  docker rm -f mongo || true
  docker network rm botnet || true
  echo "Environment torn down ... "
  exit 0
fi
# Глобальные настройки
export PORT="3000"
export ROOT_URL="http://127.0.0.1:3000"
export MONGO_URL="mongodb://mongo:27017/rocketchat"
export MONGO_OPLOG_URL="mongodb://mongo:27017/local"
export MAIL_URL="smtp://smtp.email"
export RESPOND_TO_DM="true"
export HUBOT_ALIAS="."
export LISTEN_ON_ALL_PUBLIC="true"
export ROCKETCHAT_AUTH="password"
export ROCKETCHAT_URL="rocketchat:3000"
export ROCKETCHAT_ROOM=""
export ROCKETCHAT_USER="hubot"
export ROCKETCHAT_PASSWORD="bot-pw1"
export BOT_NAME="bot"
export EXTERNAL_SCRIPTS="hubot-help,hubot-diagnostics,hubot-zmachine"
export HUBOT_ZMACHINE_SERVER="http://zmachine:80"
export HUBOT_ZMACHINE_ROOMS="zmachine"
export HUBOT_ZMACHINE_OUT_PREFIX="ot"
docker build -t spkane/mongo:4.4 ./mongodb/docker
docker push spkane/mongo:4.4
docker pull spkane/zmachine-api:latest
docker pull rocketchat/rocket.chat:5.0.4
docker pull rocketchat/hubot-rocketchat:latest
docker rm -f hubot || true
  docker rm -f zmachine || true
  docker rm -f rocketchat || true
  docker rm -f mongo-init-replica || true
  docker rm -f mongo || true
  docker network rm botnet || true
docker network create -d bridge botnet
docker container run -d \
  --name=mongo \
  --network=botnet \
  --restart unless-stopped \
  -v $(pwd)/mongodb/data/db:/data/db \
  spkane/mongo:4.4 \
  mongod --oplogSize 128 --replSet rs0
sleep 5
docker container run -d \
  --name=mongo-init-replica \
  --network=botnet \
  spkane/mongo:4.4 \
  mongo mongo/rocketchat --eval "rs.initiate({ _id: 'rs0', members: [ { _id: 0, host: 'mongo:27017' } ] })"
sleep 5
docker container run -d \
  --name=rocketchat \
  --network=botnet \
  --restart unless-stopped \
  -v $(pwd)/rocketchat/data/uploads:/app/uploads \
  -p 3000:3000 \
  -e PORT=${PORT} \
  -e ROOT_URL=${ROOT_URL} \
  -e MONGO_URL=${MONGO_URL} \
  -e MONGO_OPLOG_URL=${MONGO_OPLOG_URL} \
  -e MAIL_URL=${MAIL_URL} \
  rocketchat/rocket.chat:5.0.4
docker container run -d \
  --name=zmachine \
  --network=botnet \
  --restart unless-stopped \
  -v $(pwd)/zmachine/saves:/root/saves \
  -v $(pwd)/zmachine/zcode:/root/zcode \
  -p 3002:80 \
  spkane/zmachine-api:latest
docker container run -d \
  --name=hubot \
  --network=botnet \
  --restart unless-stopped \
  -v $(pwd)/hubot/scripts:/home/hubot/scripts \
  -p 3001:8080 \
  -e RESPOND_TO_DM="true" \
  -e HUBOT_ALIAS="." \
  -e LISTEN_ON_ALL_PUBLIC="true" \
  -e ROCKETCHAT_AUTH="password" \
  -e ROCKETCHAT_URL="rocketchat:3000" \
  -e ROCKETCHAT_ROOM="" \
  -e ROCKETCHAT_USER="hubot" \
  -e ROCKETCHAT_PASSWORD="bot-pw!" \
  -e BOT_NAME="bot" \
  -e EXTERNAL_SCRIPTS="hubot-help,hubot-diagnostics,hubot-zmachine" \
  -e HUBOT_ZMACHINE_SERVER="http://zmachine:80" \
  -e HUBOT_ZMACHINE_ROOMS="zmachine" \
  -e HUBOT_ZMACHINE_OUT_PREFIX="ot" \
  rocketchat/hubot-rocketchat:latest
echo "Environment setup ... "
exit 0
Нажмите на любой блок кода для разбора

Императивный подходСпособ описания системы, при котором вы пошагово перечисляете конкретные команды и действия для достижения результата («Как это сделать»). В отличие от декларативного подхода, где вы просто описываете желаемый конечный результат. — ручное управление каждым шагом настройки, создания сетей и запуска контейнеров через shell-скрипты.

Сложно читать

Разработчики тратят часы на разбор сотен строк bash-кода.

Хрупко

Любая ошибка в порядке запуска ломает всё окружение.

Неудобно

Сотни флагов и переменных передаются вручную в CLI.

Alchemist
docker-compose.yaml
version: '3'
services:
  mongo:
    build:
      context: ../mongodb/docker
    image: spkane/mongo:4.4
    restart: unless-stopped
    environment:
      MONGODB_REPLICA_SET_MODE: primary
      MONGODB_REPLICA_SET_NAME: rs0
      MONGODB_PORT_NUMBER: 27017
      MONGODB_INITIAL_PRIMARY_HOST: mongodb
      MONGODB_INITIAL_PRIMARY_PORT_NUMBER: 27017
      MONGODB_ADVERTISED_HOSTNAME: mongo
      MONGODB_ENABLE_JOURNAL: "true"
      ALLOW_EMPTY_PASSWORD: "yes"
    # Порт 27017 уже открыт в базовом файле
    # См. более новый базовый Dockerfile:
    # https://github.com/bitnami/containers/blob/f9fb3f8a6323/bitnami/mongodb/Dockerfile#L52
    networks:
      - botnet
  rocketchat:
    image: rocketchat/rocket.chat:5.0.4
    restart: unless-stopped
    labels:
      traefik.enable: "true"
      traefik.http.routers.rocketchat.rule: "Host('127.0.0.1')"
      traefik.http.routers.rocketchat.tls: "false"
      traefik.http.routers.rocketchat.entrypoints: http
    volumes:
      - "../rocketchat/data/uploads:/app/uploads"
    environment:
      ROOT_URL: http://127.0.0.1:3000
      PORT: 3000
      MONGO_URL: "mongodb://mongo:27017/rocketchat?replicaSet=rs0"
      MONGO_OPLOG_URL: "mongodb://mongo:27017/local?replicaSet=rs0"
      DEPLOY_METHOD: docker
    depends_on:
      mongo:
        condition: service_healthy
    ports:
      - 3000:3000
    networks:
      - botnet
  zmachine:
    image: spkane/zmachine-api:latest
    restart: unless-stopped
    volumes:
      - "../zmachine/saves:/root/saves"
      - "../zmachine/zcode:/root/zcode"
    depends_on:
      - rocketchat
    expose:
      - "80"
    networks:
      - botnet
  hubot:
    image: rocketchat/hubot-rocketchat:latest
    restart: unless-stopped
    volumes:
      - "../hubot/scripts:/home/hubot/scripts"
    environment:
      RESPOND_TO_DM: "true"
      HUBOT_ALIAS: "."
      LISTEN_ON_ALL_PUBLIC: "true"
      ROCKETCHAT_AUTH: "password"
      ROCKETCHAT_URL: "rocketchat:3000"
      ROCKETCHAT_ROOM: ""
      ROCKETCHAT_USER: "hubot"
      ROCKETCHAT_PASSWORD: "bot-pw!"
      BOT_NAME: "bot"
      EXTERNAL_SCRIPTS: "hubot-help,hubot-diagnostics,hubot-zmachine"
      HUBOT_ZMACHINE_SERVER: "http://zmachine:80"
      HUBOT_ZMACHINE_ROOMS: "zmachine"
      HUBOT_ZMACHINE_OUT_PREFIX: "ot"
    depends_on:
      - zmachine
    ports:
      - 3001:8080
    networks:
      - botnet
networks:
  botnet:
    driver: bridge
Нажмите на любой блок кода для разбора
Frontend
frontend/Dockerfile
Backend
backend/Dockerfile
Database
postgres:15-alpine
Orchestrator
docker-compose.yaml
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]
frontend:
  build: ./frontend
  ports:
    - "3000:3000"
FROM golang:1.21-alpine
WORKDIR /app
COPY . .
RUN go build -o server
EXPOSE 8080
CMD ["./server"]
backend:
  build: ./backend
  ports:
    - "8080:8080"
  depends_on:
    - db
FROM postgres:15-alpine
ENV POSTGRES_DB=mydb
COPY init.sql /docker-entrypoint-initdb.d/
db:
  image: postgres:15-alpine
  environment:
    POSTGRES_PASSWORD: example
  volumes:
    - pgdata:/var/lib/postgresql/data
docker-compose.yaml
version: '3.8'
services:
  frontend:
    build: ./frontend
    ports: ["3000:3000"]
  backend:
    build: ./backend
    depends_on: [db]
  db:
    image: postgres:15-alpine

Сборка и запуск

Docker Compose берет под контроль конфигурации всех сервисов, автоматически собирая локальные Dockerfile и настраивая связи.

$docker compose build
Сборка образов
Инициирует сборку всех локальных образов, описанных через директиву build (в нашем случае Frontend и Backend).
$docker compose up -d
Запуск системы
Создает сети, тома, запускает все контейнеры в правильном порядке и переводит их в фоновый режим.

Преимущества подхода

Декларативное описание

Вся инфраструктура описана в одном файле. Никаких императивных шагов и bash-скриптов.

Автоматическое управление связями

Сети, тома и линки настраиваются силами Compose. Больше не нужно следить за ними вручную.

Безопасная оркестрация

Запуск контейнеров в строгом соответствии с зависимостями и проверками работоспособности (healthchecks).

Что далее

Настройка Docker Compose Пройдено
Запуск сервисов
Принципы работы Rocket.Chat
Применение Docker Compose
Управление конфигурацией