Skip to main content

У чому різниця між docker stop та docker kill?

docker stop і docker kill обидва способи зупинити running container, але відрізняються за агресивністю. Вибір між ними переважно про те, чи застосунку всередині потрібен час на чисту зупинку.

Теорія

TL;DR

  • docker stop = graceful. Шле SIGTERM, чекає N секунд (дефолт 10), шле SIGKILL, якщо ще running.
  • docker kill = негайний. Шле SIGKILL за замовчуванням, або будь-який сигнал через --signal.
  • Обидва врешті змушують container вийти. Різниця в тому, чи отримує застосунок шанс прибрати.
  • Для баз, сервісів зі станом, чого-небудь з відкритими з'єднаннями, бери stop.
  • Для зависнутих процесів, застосунків з unresponsive PID 1, debug, kill.
  • docker rm -f = docker kill + docker rm в одному кроці.

Що робить docker stop

t=0 daemon шле SIGTERM на PID 1 всередині container t=0..N застосунок має обробити SIGTERM: - закінчити in-flight запити - flush логів / WAL / кешу - закрити DB-з'єднання - чисто вийти з кодом 0 t=N якщо ще running, daemon шле SIGKILL (де N = --time, дефолт 10 секунд)

Grace-період налаштовується per stop:

bash
docker stop -t 30 mycontainer # 30 секунд docker stop -t 0 mycontainer # 0 = SIGKILL негайно (як kill)

Або per container при run:

bash
docker run --stop-timeout 60 myapp

Що робить docker kill

bash
docker kill <name> # SIGKILL за замовчуванням docker kill --signal=SIGTERM <name> # явний SIGTERM (без grace-вікна) docker kill --signal=SIGUSR1 <name> # будь-який сигнал docker kill -s 9 <name> # числовий сигнал

Флаг --signal робить docker kill гнучкішим, ніж його ім'я підказує. Це також спосіб надіслати non-fatal сигнал running-застосунку, наприклад, сказати nginx перечитати config:

bash
docker kill --signal=SIGHUP nginx-container # nginx перечитує config без рестарту.

Незважаючи на ім'я, kill не завжди вбиває, лише SIGKILL і SIGTERM (без trap) завершують процес.

Side-by-side

docker stopdocker kill
Дефолтний сигналSIGTERM, потім SIGKILLSIGKILL
Grace-періодтак (дефолт 10с, налаштовується)жодного
Кастомний сигналнітак (--signal)
Для чистого shutdownТАКні
Для зависнутих процесівніТАК
Для надсилання сигналів (HUP, USR1)ніТАК

Чому graceful важить

bash
# Postgres з --memory тиском у фоні docker stop pg # SIGTERM → postgres flush WAL, закриває з'єднання, exit 0 → усе ок docker kill pg # SIGKILL → postgres помирає мід-write → на наступному старті WAL-replay → потенційно повільне recovery

Для баз: stop, ніколи не kill (якщо не свідомо).

bash
# Web-сервіс з in-flight запитами docker stop api # SIGTERM → api припиняє приймати нові, добиває існуючі, exit → без client-помилок docker kill api # SIGKILL → з'єднання падають мід-flight → 502 для юзера

Для user-facing сервісів: stop. Завжди.

Коли kill правильний

  • Зависнутий процес, що ігнорує SIGTERM і блокує усе. Stop чекав; kill закінчує.
  • Надсилання control-сигналів як SIGHUP (reload), SIGUSR1 (rotate logs), SIGUSR2 (debug dump) running-застосунку.
  • Тести / disposable container, де graceful shutdown не важить.
  • docker rm -f використовує kill внутрішньо, нормально для cleanup уже-зупинених або таких, що не важили, container.

Типові помилки

Вбивати базу мід-write

bash
# НЕПРАВИЛЬНО docker kill postgres-prod # Іноді recovers нормально; іноді корумповані індекси; іноді WAL-replay 30 хвилин.

Бери docker stop. Ще краще: спочатку чисто зупини застосунок, потім зупини container.

Застосунок ігнорує SIGTERM, тоді отримує SIGKILL через 10с

bash
$ docker stop web # Виглядає повільно; бере усі 10 секунд; container виходить з 137.

Застосунок не обробляє SIGTERM = брудний shutdown після grace-періоду. Фікс застосунку: trap SIGTERM і виходь чисто. Тестуй через docker stop і підтверджуй exit 0 (або який чистий код) за пару секунд.

Брати kill для --signal=SIGTERM замість просто stop

bash
# Те саме, що docker stop -t 0 (без grace-вікна) docker kill --signal=SIGTERM web

Це шле SIGTERM, але НЕ супроводжує SIGKILL'ом після grace-періоду, якщо застосунок ігнорує сигнал, container лишається running. Зазвичай хочеш docker stop, що ДОДАЄ SIGKILL.

Забути, що PID 1 має особливу signal-семантику

Linux PID 1 ігнорує більшість сигналів за замовчуванням, поки процес явно їх не обробляє. Якщо твій застосунок це PID 1 (так, у container), маєш trap SIGTERM у коді:

js
// Node.js приклад process.on('SIGTERM', () => { server.close(() => process.exit(0)); });

Без цього trap docker stop чекає повний grace-період і шле SIGKILL.

Реальне застосування

  • Прод-деплої: docker stop (або еквівалент stack-level оркестратора) для graceful shutdown.
  • CI cleanup: docker rm -f $(docker ps -aq) (kill + rm) для тестів, де graceful не важить.
  • Reload config nginx: docker kill --signal=SIGHUP nginx.
  • Ротація логів: docker kill --signal=USR1 myapp, щоб застосунок reopen log-файли.
  • Hung-container debug: docker kill після того, як docker stop чекав повний grace-період безуспішно.

Питання для поглиблення

Q: Який дефолтний grace-період і як його змінити?


A: 10 секунд. Override per-stop через docker stop -t N, per-container через docker run --stop-timeout N, або у Compose через stop_grace_period: 30s.

Q: Чи daemon retry'їть SIGTERM протягом grace-періоду?


A: Ні. SIGTERM шлеться раз. Якщо застосунок його ігнорує, daemon чекає і потім SIGKILL.

Q: Що означають exit code 137 vs 143?


A: 137 = 128 + 9 (SIGKILL). 143 = 128 + 15 (SIGTERM). Container вийшов через відповідний сигнал. Якщо docker stop і бачиш 137, застосунок не обробив SIGTERM і його SIGKILL'нули після grace-періоду.

Q: Чи можу надіслати сигнал, що running-процес отримає?


A: Так, docker kill --signal=<SIG> <container> шле сигнал на PID 1 всередині. Чи робить застосунок з ним щось, залежить від коду застосунку (signal-handlers).

Q: (Senior) Як забезпечити, що твій dockerized застосунок правильно обробляє SIGTERM?


A: Три перевірки. (1) Код: встанови signal-handlers у entrypoint застосунку, що trap SIGTERM і починають graceful shutdown. (2) Init: уникай обгортання у shell-форму /bin/sh -c, це робить sh PID 1 і твій застосунок дитиною, що не отримує сигнал напряму. Бери exec-форму (CMD ["node", "server.js"]) або tini через --init. (3) Тестуй: docker stop свого container і assert, що він виходить за ~1 секунду з кодом 0 (або твоїм designated-чистим кодом), не після повного grace-періоду.

Приклади

Graceful-stop з продовженим grace-періодом

bash
# Прод-DB потребує час на flush $ docker stop -t 60 postgres-prod postgres-prod # Postgres обробляє SIGTERM, крутить checkpoint, виходить чисто. Зайняло ~12 секунд.

Довгий graceful-shutdown для stateful-сервісу. Швидше, ніж дозволив би дефолтний 10с timeout.

Reload nginx-config без рестарту

bash
$ docker kill --signal=SIGHUP nginx-prod nginx-prod # nginx отримує HUP, перечитує config з /etc/nginx/nginx.conf, продовжує крутитися. # Усі існуючі з'єднання продовжуються без переривань.

Класичне використання docker kill для надсилання non-fatal control-сигналу.

Діагностика зависнутого container

bash
# Застосунок ні на що не реагує $ docker stop -t 5 hung-container # Чекає 5с, шле SIGKILL. # Або скіпни чекання повністю: $ docker kill hung-container

Для container, що застряг, kill правильний tool, graceful марне чекання.

Compose grace-period налаштування

yaml
services: api: image: myapp stop_grace_period: 30s # docker compose stop чекатиме до 30с stop_signal: SIGUSR1 # бери SIGUSR1 замість SIGTERM (рідко)

Compose дозволяє кастомізувати per service. Для більшості застосунків дефолт нормально; для slow-shutting-down DB або worker подовжуй.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Коментарі

Ще немає коментарів