Перейти к основному контенту

Глава 2.1: Анатомия docker-compose.yml и магия .env.

В предыдущем разделе мы запускали тестовый контейнер командой docker run. Это удобно для быстрых тестов, но если у вас десяток сервисов, у каждого из которых свои порты, папки данных и пароли, то запускать их вручную командами из консоли станет невозможно.

Для этого существует Docker Compose. Это инструмент, который позволяет описать всю вашу ИТ-инфраструктуру (все сервисы, сети и диски) в одном простом текстовом файле формата YAML — docker-compose.yml. Вы один раз прописываете правила игры, а затем запускаете всю экосистему одной короткой командой.


1. Магия .env файлов (Безопасность)

Главная ошибка при составлении конфигов — писать секретные пароли, ключи и домены прямо внутри кода docker-compose.yml. Если вы захотите поделиться своим конфигом с другом или выложить его на GitHub, вам придется вручную вырезать оттуда личные данные.

Правильный подход: Разделять структуру и данные. Всю структуру мы пишем в docker-compose.yml, а все переменные (пароли, пути, часовой пояс) выносим в отдельный скрытый файл .env, который лежит в той же папке.

Давайте подготовим рабочее пространство для нашей Wiki. Создадим нужную папку внутри нашего каталога стеков и перейдем в нее:

mkdir -p /stacks/bookstack

cd /stacks/bookstack

Теперь создадим скрытый файл конфигурации .env с помощью редактора nano:

nano .env

Вставьте в него следующие строки (придумайте свои надежные пароли вместо дефолтных!):

# Настройки приложения BookStack

APP_URL=http://wiki.myserver.ru

TZ=Europe/Moscow




# Секреты для базы данных

DB_ROOT_PASSWORD=super_secret_root_pass_123

DB_USER=bookstack_user

DB_PASSWORD=secure_db_password_456

Сохраните файл (нажмите Ctrl+O, затем Enter) и выйдете (Ctrl+X).


2. Создание и анатомия docker-compose.yml

Теперь создадим рядом основной манифест:

nano docker-compose.yml

Вставьте туда следующий готовый код. Обратите внимание, как вместо реальных паролей мы используем конструкции вида ${DB_PASSWORD} — Docker автоматически подставит туда значения из созданного нами файла .env.

services:

  # Сервис №1: База данных MariaDB

  bookstack-db:

    image: lscr.io/linuxserver/mariadb:latest

    container_name: bookstack_db

    environment:

      - PUID=1000

      - PGID=1000

      - TZ=${TZ}

      - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}

      - MYSQL_DATABASE=bookstackapp

      - MYSQL_USER=${DB_USER}

      - MYSQL_PASSWORD=${DB_PASSWORD}

    volumes:

      - ./db_data:/config

    restart: unless-stopped




  # Сервис №2: Само веб-приложение BookStack

  bookstack:

    image: lscr.io/linuxserver/bookstack:latest

    container_name: bookstack_app

    environment:

      - PUID=1000

      - PGID=1000

      - TZ=${TZ}

      - APP_URL=${APP_URL}

      - DB_HOST=bookstack-db

      - DB_USER=${DB_USER}

      - DB_PASSWORD=${DB_PASSWORD}

      - DB_DATABASE=bookstackapp

    volumes:

      - ./app_data:/config

    ports:

      - "8080:80"

    restart: unless-stopped

    depends_on:

      - bookstack-db

3. Разбор конфигурации «по косточкам»

Давайте поймем, что делает ключевой блок каждой директивы, чтобы вы могли легко читать любые чужие конфиги из интернета:

  • services: С этого слова начинается описание всех контейнеров, которые входят в наш стек. В нашем случае это два независимых сервиса: bookstack-db (база) и bookstack (веб-интерфейс).
  • image: Из какого чертежа (образа) разворачивать контейнер. Мы используем великолепные, чистые и регулярно обновляемые образы от сообщества LinuxServer.io.
  • container_name: Какое имя дать запущенному контейнеру в системе, чтобы его было удобно администрировать. Если его не указать, Docker сам сгенерирует имя вида bookstack-bookstack-1.
  • environment: Переменные окружения. Это "ручки настройки" внутри контейнера. Сюда мы передаем часовой пояс, секреты бд, а также параметры PUID и PGID (о них мы детально поговорим в следующей главе).
  • volumes: Связка папок (монтирование). Директива вида ./app_data:/config означает: "Возьми локальную папку app_data прямо здесь, на сервере, и свяжи её с внутренней папкой /config в контейнере". Всё, что контейнер запишет туда, сохранится на нашем жестком диске.
  • ports: Проброс портов. Запись "8080:80" расшифровывается как ВНЕШНИЙ_ПОРТ:ВНУТРЕННИЙ_ПОРТ. Внутри контейнера приложение работает на стандартном 80 порту, а мы "вытаскиваем" его наружу на порт 8080 нашего сервера Debian, чтобы оно не конфликтовало с другими будущими сайтами.
  • restart: unless-stopped: Политика перезапуска. Говорит Docker'у: "Если сервер перезагрузится, или контейнер упадет из-за ошибки — немедленно подними его автоматически. Не трогай его только в том случае, если я сам вручную его остановил".
  • depends_on: Очередь запуска. Логично, что сайт BookStack не сможет работать без базы данных. Эта строка указывает Docker'у сначала полностью запустить контейнер с СУБД, и только после этого стартовать само приложение.

⚠️ Важнейшее правило синтаксиса YAML:
Файлы конфигурации Compose невероятно чувствительны к пробелам и отступам. В них нельзя использовать клавишу Tab — только обычные пробелы. Каждый уровень вложенности сдвигается строго на 2 или 4 пробела относительно родительского. Ошибка в один лишний пробел приведет к тому, что Docker откажется запускать конфиг.


Запуск стека

Убедитесь, что вы находитесь в папке /stacks/bookstack и выполните магическую команду запуска:

docker compose up -d

Флаг -d (detached) означает запустить контейнеры в фоновом режиме, чтобы они не блокировали консоль. Docker сам скачает образы из сети, настроит связи и запустит сервисы.

После завершения процесса вы можете открыть браузер на основном компьютере и ввести IP-адрес вашего сервера с указанием нашего порта: http://ip_сервера:8080. Вы увидите стартовое окно вашей новой корпоративной Wiki!

📌 Что дальше? Контейнеры запущены и работают, но прямо сейчас в папке проекта автоматически создались новые директории app_data и db_data. Кто их владелец? Что с правами? П ереходим к Главе 2.2, чтобы разобраться с правами пользователей и не сломать систему.