Невозможно заставить любую точку входа Docker из скрипта работать без непрерывных перезапусков

У меня возникли проблемы с пониманием или просмотром какой-либо рабочей версии использования сценария bash в качестве точки входа для контейнера Docker. Я пробовал множество вещей в течение примерно 5 часов.

Даже из этого официального блога Docker. , использование bash-скрипта в качестве точки входа по-прежнему не работает.

Докерфайл

FROM debian:stretch
COPY docker-entrypoint.sh /usr/local/bin/
RUN ln -s /usr/local/bin/docker-entrypoint.sh / # backwards compat
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["postgres"]

докер-entrypoint.sh

#!/bin/bash
set -e

if [ "$1" = 'postgres' ]; then
    chown -R postgres "$PGDATA"

    if [ -z "$(ls -A "$PGDATA")" ]; then
        gosu postgres initdb
    fi

    exec gosu postgres "$@"
fi

exec "$@"

build.sh

docker build -t test .

запустить.ш

docker service create \
--name test \
test

Несмотря на многие усилия, я не могу получить Dockerfile, используя Entrypoint в качестве bash-скрипта, который не перезапускается постоянно и не повторяется.

Насколько я понимаю, exec "$@" предполагалось, что форма контейнера будет немедленно закрыта, но я не уверен, зависит ли это от сбоя какого-либо другого процесса в скрипте.

Я пробовал использовать скрипт docker-entrypoint.sh, который выглядел просто так:

#!/bin/bash

exec "$@"

И поскольку это также не удалось, я думаю, это исключает, что что-то еще не так внутри сценария, являющееся причиной сбоя.

Что также расстраивает, так это то, что нет логов ни с docker service logs test, ни с docker logs [container_id], и я не могу найти ничего полезного в docker inspect [container_id].

Мне трудно понять, как все доверяют exec "$@". Я не хочу прибегать к чему-то вроде tail -f /dev/null или использовать команду в docker run. Я надеялся, что будет какой-то непротиворечивый и надежный способ надежного использования сценария docker-entrypoint.sh для запуска служб, которые я мог бы запускать с помощью docker run, а также для других вещей для служб, но даже в официальном блоге Docker и бесчисленных вопросах здесь и в блогах других сайты, я не могу заставить работать хоть один пример.

Я был бы очень признателен за понимание того, что мне здесь не хватает.


person Alexander Kleinhans    schedule 09.08.2019    source источник
comment
Отложите режим роя на минуту (это усложнение); если вы просто docker run контейнер, который вы создали локально, на переднем плане, что он говорит?   -  person David Maze    schedule 09.08.2019


Ответы (2)


$@ — это просто строка аргументов командной строки. Вы не предоставляете ничего, поэтому он выполняет нулевую строку. Это выходит и убьет докера. Однако команда exec всегда будет выходить из запущенного скрипта — она уничтожает текущую оболочку и запускает новую, а не поддерживает ее работу.

Что, я думаю, вы хотите сделать, так это продолжать вызывать этот скрипт рекурсивным способом. Чтобы сценарий действительно вызывал сам себя, строка должна быть такой:

exec $0

$0 — это имя файла bash (или имя функции, если это функция). В данном случае это будет имя вашего скрипта.

Кроме того, мне любопытно ваше желание не использовать tail -f /dev/null? Создание новой оболочки снова и снова так быстро, как только может работать сценарий, не более эффективно. Я предполагаю, что вы хотите, чтобы этот скрипт запускался снова и снова, чтобы просто проверить ваше условие if.

В этом случае, вероятно, сработает цикл while(1).

person Riggles    schedule 09.08.2019
comment
CMD из Dockerfile передаются в качестве аргументов ENTRYPOINT. Как отмечено в вопросе, завершение сценария точки входа с помощью exec "$@" является чрезвычайно распространенным шаблоном для запуска любой команды в качестве основного процесса контейнера после выполнения некоторой инициализации. - person David Maze; 09.08.2019
comment
Но он все равно убьет его сценарий точки входа и завершит работу докера, как он его настроил. Tail -f /dev/null — вполне допустимый способ сделать то, что он хочет. - person Riggles; 09.08.2019

То, что вы показываете, в принципе должно работать и является одним из стандартных шаблонов Docker.

Взаимодействие между ENTRYPOINT и CMD довольно просто. Если вы укажете и то, и другое, то основным процессом-контейнером будет то, что указано в ENTRYPOINT (или docker run --entrypoint), и он будет передан CMD (или командой в конце docker run) в качестве аргументов. В этом контексте окончание сценария точки входа на exec "$@" просто означает «замените меня на CMD в качестве основного процесса-контейнера».

Итак, схема здесь

  1. Выполните некоторую первоначальную настройку, например chowning возможно внешний каталог данных; тогда
  2. exec "$@" для запуска всего, что было передано в качестве команды.

В вашем примере есть несколько вещей, которые стоит проверить; он не будет работать, как показано.

Все, что вы предоставляете в качестве ENTRYPOINT, должно подчиняться обычным правилам для исполняемых команд: если это голая команда, она должна быть в $PATH; в правах доступа к файлу должен быть установлен исполняемый бит; если это скрипт, то должен существовать и его интерпретатор; если это двоичный файл, он должен быть статически связан или все его общие библиотеки должны быть уже в образе. Для вашего сценария вам может потребоваться сделать его исполняемым, если он еще не

RUN chmod +x /usr/local/bin/docker-entrypoint.sh

Еще одна вещь с этой настройкой заключается в том, что (определенно) если ENTRYPOINT выходит, весь контейнер выходит, а директива оболочки Bourne set -e указывает сценарию выйти при любой ошибке. В артефактах в вопросе gosu не является стандартной частью базового образа debian, поэтому ваш точка входа потерпит неудачу (и ваш контейнер завершится), пытаясь запустить эту команду. (Однако это не повлияет на очень простой случай.)

Наконец, если у вас возникли проблемы с запуском контейнера в системе оркестровки, такой как Docker Swarm или Kubernetes, одним из ваших первых шагов должен быть запуск того же контейнера локально на переднем плане: используйте docker run без параметра -d и посмотрите, что он напечатает. вне. Например:

% docker build .
% docker run --rm c5fb7da1c7c1
docker: Error response from daemon: OCI runtime create failed: container_linux.go:345: starting container process caused "exec: \"docker-entrypoint.sh\": executable file not found in $PATH": unknown.
ERRO[0000] error waiting for container: context canceled 
% chmod +x docker-entrypoint.sh
% docker build .
% docker run --rm f5a239f2758d
/usr/local/bin/docker-entrypoint.sh: line 3: exec: postgres: not found

(Используя Dockerfile и короткий docker-entrypoint.sh из вопроса, а также используя окончательный идентификатор изображения из docker build . в этих docker run командах.)

person David Maze    schedule 09.08.2019