Остановка контейнера докера изнутри
У меня есть cronjob, работающий внутри контейнера докера, который проверяет, работают ли все службы как ожидалось. Если этот cronjob определяет, что есть проблема, я хотел бы остановить контейнер докера (изнутри...)
К сожалению, exit
просто останавливает мой cronjob script
Ответы
Ответ 1
В принципе, для выхода из контейнера требуется PID 1.
Я изначально думал, что kill -s SIGKILL 1
будет работать, но PID 1 защищен, поэтому он не работает.
Как было предложено @Thomasleveil, вы можете добавить код, например trap "exit" SIGINT SIGTERM
, в PID 1 script, что означает, что процесс будет завершен при отправке a kill -s SIGINT 1
. Я немного предпочитаю этот метод тому, с которым вы столкнулись (убивая дочерний процесс напрямую), поскольку он дает родительскому процессу возможность очистить, а также родительский процесс должен иметь возможность найти PID дочернего процесса без awk.
Однако, если вы используете несколько процессов, вам следует использовать что-то вроде supervisord или runit.
Ответ 2
Я должен был понять это недавно. После большого разочарования я приземлился на следующее:
В своем файле Docker укажите ENTRYPOINT:
ENTRYPOINT ["/entrypoint.sh"]
Затем предоставьте такой скрипт. Не нужно ничего делать, кроме как вызывать ваше приложение. Не стесняйтесь добавлять дополнительные настройки в сценарий, но помните, что если сценарий делает что-либо после того, как он вызывает ваше приложение, он может замаскировать код возврата вашего приложения. Если это имеет отношение к вам, убедитесь, что сценарий захватывает код возврата и распространяет его как собственный код возврата.
Примечание. Не используйте exec
для вызова своего приложения!
В результате PID 1 будет принадлежать entrypoint.sh, а ваше приложение будет иметь другой PID. Шахты имеют тенденцию приземляться на PID 9 или 10.
Затем, когда вам нужно убить ваше приложение, просто определите его PID и вызовите kill -SIGKILL $PID
или pkill -SIGKILL yourapp
. Ваш процесс, не являющийся PID 1, получит сигнал и немедленно завершится. Ваш entrypoint.sh
будет незамедлительно завершен, потому что то, что вы разработали для него после завершения процесса.
Ответ 3
Я столкнулся с той же проблемой и решил ее, используя функцию healthcheck в Docker.
Вы можете добавить проверки для проверки ваших услуг в файле, подобном heahthcheck.sh
. Затем добавьте что-то вроде следующего к вашему Dockerfile
:
# Healthcheck
COPY healthcheck.sh /
RUN chmod +x /healthcheck.sh
HEALTHCHECK --interval=10s --retries=5 CMD /healthcheck.sh
Это гарантирует, что Docker проверит работоспособность вашего контейнера, запустив ваш скрипт через заданный интервал времени, и если он выйдет из строя 5 раз подряд, он помечает состояние как нездоровое.
Теперь, чтобы перезапустить ваш контейнер, если состояние стало нездоровым, вы можете использовать autoheal следующим образом:
docker run -d \
--name autoheal \
--restart=always \
-e AUTOHEAL_CONTAINER_LABEL=all \
-v /var/run/docker.sock:/var/run/docker.sock \
willfarrell/autoheal
Это будет перезапускать ваш контейнер каждый раз, когда его состояние становится нездоровым.
Ответ 4
Вдохновленный @JakeRobb:
Вы можете выполнить докер с помощью команды:
/bin/bash -c "while true; do sleep infinity || exit 0; done"
Это выполнит sleep для PID ниже 1. Как только вы убьете его, цикл завершится. Для этого из докера используйте:
pkill -f sleep
Ответ 5
Я убиваю "процесс блокировки", то есть основной процесс, который запускает ваш докер; вот так (в этом случае докер запускает команду sleep infinity для демонстрационных целей).
ps -afx | grep sleep | awk '{print $ 1}' | Ксаргс убивают -9
Ответ 6
Я попытался убить процесс 1 без успеха.
Попробуйте комментарий @zero323 с помощью shutdown -h now
. Он отлично работает (извините, я не могу голосовать за него напрямую, так как он не находится в списке ответов).