Использование инструкции 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 система оболочки, тире не поддерживает

926   14  

14 ответов:

RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh"

Оригинальный Ответ

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 инструкции в Dockerfile

SHELL ["/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

согласно 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

    Ничего не найдено.