Команды Docker Compose Up и Start, а также Down и Stop: в чем разница?

Kate

Administrator
Команда форума
Начинающий пользователь 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 гораздо проще и поможет разобраться со сложными случаями. Разумеется, в зависимости от сценария использования, особенно в продукционных системах, выбор конкретной команды для решения проблемы будет зависеть от вашего подхода к решению.

 
Спасибо, интересно было прочесть.
Не могли бы ответить на такой вопрос (1), - после останова многоконтейнерного приложения командой docker-compose down, которое имеет базу данных, новые данные, введенные после первичного развертывания тоже будут удалены вместе с контейнерами или нет, например, в случае, если данные были отдельных томах, а не в контейнерах. Воспримут ли вновь развернутые, по команде docker-compose up, контейнеры с образов эти данные с оставшихся томов, т.е. продолжится ли работа с состояния на момент остановки?
2) Какой способ останова и последующего запуска подобного приложения (stop+start или down+up -d) вы могли бы порекомендовать, если надо перезагрузить сервер?
В своей практике я использовал stop и start, но потом при запуске приходилось бороться с некоторыми ошибками, в частности со стороны новой технологии snap, из-за которых возникла путаница.
 

Kate

Administrator
Команда форума
Спасибо, интересно было прочесть.
Не могли бы ответить на такой вопрос (1), - после останова многоконтейнерного приложения командой docker-compose down, которое имеет базу данных, новые данные, введенные после первичного развертывания тоже будут удалены вместе с контейнерами или нет, например, в случае, если данные были отдельных томах, а не в контейнерах. Воспримут ли вновь развернутые, по команде docker-compose up, контейнеры с образов эти данные с оставшихся томов, т.е. продолжится ли работа с состояния на момент остановки?
2) Какой способ останова и последующего запуска подобного приложения (stop+start или down+up -d) вы могли бы порекомендовать, если надо перезагрузить сервер?
В своей практике я использовал stop и start, но потом при запуске приходилось бороться с некоторыми ошибками, в частности со стороны новой технологии snap, из-за которых возникла путаница.

Здравствуйте! Добро пожаловать к нам на форум :)
Если файлы базы данных /var/lib/mysql и файлы конфигурации вытащить в волумы и не хранить эти волумы в /var/lib/docker (чтобы случайно не удалить при docker system prune), то данные должны сохраняться, а к остановке docker compose, я бы добавила timeout побольше, что бы соединения могли успешно завершить и не сломать базу.
 
Сверху