Начинающий пользователь Docker Compose легко может запутаться в очень похожих на первый взгляд командах docker-compose up и start, а также down и stop. В этой статье с подробными примерами объясняется разница между ними.
Если вы новичок в работе с Docker Compose и осваиваете этот инструмент по руководствам, вам наверняка часто попадаются такие термины, как docker-compose up, docker-compose up -d, docker-compose start, docker-compose down, а может быть и docker-compose stop.
В этом многообразии поначалу легко запутаться, ведь на первый взгляд эти парные команды Docker Compose имеют схожие функции.
Особенно сложно с ходу определить различие между
docker-compose up
и docker-compose start
.Разве запустить контейнер с помощью Docker Compose — не то же самое, что выполнить команду up? Не совсем.
Сейчас разберём этот вопрос подробно.
Различия между Docker Compose up, up -d, stop, start, down и down -v
Что делают эти команды:
Команда Docker Compose up развёртывает сервисы веб-приложений и создаёт из docker-образа новые контейнеры, а также сети, тома и все конфигурации, указанные в файле Docker Compose. Добавляя флаг
-d
, вы выполняете команду в раздельном или фоновом режиме, сохраняя возможность управления терминалом (чуть ниже рассмотрим примеры для наглядности).Команда Docker Compose stop останавливает все сервисы, связанные с определённой конфигурацией Docker Compose. Она НЕ удаляет ни контейнеры, ни связанные с ними внутренние тома и сети.
Команда Docker Compose start запускает любые остановленные сервисы в соответствии с параметрами остановленной конфигурации, указанными в том же файле Docker Compose.
Команда Docker Compose down останавливает все сервисы, связанные с определённой конфигурацией Docker Compose. В отличие от команды stop, она также удаляет все контейнеры и внутренние сети, связанные с этими сервисами — но НЕ указанные внутри тома. Чтобы очистить и их, надо дополнить команду
down
флагом -v
.Разница сопоставима с различием между командами Docker run и start, верно?
Но довольно теории — давайте перейдём к практическим примерам.
Наглядный пример для понимания разницы
Если хотите проверить примеры самостоятельно, убедитесь, что у вас под рукой есть Docker и установочный пакет Docker Compose.
Предположим, вы используете платформу для блогов Ghost через Docker Compose на своём сервере Linux.
В наших руководствах по самостоятельному хостингу я обычно использую флаг
-d
для всех развёртываний конфигураций на серверах. Но что если не делать этого уточнения?avimanyu@localhost:~/ghost$ docker-compose up
Pulling ghost (ghost:4.20.3)...
4.20.3: Pulling from library/ghost
b380bbd43752: Pull complete
8d36a6ce056a: Pull complete
f75fe68b8e22: Pull complete
44f6d143e12f: Pull complete
0ebe8063dedd: Pull complete
f984e0e37c5a: Pull complete
ce2320facea8: Pull complete
898c3dbc1716: Pull complete
45c37559f24a: Pull complete
Digest: sha256:b332684117bfa05329298712ad0ffcfc4a83ce6314332e073978f46be3c05e81
Status: Downloaded newer image for ghost:4.20.3
Creating ghost_ghost_1 ... done
Attaching to ghost_ghost_1
ghost_1 | [2021-10-26 07:02:05] INFO Ghost is running in production...
ghost_1 | [2021-10-26 07:02:05] INFO Your site is now available on https://ghost.domain.com/
ghost_1 | [2021-10-26 07:02:05] INFO Ctrl+C to shut down
ghost_1 | [2021-10-26 07:02:05] INFO Ghost server started in 0.369s
ghost_1 | [2021-10-26 07:02:06] WARN Database state requires initialisation.
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: posts
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: posts_meta
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: users
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: oauth
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: posts_authors
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: roles
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: roles_users
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: permissions
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: permissions_users
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: permissions_roles
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: settings
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: tags
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: posts_tags
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: invites
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: brute
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: sessions
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: integrations
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: webhooks
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: api_keys
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: mobiledoc_revisions
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: members
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: products
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: offers
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: benefits
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: products_benefits
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: members_products
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: members_payment_events
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: members_login_events
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: members_email_change_events
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: members_status_events
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: members_product_events
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: members_paid_subscription_events
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: labels
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: members_labels
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: members_stripe_customers
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: members_stripe_customers_subscriptions
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: offer_redemptions
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: members_subscribe_events
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: stripe_products
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: stripe_prices
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: actions
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: emails
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: email_batches
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: email_recipients
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: tokens
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: snippets
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: temp_member_analytic_events
ghost_1 | [2021-10-26 07:02:06] INFO Creating table: custom_theme_settings
ghost_1 | [2021-10-26 07:02:06] INFO Model: Product
ghost_1 | [2021-10-26 07:02:06] INFO Model: Tag
ghost_1 | [2021-10-26 07:02:06] INFO Model: Role
ghost_1 | [2021-10-26 07:02:06] INFO Model: Permission
ghost_1 | [2021-10-26 07:02:07] INFO Model: User
ghost_1 | [2021-10-26 07:02:07] INFO Model: Post
ghost_1 | [2021-10-26 07:02:08] INFO Model: Integration
ghost_1 | [2021-10-26 07:02:08] INFO Relation: Role to Permission
ghost_1 | [2021-10-26 07:02:08] INFO Relation: Post to Tag
ghost_1 | [2021-10-26 07:02:08] INFO Relation: User to Role
ghost_1 | [2021-10-26 07:02:08] INFO Database is in a ready state.
ghost_1 | [2021-10-26 07:02:08] INFO Ghost database ready in 3.309s
ghost_1 | [2021-10-26 07:02:09] INFO Ghost booted in 4.457s
ghost_1 | [2021-10-26 07:02:09] INFO Adding offloaded job to the queue
ghost_1 | [2021-10-26 07:02:09] INFO Scheduling job update-check at 49 27 22 * * *. Next run on: Tue Oct 26 2021 22:27:49 GMT+0000 (Coordinated Universal Time)
ghost_1 | [2021-10-26 07:02:51] INFO "GET /favicon.ico" 200 7ms
ghost_1 | [2021-10-26 07:02:51] INFO "GET /" 200 605ms
ghost_1 | [2021-10-26 07:02:51] INFO "GET /assets/built/screen.css?v=dde6c321bb" 200 5ms
ghost_1 | [2021-10-26 07:02:51] INFO "GET /assets/built/casper.js?v=dde6c321bb" 200 3ms
ghost_1 | [2021-10-26 07:02:52] INFO "GET /members/api/member/" 204 1ms
ghost_1 | [2021-10-26 07:02:52] INFO "GET /members/api/site/" 200 14ms
ghost_1 | [2021-10-26 07:02:52] INFO "GET /favicon.ico" 200 2ms
Видите? Без флага
-d
вы всё-таки запускаете целевую конфигурацию, но в режиме расширенного вывода и без возврата к подсказке терминала. Удобно, правда? Если открыть браузер и перейти к блогу Ghost, он станет доступен через пару секунд. А что будет, если выйти из консоли с помощью Ctrl+Z? Выполнение процесса продолжится в фоновом режиме, и это можно проверить с помощью команды docker ps:avimanyu@localhost:~/ghost$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
563a45d049cf ghost:4.20.3 "docker-entrypoint.s…" 3 minutes ago Up 3 minutes 2368/tcp ghost_ghost_1
А что стало бы с контейнером при нажатии Ctrl+C? Процесс был бы мгновенно прерван.
avimanyu@localhost:~/ghost$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Использование флага
-d
аналогично нажатию Ctrl+Z: такая команда отделяет контейнер от консоли и продолжает его работу в фоновом режиме, а также выводит на экран новое имя контейнера (в нашем случае ghost_ghost_1
).А теперь вместо
docker-compose down
давайте введём команду docker-compose stop
:avimanyu@localhost:~/ghost$ docker-compose stop
avimanyu@localhost:~/ghost$
И проверим запущенные контейнеры. По идее, таковых быть не должно:
avimanyu@localhost:~/ghost$ docker-compose ps
Name Command State Ports
---------------------------------------------------------------
ghost_ghost_1 docker-entrypoint.sh node ... Exit 0
Заметьте, что я ввёл не
docker ps
, а docker-compose ps
, чтобы проиллюстрировать альтернативный способ проверки состояния Exit 0
. Этот код означает, что контейнер остановлен/из него произведён выход.Давайте для проверки введём
docker ps -a
. Флаг -a
выполнит поиск и по остановленным контейнерам:avimanyu@localhost:~/ghost$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
44d09e778a91 ghost:4.20.3 "docker-entrypoint.s…" 8 minutes ago Exited (0) 7 minutes ago ghost_ghost_1
А что же за команда
docker-compose start
?Использовать Docker Compose start имеет смысл, только пока вы не удалили контейнеры командой
docker-compose down
(а в командной строке данного руководства я этого пока не сделал). Основное отличие данной команды — она запускает контейнеры, которые были остановлены, но не удалены.Для начала давайте выполним команду
start
вместо up
и посмотрим, что произойдёт:avimanyu@localhost:~/ghost$ docker-compose start
Starting ghost ... done
avimanyu@localhost:~/ghost$
Остановленный контейнер вновь запускается:
avimanyu@localhost:~/ghost$ docker-compose ps
Name Command State Ports
-----------------------------------------------------------------
ghost_ghost_1 docker-entrypoint.sh node ... Up 2368/tcp
Готово! Теперь состояние сменилось с
Exit 0
на Up
. Перепроверить результат можно с docker
версией той же команды:avimanyu@localhost:~/ghost$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
44d09e778a91 ghost:4.20.3 "docker-entrypoint.s…" 22 minutes ago Up About a minute 2368/tcp ghost_ghost_1
А теперь давайте снова выполним команду
stop
.avimanyu@localhost:~/ghost$ docker-compose stop
Stopping ghost_ghost_1 ... done
Теперь вам известно текущее состояние контейнера. Запустить его вновь можно командой
up
или start
. Примечательно, что в этом состоянии можно также выполнить команду down
, не запуская при этом сервисы:avimanyu@localhost:~/ghost$ docker-compose down
Removing ghost_ghost_1 ... done
Network net is external, skipping
Теперь контейнер удалён. Если бы в файле Docker Compose были указаны внутренние сети, они тоже оказались бы удалены. Поскольку сеть
net
является внешней, операция по удалению её пропускает. Но добавив в команду флаг -v
, вы удалили бы и её!avimanyu@localhost:~/ghost$ docker-compose down -v
Stopping ghost_ghost_1 ... done
Removing ghost_ghost_1 ... done
Network net is external, skipping
Volume ghost is external, skipping
В деле защиты данных осторожность не помешает!
И ещё один совет. Обратите внимание: я использую внешний том (созданный ранее с помощью команды
docker volume create volume-name
), поэтому команда down
его не удаляет даже с флагом -v
. Действие этого флага распространяется только на тома, созданные из спецификаций Docker Compose. А вот команда docker volume prune
удалит и внешний том — причём, даже если его использует какой-либо контейнер.Кроме того, на данном этапе уже нельзя использовать команду
start
. Она работает только в конфигурациях, остановленных командой stop
:avimanyu@localhost:~/ghost$ docker-compose start
Starting ghost ... failed
ERROR: No containers to start
В этом случае нужно ещё раз ввести
docker-compose
up или docker-compose up -d
.avimanyu@localhost:~/ghost$ docker-compose up -d
Creating ghost_ghost_1 ... done
avimanyu@localhost:~/ghost$
Заключение
Надеюсь, в этой статье мне удалось пояснить разницу между командами
up
, up -d
и start
, а также stop
, down
и down -v
в Docker Compose.Это обширное руководство с пояснениями сделает вашу ежедневную работу в Docker гораздо проще и поможет разобраться со сложными случаями. Разумеется, в зависимости от сценария использования, особенно в продукционных системах, выбор конкретной команды для решения проблемы будет зависеть от вашего подхода к решению.
Если у вас есть соображения, вопросы или предложения, пожалуйста, поделитесь ими в комментариях.
НЛО прилетело и оставило здесь промокод для читателей нашего блога:
— 15% на все тарифы VDS (кроме тарифа Прогрев) — HABRFIRSTVDS.
Доступно до 31 декабря 2021 г.