Использование инструкции RUN в Dockerfile с 'source' не работает
у меня есть 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 команда я получаю ту же ошибку "не найден", что и выше. Однако, если я запускаю сеанс интерактивной оболочки, источник работает:
$ docker run 3a87 bash
source
bash: line 1: source: filename argument required
source: usage: source filename [arguments]
я могу запустить скрипт отсюда, а затем счастливо получить доступ workon,mkvirtualenv etc.
я немного покопался, и изначально казалось, что проблема может заключаться в разнице между Баш как Ubuntu login shell и тире как Ubuntu система оболочки, тире не поддерживает
14 ответов:
Оригинальный Ответ
FROM ubuntu:14.04 RUN rm /bin/sh && ln -s /bin/bash /bin/shэто должно работать для каждого базового образа Ubuntu docker. Я обычно добавляю эту строку для каждого Dockerfile, который я пишу.
редактировать заинтересованным свидетелем
если вы хотите получить эффект "использовать
bashвместоshна протяжении всего этого Dockerfile", без изменения и повреждения* ОС внутри контейнера, вы можете просто скажи докеру о своем намерении. Что делается так:SHELL ["/bin/bash", "-c"]* возможный ущерб заключается в том, что много скрипты в Linux (на новой Ubuntu install
grep -rHInE '/bin/sh' /возвращает более 2700 результатов) ожидайте полностью POSIX оболочки в/bin/sh. Оболочка bash-это не просто POSIX плюс дополнительные встроенные модули. Есть встроенные (и более), которые ведут себя совершенно иначе, чем в POSIX. Я полностью поддерживаю избегание POSIX (и заблуждение, что любой скрипт, который вы не тестировали на другой оболочке, будет работать, потому что вы думаю, вы избегали басмизмов) и просто использовали башизм. Но вы делаете это с надлежащим shebang в вашем сценарии. Не вытаскивая оболочку POSIX из - под всей ОС. (Если у вас нет времени, чтобы проверить все 2700 плюс скрипты, которые поставляются с Linux плюс все те, в каких пакетах вы устанавливаете.)более подробно в этом ответе ниже. https://stackoverflow.com/a/45087082/117471
У меня была та же проблема, и для выполнения установки pip внутри virtualenv мне пришлось использовать эту команду:
RUN pip install virtualenv virtualenvwrapper RUN mkdir -p /opt/virtualenvs ENV WORKON_HOME /opt/virtualenvs RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh \ && mkvirtualenv myapp \ && workon myapp \ && pip install -r /mycode/myapp/requirements.txt"Я надеюсь, что это помогает.
самый простой способ-использовать оператор точки вместо источника, который является эквивалентом sh bash :
вместо:
RUN source /usr/local/bin/virtualenvwrapper.shиспользование:
RUN . /usr/local/bin/virtualenvwrapper.sh
Регистрация команда оболочки. Оболочка по умолчанию в Linux - это ["/bin/sh","- c"]
RUN "source file" # translates to: RUN /bin/sh -c "source file"вы можете изменить оболочку по умолчанию с помощью
SHELLкакие изменения оболочки используются для последующихRUNинструкции в DockerfileSHELL ["/bin/bash", "-c"]теперь оболочка по умолчанию изменилась, и вам не нужно явно определять ее в каждой инструкции запуска
RUN "source file" # now translates to: RUN /bin/bash -c "source file"Дополнительная Информация: вы также можете добавить
--loginопция, которая запускает вход в систему ракушка. Это значит~/.bachrcнапример, будет прочитано, и вам не нужно явно указывать его перед вашей командой
основываясь на ответах на этой странице, Я бы добавил, что вы должны знать, что каждый оператор RUN работает независимо от других с
/bin/sh -cи поэтому не получит никаких vars среды, которые обычно были бы получены в оболочках входа.лучший способ, который я нашел до сих пор, это добавить скрипт в
/etc/bash.bashrcа затем вызвать каждую команду как bash login.RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc RUN /bin/bash --login -c "your command"вы могли бы, например, установить и настроить virtualenvwrapper, создать виртуальный env, иметь его активируйте, когда вы используете логин bash, а затем установите свои модули python в этот env:
RUN pip install virtualenv virtualenvwrapper RUN mkdir -p /opt/virtualenvs ENV WORKON_HOME /opt/virtualenvs RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc RUN /bin/bash --login -c "mkvirtualenv myapp" RUN echo "workon mpyapp" >> /etc/bash.bashrc RUN /bin/bash --login -c "pip install ..."чтение руководства по bash startup files помогает понять, что поступает при.
если вы используете Docker 1.12 или новее, просто используйте
SHELL!Короткий Ответ:
общие:
SHELL ["/bin/bash", "-c"]для python vituralenv:
SHELL ["/bin/bash", "-c", "source /usr/local/bin/virtualenvwrapper.sh"]Ответ:
от https://docs.docker.com/engine/reference/builder/#/shell
SHELL ["executable", "parameters"]инструкция SHELL позволяет использовать оболочку по умолчанию для формы оболочки команд, которые нужно переопределить. Оболочка по умолчанию в Linux есть ["/bin/sh", "- c"], а в Windows - ["cmd", "/S", "/C"]. оболочка инструкция должна быть написана в форме JSON в Dockerfile.
инструкция оболочки особенно полезна в Windows, где есть есть две часто используемые и совершенно разные собственные оболочки: cmd и powershell, а также альтернативные оболочки, доступные в том числе sh.
инструкция оболочки может появиться несколько раз. Каждая раковина инструкция переопределяет все предыдущие инструкции оболочки, и влияет на всех последующие инструкции. Например:
FROM microsoft/windowsservercore # Executed as cmd /S /C echo default RUN echo default # Executed as cmd /S /C powershell -command Write-Host default RUN powershell -command Write-Host default # Executed as powershell -command Write-Host hello SHELL ["powershell", "-command"] RUN Write-Host hello # Executed as cmd /S /C echo hello SHELL ["cmd", "/S"", "/C"] RUN echo helloследующие инструкции могут быть затронуты инструкцией оболочки когда форма оболочки из них используется в Dockerfile: RUN, CMD и Точка входа.
следующий пример-это общий шаблон, найденный в Windows, который может оптимизируйте с помощью инструкции оболочки:
... RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt" ...команда, вызываемая docker будет:
cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"это неэффективно по двум причинам. Во-первых, есть ненужное УМК.вызывается командный процессор exe (aka shell). Во-вторых, каждый запуск инструкция в форме оболочки требует дополнительной powershell-команды префикс команды.
чтобы сделать это более эффективным, можно использовать один из двух механизмов. Один заключается в использовании форма JSON в командной запустить например:
... RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 \"c:\foo.txt\""] ...в то время как форма JSON однозначна и не использует ненужный УМК.EXE-файл, он делает требуют большей детализации через двойное цитирование и убегающий. Альтернативный механизм заключается в использовании инструкции оболочки и оболочки форме, что делает более естественный синтаксис для пользователей Windows, особенно в сочетании с директивой escape parser:
# escape=` FROM microsoft/nanoserver SHELL ["powershell","-command"] RUN New-Item -ItemType Directory C:\Example ADD Execute-MyCmdlet.ps1 c:\example\ RUN c:\example\Execute-MyCmdlet -sample 'hello world'в результате:
PS E:\docker\build\shell> docker build -t shell . Sending build context to Docker daemon 4.096 kB Step 1/5 : FROM microsoft/nanoserver ---> 22738ff49c6d Step 2/5 : SHELL powershell -command ---> Running in 6fcdb6855ae2 ---> 6331462d4300 Removing intermediate container 6fcdb6855ae2 Step 3/5 : RUN New-Item -ItemType Directory C:\Example ---> Running in d0eef8386e97 Directory: C:\ Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 10/28/2016 11:26 AM Example ---> 3f2fbf1395d9 Removing intermediate container d0eef8386e97 Step 4/5 : ADD Execute-MyCmdlet.ps1 c:\example\ ---> a955b2621c31 Removing intermediate container b825593d39fc Step 5/5 : RUN c:\example\Execute-MyCmdlet 'hello world' ---> Running in be6d8e63fe75 hello world ---> 8e559e9bf424 Removing intermediate container be6d8e63fe75 Successfully built 8e559e9bf424 PS E:\docker\build\shell>инструкция оболочки также может быть использована для изменения способа, которым a оболочка работает. Например, с помощью оболочки cmd / S /C / V:ON/OFF on Windows, отложенная среда переменная семантика расширения может быть модифицированный.
инструкция оболочки также может быть использована в Linux, если альтернативный раковина необходима как zsh, csh, tcsh и другие.
функция оболочки была добавлена в Docker 1.12.
согласно документации Docker
чтобы использовать другую оболочку, отличную от’ /bin/sh', используйте форму exec, передающую в нужную оболочку. Например,
RUN ["/bin/bash", "-c", "echo hello"]
согласно https://docs.docker.com/engine/reference/builder/#run оболочка по умолчанию [Linux] для
RUN- это/bin/sh -c. Вы, кажется, ожидаете башизмов, поэтому вы должны использовать "форму exec"RUNуказать свою оболочку.RUN ["/bin/bash", "-c", "source /usr/local/bin/virtualenvwrapper.sh"]в противном случае использование "формы оболочки" RUN и указание другой оболочки приводит к вложенным оболочкам.
# don't do this... RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh" # because it is the same as this... RUN ["/bin/sh", "-c", "/bin/bash" "-c" "source /usr/local/bin/virtualenvwrapper.sh"]если у вас есть более 1 команды, которая нуждается в другой оболочке, вы должны прочитать https://docs.docker.com/engine/reference/builder/#shell и измените оболочку по умолчанию, поместив ее перед командами запуска:
SHELL ["/bin/bash", "-c"]наконец, если вы разместили что-либо в корневом пользователе
.bashrcфайл, который вам нужен, вы можете добавить-lфлагSHELLилиRUNкоманда, чтобы сделать его оболочкой входа и убедиться, что он получает источник.примечание: Я намеренно проигнорировал тот факт, что бессмысленно создавать сценарий как единственный команда в беге.
у меня также были проблемы с запуском
sourceв DockerfileЭто прекрасно работает для создания контейнера CentOS 6.6 Docker, но дало проблемы в контейнерах Debian
RUN cd ansible && source ./hacking/env-setupвот как я справился с этим, может быть, не элегантный способ, но это то, что сработало для меня
RUN echo "source /ansible/hacking/env-setup" >> /tmp/setup RUN /bin/bash -C "/tmp/setup" RUN rm -f /tmp/setup
вы, возможно, захотите, чтобы запустить
bash -vчтобы увидеть, что находится источник.Я бы сделал следующее вместо того чтобы играть с ссылки:
RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc
Это может происходить потому, что
sourceявляется встроенным в bash, а не двоичным где-то в файловой системе. Является ли ваше намерение для сценария, который вы ищете, изменить контейнер после этого?
Если вы просто пытаетесь использовать pip для установки чего-то в virtualenv, вы можете изменить путь env, чтобы сначала посмотреть в папке bin virtualenv
ENV PATH="/path/to/venv/bin:${PATH}"тогда любой
pip installкоманды, которые следуют в Dockerfile, сначала найдут /path/to/venv/bin/pip и используют это, что установит в этот virtualenv, а не в системный python.
Я закончил тем, что положил свои env вещи в
.profileи мутировалSHELLчто-то вродеSHELL ["/bin/bash", "-c", "-l"] # Install ruby version specified in .ruby-version RUN rvm install $(<.ruby-version) # Install deps RUN rvm use $(<.ruby-version) && gem install bundler && bundle install CMD rvm use $(<.ruby-version) && ./myscript.rb
Comments