У меня есть Dockerfile, который я собираю для установки среды vanilla python (в которую я буду устанавливать приложение, но позже).
FROM ubuntu:12.04
# required to build certain python libraries
RUN apt-get install python-dev -y
# install pip - canonical installation instructions from pip-installer.org
# http://www.pip-installer.org/en/latest/installing.html
ADD https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py /tmp/ez_setup.py
ADD https://raw.github.com/pypa/pip/master/contrib/get-pip.py /tmp/get-pip.py
RUN python /tmp/ez_setup.py
RUN python /tmp/get-pip.py
RUN pip install --upgrade pip
# install and configure virtualenv
RUN pip install virtualenv
RUN pip install virtualenvwrapper
ENV WORKON_HOME ~/.virtualenvs
RUN mkdir -p $WORKON_HOME
RUN source /usr/local/bin/virtualenvwrapper.sh
Сборка работает нормально до последней строки, где я получаю следующее исключение:
[previous steps 1-9 removed for clarity]
...
Successfully installed virtualenvwrapper virtualenv-clone stevedore
Cleaning up...
---> 1fc253a8f860
Step 10 : ENV WORKON_HOME ~/.virtualenvs
---> Running in 8b0145d2c80d
---> 0f91a5d96013
Step 11 : RUN mkdir -p $WORKON_HOME
---> Running in 9d2552712ddf
---> 3a87364c7b45
Step 12 : RUN source /usr/local/bin/virtualenvwrapper.sh
---> Running in c13a187261ec
/bin/sh: 1: source: not found
Если я ls
попаду в этот каталог (просто чтобы проверить, что предыдущие шаги были зафиксированы), я вижу, что файлы существуют, как и ожидалось:
$ docker run 3a87 ls /usr/local/bin
easy_install
easy_install-2.7
pip
pip-2.7
virtualenv
virtualenv-2.7
virtualenv-clone
virtualenvwrapper.sh
virtualenvwrapper_lazy.sh
Если я пытаюсь source
выполнить команду, я получаю ту же ошибку «not found», что и выше. Однако, если я запускаю сеанс интерактивной оболочки, источник работает:
$ docker run 3a87 bash
source
bash: line 1: source: filename argument required
source: usage: source filename [arguments]
Я могу запустить скрипт отсюда, а затем с радостью получить доступ workon
и mkvirtualenv
т. Д.
Я сделал некоторое рытье, и первоначально это выглядело так , как будто эта проблема может лежать в различии между Башем как Ubuntu шелл и тиром в качестве Ubuntu системы оболочки , тир не поддерживает source
команду.
Тем не менее, ответом на этот вопрос является использование «.» вместо этого source
, но это только приводит к тому, что среда исполнения Docker взрывается с исключением из-за паники.
Как лучше всего запустить сценарий оболочки из инструкции Dockerfile RUN, чтобы обойти это (я запускаю базовый образ по умолчанию для Ubuntu 12.04 LTS).
CMD source activate django-py35
Ответы:
RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh"
источник
source
вообще, простоbash /usr/local/bin/virtualenvwrapper.sh
в таком случае?RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh; my_command; my_command; my_command;"
/bin/sh -c
это оболочка по умолчанию, эта «форма оболочки» RUN переводится какRUN ["/bin/sh", "-c", "/bin/bash" "-c" "source /usr/local/bin/virtualenvwrapper.sh"]
. Вы должны пойти дальше и использовать «исполнительную форму» RUN, чтобы вы могли убратьsh
вот такRUN ["/bin/bash" "-c" "source /usr/local/bin/virtualenvwrapper.sh"]
bash
вложенные вsh
и поэтому следует избегать.Оригинальный ответ
Это должно работать для каждого базового образа докера Ubuntu. Я обычно добавляю эту строку для каждого Dockerfile, который я пишу.
Редактировать заинтересованным свидетелем
Если вы хотите получить эффект «использовать
bash
вместоsh
всего этого Dockerfile», не изменяя и не повреждая * ОС внутри контейнера, вы можете просто сообщить Docker о своем намерении . Это делается так:Более подробно в этом ответе ниже. https://stackoverflow.com/a/45087082/117471
источник
ln -snf /bin/bash /bin/sh
sh
наbash
ln -s /bin/bash /bin/sh
это ужасная идея Ubuntu целевых / bin / sh, чтобы разбить по причине. dash - это полностью posix-оболочка, которая на несколько порядков быстрее, чем bash. ссылка / bin / sh на bash резко снизит производительность вашего сервера. Цитироватьsh
оболочкой, но вы хотитеbash
, правильное решение - этоsh
вызвать процессbash
как однократный, напримерbash -c 'source /script.sh && …'
, или вы могли бы даже пойти так далеко, чтобы полностью избежать бешизмов (напримерsource
), и вместо этого выбрать только когда-либо использовать действительные эквиваленты POSIX, например. /script.sh
. (Запомните пробел после.
!) И наконец, если ваш скрипт исполняемый (а не только исходный), никогда не заставляйте ваш скрипт лежать с#!/bin/sh
шебангом, если он на самом деле не совместим с sh. Используйте#!/bin/bash
вместо этого.Оболочка по умолчанию для
RUN
обучения является["/bin/sh", "-c"]
.Используя инструкцию SHELL , вы можете изменить оболочку по умолчанию для последующих
RUN
инструкций в Dockerfile:Теперь оболочка по умолчанию изменилась, и вам не нужно явно определять ее в каждой инструкции RUN
Дополнительное примечание : Вы также можете добавить
--login
опцию, которая запускает оболочку входа в систему. Это означает,~/.bachrc
что, например, будет прочитано, и вам не нужно явно указывать его перед вашей командойисточник
--login
- только что сам понялSHELL ["/bin/bash", "-c", "-l"]
я смог использовать дополнительные обновления для файла .bashrc, что позволило мне легко запускать команды asdf.У меня была такая же проблема, и для выполнения установки pip внутри virtualenv мне пришлось использовать эту команду:
Я надеюсь, что это помогает.
источник
RUN /bin/bash -c "source /opt/ros/melodic/setup.bash && \ cd /home && \ git clone https://angelos.p:$password@gitlab.com/inno/grpc-comms.git && \ cd grpc-comms && \ mkdir build && \ cd build && \ cmake .. && make"
Самый простой способ - использовать оператор точки вместо источника, который является эквивалентом команды bash
source
:Вместо того:
Использование:
источник
.
/source
также принимает позиционные параметры после имени файлаsource
или.
теряются при завершении команды RUN. См .: stackoverflow.com/a/40045930/19501Если вы используете Docker 1.12 или новее, просто используйте
SHELL
!Короткий ответ:
Общее:
для питона vituralenv:
Длинный ответ:
со страницы https://docs.docker.com/engine/reference/builder/#/shell
источник
Основываясь на ответах на этой странице, я хотел бы добавить, что вы должны знать, что каждое утверждение RUN выполняется независимо от других с
/bin/sh -c
и, следовательно, не получит никаких переменных среды, которые обычно были бы получены в оболочках входа в систему.Наилучший способ, который я нашел на данный момент, - добавить скрипт
/etc/bash.bashrc
и затем вызвать каждую команду как bash login.Например, вы можете установить и настроить virtualenvwrapper, создать виртуальную среду, активировать ее при использовании входа в систему bash, а затем установить модули python в эту среду:
Чтение руководства по загрузочным файлам bash помогает понять, когда это происходит.
источник
ADD env-file /etc/profile.d/installerenv.sh
RUN /bin/bash --login -c 'env'
RUN /bin/bash -c 'rm /etc/profile.d/installerenv.sh'
если один из вариантов использования добавляет дополнительные переменные среды ввода в перспективу сборки Docker, как я сделал, я бы порекомендовал взглянуть на docs.docker.com/compose/yml. / # env-файл тоже.RUN
команды, а это значит, что вы не можете установить множество зависимостей проекта, а затем скопировать исходный код и воспользоваться преимуществами Кэширование промежуточных шагов докера. Он будет переустанавливать все зависимости проекта каждый раз./etc/bashrc
для Redhat, а не/etc/bash.bashrc
как указано выше (для Ubuntu)Согласно https://docs.docker.com/engine/reference/builder/#run оболочка [Linux] по умолчанию для
RUN
is/bin/sh -c
. Вы, кажется, ожидаете bashisms, поэтому вы должны использовать "exec форму",RUN
чтобы указать вашу оболочку.В противном случае использование «формы оболочки» RUN и указание другой оболочки приводит к появлению вложенных оболочек.
Если у вас более одной команды, для которой требуется другая оболочка, вам следует прочитать https://docs.docker.com/engine/reference/builder/#shell и изменить оболочку по умолчанию, поместив ее перед командами RUN:
Наконец, если вы поместили в
.bashrc
файл пользователя root что-то, что вам нужно, вы можете добавить-l
флаг к командеSHELL
or,RUN
чтобы сделать его оболочкой входа в систему и убедиться, что он получен.Примечание: я намеренно проигнорировал тот факт, что бессмысленно указывать скрипт как единственную команду в RUN.
источник
SHELL ["/bin/sh", "-c", "-l"]
поэтому он/bin/sh
не решит проблему неиспользования bash. Кроме того, при выполненииdocker build
операции вряд ли будет что-то полезное в .bashrc пользователя root, которое вам нужно. Но, если вы поместите что-то там ранее в Dockerfile (например, возможноJAVA_HOME
, тогда да. Я добавлю примечание об этом в своем ответе.Согласно документации Docker
См. Https://docs.docker.com/engine/reference/builder/#run.
источник
Если у вас есть
SHELL
доступ, вы должны пойти с этим ответом - не используйте принятый ответ , который заставляет вас поместить остальную часть файла docker в одну команду для каждого комментария .Если вы используете старую версию Docker и не имеете доступа
SHELL
, это будет работать до тех пор, пока вам ничего не понадобится.bashrc
(что является редким случаем в Dockerfiles):Обратите внимание, что
-i
bash необходим для чтения rcfile.источник
Вы могли бы хотеть бежать
bash -v
чтобы увидеть, что происходит.Я бы сделал следующее вместо того, чтобы играть с символическими ссылками:
RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc
источник
У меня тоже были проблемы с бегом
source
в DockerfileЭто прекрасно работает для построения контейнера CentOS 6.6 Docker, но вызывает проблемы в контейнерах Debian
Это то, как я решил, может быть, это не элегантный способ, но это то, что сработало для меня
источник
Это может произойти, потому что
source
это встроенный в bash, а не двоичный файл где-то в файловой системе. Вы планируете использовать сценарий для изменения контейнера позже?источник
Я закончил тем, что положил свои вещи в env
.profile
иSHELL
что-то вродеисточник
Если вы просто пытаетесь использовать pip для установки чего-либо в virtualenv, вы можете изменить окружение PATH, чтобы сначала просмотреть папку bin в virtualenv.
ENV PATH="/path/to/venv/bin:${PATH}"
Затем любые
pip install
команды, которые следуют в Dockerfile, сначала найдут / path / to / venv / bin / pip и будут использовать его, что установит в этот virtualenv, а не в системный питон.источник