Шпаргалка Docker Compose для работы на сервере
Основные команды Docker Compose V2 для управления контейнерами на сервере. Справочник по жизненному циклу, логам и сетям. Решение ошибки docker-compose not found в Ubuntu.
Команды Compose, которые вы действительно используете
Docker Compose содержит более сорока подкоманд. В повседневной работе на сервере используется около дюжины. На этой странице они сгруппированы по задачам, для каждой приведена одна простая причина использования, а также ссылки на подробные руководства, если команда содержит скрытые ловушки.
Все описанное здесь относится к Compose V2: docker compose через пробел, а не старый скрипт docker-compose. V2 — это плагин на Go, который устанавливается вместе с Docker Engine. V1 больше нет в актуальных пакетах, поэтому ошибка docker-compose: command not found на свежей установке Ubuntu по состоянию на июль 2026 года ожидаема, а не является признаком поломки. Проверьте версию с помощью docker compose version. Если команда ничего не выводит, установите пакет docker-compose-plugin.
Все приведенные ниже команды запускаются из каталога, в котором находится ваш файл compose.yaml, так как Compose берет имя проекта из этого каталога и ищет файл относительно него. Если запустить ту же команду уровнем выше, Compose завершит работу с ошибкой no configuration file provided: not found. Если формат файла для вас в новинку, начните с первого файла Compose на VPS и возвращайтесь сюда за командами.
Жизненный цикл: четыре команды для запуска и одна для удаления контейнеров
docker compose up -d
docker compose up -d --wait
docker compose stop
docker compose start
docker compose restart web
docker compose downup -d создает сеть, создает контейнеры, запускает их и завершает работу. Команда возвращает управление сразу после создания контейнеров, поэтому скрипт развертывания, который сразу после этого выполняет проверку curl, часто завершается ошибкой при первой попытке. up -d --wait блокирует выполнение до тех пор, пока каждый сервис, для которого объявлена проверка работоспособности (healthcheck), не перейдет в состояние healthy; если хотя бы один сервис не достигнет этого состояния, команда завершится с ненулевым кодом. Эффективность этого флага ограничена качеством самой проверки, поэтому перед использованием в автоматизации настройте надежный healthcheck для Compose.
stop останавливает контейнеры, но сохраняет их, поэтому start возвращает в работу те же самые контейнеры с тем же слоем для записи. down останавливает контейнеры, а затем удаляет их вместе с сетью проекта. Все данные, записанные внутри контейнера вне томов (volumes), будут безвозвратно утеряны. Это самое частое и дорогостоящее заблуждение при работе с Compose, а в статье полная разница между down и stop подробно описано, в каких ситуациях это приводит к проблемам.
restart — это не перезагрузка. Команда останавливает и запускает тот же самый контейнер с уже имеющейся конфигурацией, поэтому изменение переменной окружения, новый тег образа или отредактированный проброс портов не дадут никакого эффекта. Чтобы применить изменения в файлах, снова запустите up -d. Compose сравнит каждый сервис с запущенным контейнером и пересоздаст только те из них, конфигурация которых изменилась.
Применение изменений: пересоздание, загрузка или пересборка
docker compose up -d --force-recreate
docker compose pull && docker compose up -d
docker compose build --no-cache web
docker compose up -d --build webКоманда up -d сама по себе ничего не делает, если изменений нет, что и позволяет безопасно запускать её многократно. Флаг --force-recreate отменяет это сравнение и заменяет каждый контейнер, даже если конфигурация идентична, поэтому это самый быстрый способ очистить странные состояния внутри контейнера.
Обновление image требует двух команд, потому что они выполняют разные задачи. pull загружает актуальный image для каждого тега, указанного в файле. Затем up -d обнаруживает, что ID image сервиса больше не соответствует его запущенному контейнеру, и пересоздаёт контейнер. Если пропустить pull, up -d продолжит без ошибки использовать прошлогодний latest. Обратная проблема возникает в stack из нескольких сервисов: одновременная загрузка latest для каждого сервиса может нарушить работу приложения, которое ещё десять секунд назад работало нормально. Поэтому self-hosted workspace AFFiNE фиксирует каждый из четырёх тегов image. Фиксация тега также превращает обновление в осознанное изменение тега с последующим pull и пересозданием. Если stack переносит базу данных при запуске, перед выполнением любой из этих команд нужна готовая dump. Такой порядок self-hosted служба поддержки Chatwoot использует при каждом обновлении версии.
Команда build применяется к сервисам, в которых объявлена секция build: вместо image:. up -d --build выполняет сборку и запуск за один шаг — это стандартный цикл при изменении кода. Используйте --no-cache только тогда, когда кэшированный слой явно устарел, так как она пересобирает каждый слой с нуля. Когда стек развёртывается из checkout-версии git-тега, а не из образа в реестре, этот же цикл сборки является и путём обновления; именно так самохостинг трекера тренировок openGym переходит от одной зафиксированной версии к другой.
Просмотр запущенных процессов
docker compose ps
docker compose ps -a
docker compose logs -f --tail=100
docker compose logs --since 15m --timestamps db
docker compose top
docker compose lsps выводит только запущенные контейнеры. Сервис, который аварийно завершился при запуске, не будет виден в этом списке, пока вы не добавите -a. Если контейнер отсутствует в ps, но ps -a показывает его как Exited (1), это типичный признак ошибки при старте. Проверьте код завершения, а затем изучите логи.
logs -f выводит логи всех сервисов одновременно, добавляя имя сервиса в начало каждой строки. Это полезно, когда сервисы взаимодействуют друг с другом и важна последовательность событий. Укажите имя сервиса, чтобы сузить область вывода. --tail=100 важен для контейнера, который работает уже месяц, так как по умолчанию команда выводит всю историю и переполняет терминал. --since 15m отвечает на стандартный вопрос о том, что именно произошло во время последней перезагрузки.
top перечисляет процессы внутри каждого контейнера, что позволяет отличить состояние «контейнер запущен» от состояния «процесс внутри него запущен». ls выходит за пределы текущего каталога и выводит список всех проектов Compose на хосте с их статусом, что помогает найти стек, запущенный несколько месяцев назад.
Получение доступа к оболочке внутри сервиса
docker compose exec web sh
docker compose exec -u root web sh
docker compose run --rm web env
docker compose run --rm --no-deps web shКоманда exec выполняет команду внутри уже запущенного контейнера. Команда run запускает новый контейнер на основе того же определения сервиса; это необходимо, если сервис завершается слишком быстро и вы не успеваете выполнить run. Всегда используйте run вместе с --rm, иначе каждый вызов будет оставлять после себя остановленный контейнер. Со временем их количество станет таким большим, что вывод docker compose ps -a будет невозможно прочитать.
Попробуйте sh перед bash. В образах на базе Alpine отсутствует bash, и при попытке запуска возникнет ошибка exec: "bash": executable file not found in $PATH. Добавление флага --no-deps к команде run позволяет пропустить зависимости сервиса. Это предотвращает запуск всей базы данных при выполнении простой проверки конфигурации.
Команда run --rm web env — самый быстрый способ увидеть переменные окружения, которые фактически получил сервис после объединения всех файлов .env, блоков environment: и переменных оболочки. Если значение оказывается неверным, причина обычно кроется в порядке объединения. В разделе как Compose обрабатывает файлы окружения и секреты описано, какой источник имеет приоритет.
Сети, порты и разрешение имен
docker compose port web 80
docker compose exec web getent hosts db
docker compose config --networksCompose помещает все сервисы в одну сеть проекта, а имя каждого сервиса становится DNS-именем в этой сети. Запуск getent hosts db внутри web выводит IP-адрес контейнера, если разрешение имени работает, и ничего не выводит, если оно не работает. Поэтому за две секунды можно проверить, «видят ли эти контейнеры друг друга». Если имя разрешается, но соединение отклоняется, процесс внутри db привязан к 127.0.0.1, а не к 0.0.0.0. Поэтому он не принимает пакеты от другого контейнера. Это же ограничение объясняет, почему контейнер, запущенный вне проекта через docker run или в отдельном стеке, вообще не может разрешить имя вроде jellyfin. Это первое, что нужно проверить, если фронтенд Halcyon для вашей библиотеки Jellyfin не может подключиться к указанному серверу. Подробнее эта модель описана в материале как работают сети Compose и DNS сервисов.
port web 80 выводит адрес хоста и порт, на котором опубликован порт контейнера; это избавляет от необходимости угадывать, если маппинг задан через переменную. Публикация порта также создает правило межсетевого экрана, которым Docker управляет самостоятельно. Это правило стоит перед вашими собственными, поэтому сервис, который вы считали приватным, может оказаться открытым для интернета. Этот случай разобран в почему опубликованные порты Docker обходят ufw. Более безопасный подход — не публиковать эти порты, а разместить перед сервисами один прокси с аутентификацией в проектной сети. Именно это дает запуск Authentik в качестве уровня единого входа.
Тома и данные
docker compose config --volumes
docker compose cp db:/etc/postgresql/pg_hba.conf ./pg_hba.conf
docker compose down -vconfig --volumes выводит именованные тома, объявленные в проекте, по одному на строку. Этот список необходимо использовать для резервного копирования. Если тома содержат незаменимые данные, точная команда для бэкапа так же важна, как и сам список; именно поэтому в сравнении PhotoPrism и Immich подробно описаны команды дампа и копирования, необходимые для каждого фотосервера. cp копирует файл внутрь контейнера или из него без открытия оболочки, используя формат service:path для стороны, являющейся контейнером.
down -v удаляет эти именованные тома вместе с контейнерами. Это подходящая команда для разбора тестового стека, но она не подходит для любых данных, которые вам важны, так как запрос подтверждения отсутствует, а отмена действия невозможна. Bind mounts сохраняются при этом, так как они находятся в файловой системе хоста. Эта разница в радиусе поражения — одна из причин осознанно выбирать между bind mounts и именованными томами.
Очистка диска без потери данных
docker compose down --remove-orphans
docker system df
docker image prune -a
docker builder prune--remove-orphans удаляет контейнеры, которые относятся к проекту, но больше не указаны в файле конфигурации; именно это происходит после переименования сервиса. Без этой команды такие контейнеры продолжают работать, оставаясь невидимыми для docker compose ps.
docker system df показывает, на что расходуется место на диске, прежде чем вы что-либо удалите. Утилита разделяет данные на образы, контейнеры, локальные тома и кэш сборки, указывая объем, который можно освободить для каждой категории. image prune -a удаляет все образы, на которые не ссылается ни один тег. На сервере, куда загружалось несколько версий одного крупного образа, это обычно дает наибольший прирост свободного места. builder prune очищает кэш сборки, который незаметно растет на любом сервере, где выполняется сборка собственных образов.
Ни одна из этих команд не затрагивает именованные тома. Это делают только docker volume prune и docker compose down -v.
Проверка файла перед внесением изменений
docker compose config --quiet
docker compose config --services
docker compose --dry-run up -dconfig --quiet выполняет проверку и не выводит ничего при успешном завершении, поэтому эту команду следует использовать на этапе подготовки к развертыванию или в git hook. Обычная команда config выводит полностью объединенный и интерполированный файл; это позволяет убедиться, что переменная была подставлена, а файл переопределений применился ожидаемым образом. Неустановленная переменная отобразится там как пустое значение рядом с предупреждением The "X" variable is not set. Defaulting to a blank string..
--dry-run — это глобальный флаг, а не флаг подкоманды, поэтому он указывается перед up. Он выводит все действия, которые выполнит Compose, не внося при этом никаких изменений. Потратить на это тридцать секунд перед выполнением down для важного стека — разумное решение.
Работа с несколькими файлами, профилями и проектами
docker compose -f compose.yaml -f compose.prod.yaml up -d
docker compose --profile debug up -d
docker compose -p staging up -dНесколько флагов -f объединяются в порядке их указания, при этом последующие файлы переопределяют предыдущие по каждому ключу. Это стандартный способ использования базового файла с небольшим переопределением для production, однако правила для списков и словарей различаются, поэтому ознакомьтесь с тем, как Compose объединяет несколько файлов, прежде чем приступать к отладке неожиданного поведения.
--profile запускает сервисы, помеченные этим профилем, вместе с сервисами без меток, что позволяет исключить отладочные инструменты из обычного up. -p задает имя проекта, благодаря чему две копии одного стека могут работать одновременно, используя отдельные сети и тома. Восстановление стека после перезагрузки не требует ввода команд вручную — для этого используется юнит, который выполняет задачу за вас, как описано в автозапуске стеков Compose.
FAQ
What replaced docker-compose with a hyphen?
Compose V2, invoked as docker compose with a space. It is a plugin bundled with Docker Engine, and the V1 Python tool is no longer installed by current packages. If the space form prints nothing, install the docker-compose-plugin package for your distribution. Update old scripts to the space form rather than adding an alias, because V2 has flags V1 never had.
Why does docker compose restart not pick up my config change?
restart stops and starts the existing container with the configuration it was created with, and it never re-reads compose.yaml. Any change to environment variables, ports, volumes or the image tag needs docker compose up -d, which compares each service against its running container and recreates the ones that differ. Add --force-recreate when you want the replacement to happen even though nothing in the file changed.
How do I update a service to a newer image?
Run docker compose pull, then docker compose up -d. The pull fetches the current image for each tag in the file, and up -d recreates any service whose image ID no longer matches its container. Running up -d on its own reuses the image already on disk, which is how a stack pinned to latest sits on a months old build without printing any error.
Which cleanup commands are safe on a live server?
docker system df, docker image prune -a and docker builder prune remove images and cache only, so running services keep working and named volumes are untouched. The dangerous pair is docker compose down -v and docker volume prune, which delete named volumes with no prompt. Run docker compose config --volumes first so you know what is at risk.
Can I run one command without starting the whole stack?
Yes. docker compose run --rm --no-deps web sh starts a single container from the web service definition, skips its dependencies, and removes the container when you exit. Use exec instead when the container is already running, because exec joins the live process and shows you the state the service is actually in.