Запуск Docker Compose как службы Linux с помощью systemd
Запуск Docker Compose при загрузке, управляемый через systemd.
Docker Compose на Linux-сервере должен запускаться при загрузке, корректно останавливаться при выключении и переживать перезагрузки без ручного вмешательства.
Docker Compose — это не Kubernetes, и для рабочих нагрузок, на которые ориентировано данное руководство, это вполне подходит. Для многих реальных систем проект Compose на одном Linux-хосте является оптимальным количеством инфраструктуры: он прост, понятен, легко резервируется и вполне достаточен для внутренних инструментов, побочных проектов, self-hosted сервисов, staging-сред, небольших продакшен-приложений и инфраструктуры разработчиков.

Обычно не хватает механизма управления сервисами. Ручного запуска недостаточно:
docker compose up -d
Одна команда запускает стек, но она не документирует, как стек должен запускаться при загрузке, останавливаться при выключении, перезагружаться после изменений, вести логи, восстанавливаться после сбоев или безопасно обновляться. Здесь на помощь приходит systemd.
В этом руководстве рассматривается запуск проекта Docker Compose в качестве Linux-сервиса с помощью systemd — юнит-файлы, порядок загрузки, обновления, логи и резервное копирование. Разделение ответственности намеренное: Docker запускает контейнеры, Compose определяет стек, а systemd запускает и останавливает проект на хосте. Это часть раздела Инструменты разработчика — руководство по рабочим процессам.
Когда имеет смысл запускать Docker Compose как сервис
Запуск Compose под systemd имеет смысл, когда у вас есть:
- Единый Linux-сервер
- Небольшое self-hosted приложение
- Стек обратного прокси
- Стек мониторинга
- Локальная платформа разработки
- Внутренний инструмент
- Staging-окружение
- Простой продакшен-сервис с известными ограничениями
Примеры:
- Nginx Proxy Manager
- Traefik
- Gitea
- Grafana и Prometheus
- PostgreSQL плюс небольшое веб-приложение
- Uptime Kuma
- Вспомогательные сервисы Home Assistant
- Приватный реестр
- Внутренний API плюс воркер плюс Redis
Compose хорошо подходит, когда операционная модель остается понятной одному человеку, просматривающему одну директорию.
Когда Docker Compose недостаточно
Используйте что-то другое, если вам нужно:
- Планирование на нескольких узлах
- Автоматическое перепланирование между хостами
- Сервисная discovery на уровне кластера
- Горизонтальное автомасштабирование
- Последовательные развертывания на многих машинах
- Тонкозернистая идентификация рабочих нагрузок
- Сложная сетевая политика
- Крупные платформенные операции для нескольких команд
На этом этапе Kubernetes, Nomad, Swarm или управляемая платформа могут подходить лучше.
Мое практическое правило: избегать использования Kubernetes просто чтобы не изучать systemd, и избегать использования Compose, когда рабочая нагрузка явно требует оркестрации на нескольких хостах.
Базовая архитектура
Чистая настройка разделяет файлы проекта, systemd-юнит и постоянные данные на хосте. Проект Compose находится в /opt/myapp/ с файлами compose.yaml, .env, data/, backups/ и опциональными скриптами, такими как scripts/update.sh. Файл юнита systemd находится в /etc/systemd/system/myapp.service.
У каждого слоя есть четкая задача: Docker запускает контейнеры, Compose определяет стек приложения, systemd запускает и останавливает проект Compose при загрузке и выключении, файловая система хоста хранит постоянные данные, резервные копии остаются явными, а обновления проходят через скриптованные, проверяемые шаги. Эта структура намеренно скучна, потому что скучная инфраструктура легче в ремонте, когда что-то ломается в 2 часа ночи.
Подготовка директории проекта Compose
Создайте директорию в /opt:
sudo mkdir -p /opt/myapp
sudo chown -R "$USER":"$USER" /opt/myapp
cd /opt/myapp
Создайте файл Compose:
nano compose.yaml
Пример:
services:
web:
image: nginx:stable
restart: unless-stopped
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html:ro
healthcheck:
test: ["CMD-SHELL", "nginx -t || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
volumes: {}
Создайте директорию контента:
mkdir -p html
echo "Hello from Docker Compose" > html/index.html
Сначала протестируйте вручную:
docker compose up -d
docker compose ps
docker compose logs --tail=50
Затем остановите его перед передачей управления жизненным циклом systemd:
docker compose down
Не создавайте сервис systemd, пока проект Compose не заработает вручную. Во время тестов держите под рукой Шпаргалку по Docker Compose для ps, logs, pull и структуры проекта.
Используйте современную команду docker compose
Docker Engine и плагин Compose должны быть установлены перед написанием файла юнита. На Ubuntu руководство Установка Docker на Ubuntu описывает APT, Snap, режим без прав root и безопасность после установки, чтобы у вас получилась рабочая команда docker compose.
Используйте это:
docker compose version
А не это:
docker-compose version
Старый бинарный файл docker-compose все еще существует на многих машинах, но современный Docker использует Compose как плагин CLI Docker.
В файлах сервисов и скриптах предпочитайте:
/usr/bin/docker compose
Путь к Docker можно найти с помощью:
command -v docker
Обычно это:
/usr/bin/docker
Создание systemd-сервиса для Docker Compose
Если файлы юнитов вам новы, руководство Запуск любого исполняемого файла как сервиса в Linux объясняет Type, ExecStart, systemctl и общий рабочий процесс systemd. Этот раздел применяет эти паттерны специально к стеку Compose.
Создайте файл сервиса:
sudo nano /etc/systemd/system/myapp.service
Используйте этот юнит:
[Unit]
Description=MyApp Docker Compose stack
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
TimeoutStopSec=120
[Install]
WantedBy=multi-user.target
Перезагрузите systemd:
sudo systemctl daemon-reload
Запустите сервис:
sudo systemctl start myapp.service
Включите его при загрузке:
sudo systemctl enable myapp.service
Проверьте статус:
systemctl status myapp.service
Проверьте контейнеры:
cd /opt/myapp
docker compose ps
Почему Type=oneshot и RemainAfterExit=yes?
Это та часть, которую многие руководства понимают неверно.
docker compose up -d запускает контейнеры в отсоединенном режиме и завершается, поэтому нет долгоживущего фонового процесса Compose, за которым systemd мог бы наблюдать. Юнит systemd не должен притворяться, что docker compose up -d — это долгоживущий демон.
Используйте:
Type=oneshot
RemainAfterExit=yes
Это говорит systemd:
- Выполнить команду старта.
- Считать юнит активным после успешного завершения команды.
- Выполнить
ExecStopпри остановке сервиса.
Это соответствует фактическому поведению отсоединенного Compose, поэтому Type=oneshot с RemainAfterExit=yes является правильным значением по умолчанию для большинства стеков.
Почему не Type=simple?
С Type=simple systemd ожидает, что процесс ExecStart будет продолжать работу, но docker compose up -d завершается после запуска контейнеров. Это может заставить systemd думать, что сервис завершился, затем вызвать логику остановки или пометить юнит неактивным в зависимости от конфигурации.
Если вы хотите Type=simple, вы обычно запускали бы Compose в переднем плане:
ExecStart=/usr/bin/docker compose up
Это может работать, но я обычно не предпочитаю это для стеков Compose на серверах. Отсоединенные контейнеры плюс явный ExecStop проще в эксплуатации.
Более продакшен-ориентированный юнит
Для реального сервера я предпочитаю немного более строгий юнит:
[Unit]
Description=MyApp Docker Compose stack
Documentation=https://example.com/docs/myapp
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/myapp
EnvironmentFile=-/opt/myapp/.env.systemd
ExecStartPre=/usr/bin/docker compose config --quiet
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecReload=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
TimeoutStopSec=120
[Install]
WantedBy=multi-user.target
Важные детали:
WorkingDirectoryуказывает на проект Compose.ExecStartPreвалидирует конфигурацию Compose.ExecReloadпересоздает измененные сервисы.ExecStopостанавливает и удаляет контейнеры проекта Compose и сетью по умолчанию.EnvironmentFile=-...означает, что файл опционален.
Создайте опциональный файл окружения systemd:
nano /opt/myapp/.env.systemd
Пример:
COMPOSE_PROJECT_NAME=myapp
Затем перезагрузите systemd:
sudo systemctl daemon-reload
sudo systemctl restart myapp.service
Compose .env против systemd EnvironmentFile
Compose и systemd имеют собственные механизмы окружения, и их смешивание вызывает запутанные ошибки “переменная не установлена” при загрузке.
Compose автоматически читает файл .env в директории проекта для подстановки переменных в файле Compose.
Пример .env:
APP_TAG=1.2.3
WEB_PORT=8080
Пример compose.yaml:
services:
web:
image: nginx:${APP_TAG}
ports:
- "${WEB_PORT}:80"
EnvironmentFile в systemd устанавливает переменные окружения для самой команды docker compose.
Пример:
EnvironmentFile=-/opt/myapp/.env.systemd
Для многих проектов вам нужен только .env Compose.
Используйте файл окружения systemd, когда вы хотите определить такие вещи, как:
COMPOSE_PROJECT_NAME=myapp
COMPOSE_FILE=compose.yaml
DOCKER_HOST=unix:///var/run/docker.sock
Не используйте ни один из файлов как хранилище секретов. Если секреты важны, используйте Docker secrets, внешний менеджер секретов, зашифрованные файлы или хотя бы строгие права доступа.
Установите строгие права доступа:
chmod 600 /opt/myapp/.env
chmod 600 /opt/myapp/.env.systemd
Политики перезапуска: Docker против systemd
Есть два уровня перезапуска — политика перезапуска контейнеров в Compose и политика перезапуска сервиса в systemd — и их не следует слепо смешивать.
Для долгоживущих контейнеров устанавливайте политики перезапуска в Compose:
services:
web:
image: nginx:stable
restart: unless-stopped
Распространенные значения перезапуска:
| Политика | Значение |
|---|---|
| no | Не перезапускать автоматически |
| always | Перезапускать после выхода и перезапуска демона |
| on-failure | Перезапускать только после сбоя |
| unless-stopped | Перезапускать, если не остановлено вручную |
Для большинства постоянных сервисов я предпочитаю:
restart: unless-stopped
Это предсказуемо и уважает намеренные ручные остановки.
Сам юнит systemd обычно не должен перезапускаться многократно, потому что docker compose up -d — это не рабочая нагрузка. Контейнеры — это рабочая нагрузка.
Поэтому избегайте этого, если у вас нет конкретной причины:
Restart=always
В большинстве юнитов Compose-as-service позвольте Docker обрабатывать перезапуски контейнеров.
Health Checks
Политики перезапуска перезапускают контейнеры, когда процессы завершаются. Они не волшебным образом исправляют каждый нездоровый экземпляр приложения.
Добавляйте health checks там, где они полезны:
services:
app:
image: example/app:latest
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8080/health || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
Проверьте здоровье:
docker compose ps
Осмотрите контейнер:
docker inspect container-name
Health checks особенно полезны для:
- Веб-приложений
- Обратных прокси
- Баз данных
- Очерей
- Внутренних API
- Воркеров с эндпоинтом здоровья
Они менее полезны, когда они проверяют только наличие процесса, потому что процесс, который жив, но завис, все еще выглядит здоровым. Плохой health check — это просто еще одна ложь в YAML.
Порядок запуска и depends_on
Compose может определять зависимости:
services:
app:
image: example/app:latest
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
Это может помочь с порядком запуска, но не доверяйте ему слепо. Приложения все еще должны обрабатывать повторные попытки — базы данных перезапускаются, сети могут глючить, DNS требует времени, и устойчивое приложение повторяет попытки соединения вместо того, чтобы предполагать идеальный порядок запуска.
Логи: journalctl и docker compose logs
Два вида логов покрывают большинство задач отладки: systemd захватывает жизненный цикл самого юнита, в то время как Compose захватывает вывод приложения из работающих контейнеров.
Логи сервиса systemd:
journalctl -u myapp.service -n 100 --no-pager
Следить за логами systemd:
journalctl -u myapp.service -f
Логи сервиса Compose:
cd /opt/myapp
docker compose logs --tail=100
docker compose logs -f
docker compose logs -f web
Для большинства задач отладки приложений docker compose logs более полезен; для отладки жизненного цикла — сбоев запуска, крашей юнита, ошибок прав доступа — journalctl более полезен. Если systemctl start myapp не удалось, сначала проверьте journalctl. Если стек запустился, но приложение сломано, проверьте docker compose logs.
Ротация логов
Логи Docker могут расти бесконечно, если вы не настроите их.
Для небольших серверов настройте ротацию логов Docker в /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "5"
}
}
Перезапустите Docker:
sudo systemctl restart docker
Затем перезапустите стек Compose:
sudo systemctl restart myapp.service
Это применяется к вновь созданным контейнерам. Пересоздайте контейнеры при необходимости:
cd /opt/myapp
docker compose up -d --force-recreate
Ротация логов не гламурна, но это один из самых простых способов предотвратить outage из-за полного диска на небольшом сервере.
Обновление сервиса Compose
Простой ручной поток обновлений:
cd /opt/myapp
docker compose pull
docker compose up -d --remove-orphans
docker image prune -f
Если управляется systemd, вы можете использовать:
sudo systemctl reload myapp.service
Если ваш юнит имеет:
ExecReload=/usr/bin/docker compose up -d --remove-orphans
Но обратите внимание: ExecReload не тянет образы, если вы не включили этот шаг.
Для явных обновлений создайте скрипт.
mkdir -p /opt/myapp/scripts
nano /opt/myapp/scripts/update.sh
Скрипт:
#!/usr/bin/env bash
set -euo pipefail
cd /opt/myapp
docker compose config --quiet
docker compose pull
docker compose up -d --remove-orphans
docker image prune -f
docker compose ps
Сделайте его исполняемым:
chmod +x /opt/myapp/scripts/update.sh
Запустите его:
/opt/myapp/scripts/update.sh
Затем юнит сервиса может оставаться сфокусированным на жизненном цикле, в то время как скрипт обновления обрабатывает развертывание.
Более безопасный скрипт обновления с хуком резервного копирования
Для сервисов с состоянием обновляйте только после резервного копирования.
#!/usr/bin/env bash
set -euo pipefail
APP_DIR="/opt/myapp"
BACKUP_DIR="/opt/myapp/backups"
cd "$APP_DIR"
mkdir -p "$BACKUP_DIR"
echo "Validating compose file"
docker compose config --quiet
echo "Running backup hook"
if [ -x "$APP_DIR/scripts/backup.sh" ]; then
"$APP_DIR/scripts/backup.sh"
else
echo "No backup hook found"
fi
echo "Pulling images"
docker compose pull
echo "Recreating services"
docker compose up -d --remove-orphans
echo "Pruning unused images"
docker image prune -f
echo "Current status"
docker compose ps
Это все еще просто, но теперь это кодирует операционную привычку: резервное копирование перед изменением.
Остановка сервиса
Остановите стек:
sudo systemctl stop myapp.service
Это запускает:
docker compose down
По умолчанию docker compose down удаляет:
- Контейнеры для сервисов в файле Compose
- Сети, определенные в файле Compose
- Сеть по умолчанию
Она не удаляет именованные тома, если вы не попросите об этом.
Не используйте небрежно:
docker compose down -v
Это удаляет именованные тома, объявленные в файле Compose, и анонимные тома, прикрепленные к контейнерам. Для баз данных и сервисов с состоянием это может означать удаление реальных данных.
Используйте down -v только когда вы имеете в виду “разрушить это окружение”.
Перезапуск сервиса
Перезапустите юнит systemd:
sudo systemctl restart myapp.service
Это запускает команду остановки, а затем команду запуска.
Для перезапуска только контейнеров без их пересоздания:
cd /opt/myapp
docker compose restart
Важное различие:
docker compose restartперезапускает существующие контейнеры.docker compose up -dприменяет изменения конфигурации или образов, пересоздавая контейнеры при необходимости.
Если вы изменили compose.yaml, используйте:
docker compose up -d
А не просто:
docker compose restart
Обработка сиротских контейнеров
Если вы переименовали или удалили сервис в compose.yaml, старые контейнеры могут остаться как сироты.
Используйте:
docker compose up -d --remove-orphans
Поэтому в примерах systemd-сервисов в этом руководстве используется:
ExecStart=/usr/bin/docker compose up -d --remove-orphans
Это держит стек ближе к текущему файлу Compose.
Резервное копирование
Резервное копирование зависит от рабочей нагрузки, но принципы стабильны.
Для bind mounts:
/opt/myapp/data/
Резервируйте эту директорию.
Для именованных томов:
docker volume ls
Осмотрите том:
docker volume inspect volume-name
Для баз данных копий файловой системы не всегда достаточно. Используйте резервное копирование, осознающее приложение:
Пример PostgreSQL:
docker compose exec -T db pg_dump -U postgres appdb > backups/appdb.sql
Пример MariaDB:
docker compose exec -T db mariadb-dump -u root -p appdb > backups/appdb.sql
Пример Redis:
docker compose exec redis redis-cli BGSAVE
Стек Compose без плана резервного копирования — это не сервис, а временный эксперимент, который случайно имеет uptime.
Базовая безопасность
Для небольшого сервиса Compose на Linux начните с этой базы:
- Держите проект Compose под
/opt/appname. - Используйте явные теги образов, а не только
latest, когда важна стабильность. - Используйте bind mounts или именованные тома осознанно.
- Не экспортируйте порты, которые вам не нужны.
- Поместите публичные сервисы за обратный прокси.
- Используйте HTTPS на границе.
- Держите секреты вне Git.
- Ограничьте права доступа к
.env. - Избегайте привилегированных контейнеров, если они не требуются по-настоящему.
- Избегайте монтирования сокета Docker в контейнеры.
- Держите Docker и образы обновленными.
- Тестируйте поведение файрвола с другой машины.
Опасный паттерн:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
Это дает контейнеру контроль над Docker. На практике это может стать контролем на уровне хоста. Используйте это только когда вы понимаете риск.
Ограничения ресурсов
На небольших серверах один плохой контейнер может потребить хост.
Compose поддерживает настройки, связанные с ресурсами, но поведение может зависеть от версии Docker Engine и Compose. Для простой защиты начните с ограничений на уровне приложения и ограничений логов Docker.
Для некоторых рабочих нагрузок вы можете добавить ограничения памяти:
services:
app:
image: example/app:stable
restart: unless-stopped
mem_limit: 512m
Также настройте количество воркеров на уровне приложения, лимиты очередей и размеры кэша. Ограничения контейнеров полезны, но они не заменяют понимание приложения.
Пример: Реалистичный сервис Compose
Директория:
/opt/whoami/
compose.yaml
.env
Файл Compose:
services:
whoami:
image: traefik/whoami:v1.10
restart: unless-stopped
ports:
- "${WHOAMI_PORT}:80"
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost || exit 1"]
interval: 30s
timeout: 5s
retries: 3
Файл .env:
WHOAMI_PORT=8080
COMPOSE_PROJECT_NAME=whoami
Юнит systemd:
[Unit]
Description=Whoami Docker Compose stack
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/whoami
ExecStartPre=/usr/bin/docker compose config --quiet
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecReload=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
TimeoutStopSec=120
[Install]
WantedBy=multi-user.target
Установите его:
sudo systemctl daemon-reload
sudo systemctl enable --now whoami.service
Протестируйте:
curl http://localhost:8080
Проверьте статус:
systemctl status whoami.service
cd /opt/whoami
docker compose ps
Устранение неполадок
Сервис запускается, но контейнеры не работают
Проверьте systemd:
journalctl -u myapp.service -n 100 --no-pager
Валидируйте Compose:
cd /opt/myapp
docker compose config
Проверьте Docker:
systemctl status docker
docker info
WorkingDirectory неверный
Если systemd не может найти ваш файл Compose, подтвердите:
WorkingDirectory=/opt/myapp
Затем проверьте:
ls -la /opt/myapp
ls -la /opt/myapp/compose.yaml
Сервис запускается из WorkingDirectory, а не из текущей директории оболочки.
Отказано в доступе Docker
Если юнит запускается как root, он обычно может получить доступ к Docker.
Если вы установили User=someuser, этот пользователь должен иметь доступ к Docker. Обычно это означает членство в группе docker или настройку Docker без прав root.
Проверьте:
groups someuser
Добавьте пользователя, если это уместно:
sudo usermod -aG docker someuser
Будьте осторожны. Группа Docker фактически привилегирована.
Команда Compose не найдена
Найдите Docker:
command -v docker
Используйте полный путь в юните:
ExecStart=/usr/bin/docker compose up -d --remove-orphans
Если плагин Compose отсутствует:
docker compose version
Установите его через ваш источник пакетов Docker.
Переменные окружения отсутствуют
Проверьте конфигурацию Compose так, как видит ее systemd:
cd /opt/myapp
docker compose config
Если systemd нужны дополнительные переменные окружения, используйте:
EnvironmentFile=-/opt/myapp/.env.systemd
Если Compose нужны переменные для подстановки, используйте:
/opt/myapp/.env
Они связаны, но не идентичны.
Контейнеры не запускаются после перезагрузки
Проверьте, включен ли сервис systemd:
systemctl is-enabled myapp.service
Включите его:
sudo systemctl enable myapp.service
Проверьте Docker:
systemctl is-enabled docker
systemctl status docker
Проверьте логи загрузки:
journalctl -u myapp.service -b --no-pager
Приложение запускается до того, как база данных готова
Добавьте health check базы данных и depends_on с service_healthy.
Также исправьте приложение. Оно должно повторять попытки соединения с базой данных. Порядок запуска инфраструктуры полезен, но логика повторных попыток в приложении лучше.
Диск заполнен логами Docker
Проверьте использование диска Docker:
docker system df
Проверьте большие логи контейнеров:
sudo du -h /var/lib/docker/containers | sort -h | tail
Настройте ротацию логов Docker в /etc/docker/daemon.json.
Затем пересоздайте контейнеры.
Частые ошибки
Ошибка 1: Запуск docker compose up в rc.local
Запуск docker compose up из rc.local или скрипта входа работает, пока не перестанет — используйте правильный юнит systemd вместо этого.
Ошибка 2: Использование Restart=always в systemd и restart: always в Compose
Обычно вам нужны только политики перезапуска контейнеров в Compose. Избегайте борьбы двух супервизоров.
Ошибка 3: Забывание –remove-orphans
Переименования и удаления сервисов могут оставить старые контейнеры. Используйте:
docker compose up -d --remove-orphans
Ошибка 4: Использование docker compose restart после изменений конфигурации
restart перезапускает контейнеры. Он не применяет все изменения конфигурации.
Используйте:
docker compose up -d
Ошибка 5: Запуск down -v без раздумий
Это может удалить тома. Для сервисов с состоянием это может означать удаление данных.
Ошибка 6: Нет резервной копии перед pull
Новые образы могут сломаться. Базы данных могут мигрировать. Теги могут сдвинуться. Сначала сделайте резервную копию.
Ошибка 7: Публикация каждого порта
Публикуйте только то, что хосту нужно экспортировать. Внутренний трафик между сервисами может оставаться в сети Compose.
Итоговый рекомендуемый паттерн
Для большинства сервисов на одном Linux-хосте используйте этот паттерн:
Файл Compose:
services:
app:
image: example/app:stable
restart: unless-stopped
ports:
- "8080:8080"
env_file:
- .env
Юнит systemd:
[Unit]
Description=MyApp Docker Compose stack
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/myapp
ExecStartPre=/usr/bin/docker compose config --quiet
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecReload=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
TimeoutStopSec=120
[Install]
WantedBy=multi-user.target
Включите его:
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service
Эксплуатируйте его:
sudo systemctl status myapp.service
sudo systemctl restart myapp.service
journalctl -u myapp.service -f
cd /opt/myapp && docker compose logs -f
Этот паттерн не фантичный, и это суть. Docker Compose отлично подходит для небольших, понятных систем, systemd отлично справляется с запуском и остановкой сервисов хоста, и вместе они дают вам надежную модель развертывания на одном сервере, не притворяясь, что каждому проекту нужен кластер. Для команд уровня контейнеров вне Compose — образы, тома, сети и очистка — см. Шпаргалку по Docker.