Остановка контейнера докера изнутри

У меня есть 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. Он отлично работает (извините, я не могу голосовать за него напрямую, так как он не находится в списке ответов).