Почему - c в «sh - c команда» является обязательным в некоторых случаях и недопустимым в других? - PullRequest
0 голосов
/ 18 апреля 2020

Я использую ожидание , сценарий linux POSIX (#! Bin / sh) в моей конфигурации docker (python:3.8.1-alpine3.11).

В моем docker -compose.yml я использую следующую команду для загрузки скрипта:

app:
   command: sh -c "wait-for postgres:5432 && python manage.py migrate 
                && python manage.py runserver 0.0.0.0:8000"

Однако это приводит к /bin/sh: wait-for: not found. Файл определенно находится там, как я вижу, когда заливаюсь в контейнер.

Путем проб и ошибок внутри контейнера я обнаружил, что будет работать следующее:

/usr/src/app $  sh wait-for

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

Например, другие команды в строке не запускаются без -c; sh python не запускается, для этого требуется sh -c python.

Какой правильный подход использовать в моем файле docker-compose.yml? У меня должно быть две записи команды (одна для sh wait-for и другая для sh -c [other commands])?

1 Ответ

3 голосов
/ 18 апреля 2020

sh script.sh берет имя файла, читает из него команды и выполняет их; он специально выполняет сценарий оболочки. Если имя файла не содержит sla sh, , оно ищет текущий каталог перед поиском $PATH. Эта форма всегда запускает скрипт оболочки, поэтому , например, sh python не работает.

sh -c 'command' принимает одну команду в качестве позиционного аргумента и выполняет ее. Различные названия команд там интерпретируются в соответствии с обычными правилами; в частности, они должны быть где-то в переменной окружения $PATH, иначе в их именах должен быть sla sh.

В вашем Dockerfile похоже, что вы копируете скрипт wait-for в текущий каталог (с остальной частью вашего приложения). Таким образом, здесь конструкция sh wait-for использует правило «сначала искать в текущем каталоге» и работает, но форма sh -c 'wait-for ...' не находит его в $PATH. Самый простой обходной путь - это явно квалифицировать последний вызов с относительным путем

command: sh -c "./wait-for postgres:5432 && ..."

. Более широко полезным шаблоном является разделение первоначальной настройки (такой как «ожидание базы данных» и «запуск миграций») на сценарий точки входа, и его последний шаг - «запустить команду основного контейнера». Ваша точка входа может быть обычным сценарием оболочки

#!/bin/sh
set -e  # stop on error; equivalent to the "&&" in the one-liner
./wait-for "$POSTGRES_HOST:$POSTGRES_PORT"
python manage.py migrate
exec "$@"

, а затем в Dockerfile вы должны отдельно указать точку входа и команду

COPY wait-for entrypoint .
RUN chmod +x wait-for entrypoint
ENTRYPOINT ["./entrypoint"]
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

и ничего не указывать в docker-compose.yml в все.

...