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
в все.