'source'を指定したDockerfileでRUN命令を使用しても機能しない


274

バニラのpython環境をインストールするためにまとめているDockerfileがあります(そこにアプリをインストールしますが、後日インストールします)。

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]

私は喜んで、その後のアクセスをここからスクリプトを実行し、することができworkonmkvirtualenvなど

私はいくつかの掘削を行ってきた、と問題が違いにあるかもしれないかのように、最初はそれが見えたbashの Ubuntuのようログインシェル、およびダッシュのUbuntuなどのシステムシェルダッシュをサポートしていないsourceコマンドを。

ただし、これに対する答えは「。」を使用することです。の代わりにsource、これによりDockerランタイムがgo panic例外で爆発するだけです。

これを回避するためにDockerfile RUN命令からシェルスクリプトを実行する最良の方法は何ですか(Ubuntu 12.04 LTSのデフォルトのベースイメージで実行しています)。


2
したがって、「ソース」せずに、コマンドを実行してください。または、具体的には「bash」を使用してシェルスクリプトを実行します。
Alister Bulman

それを試しました-スクリプトは失敗しませんが、私が望んでいたさまざまなコマンドにアクセスできません。この問題は同じものです-github.com/dotcloud/docker/issues/2847
Hugo Rodger-Brown

2
それについて考えると、どちらが正しいのでしょう。Virtualenvwrapperはおそらくコンテナー環境では意味がありません。私はそれをバックアウトし、代わりに「ネイティブ」virtualenvを使用します。
Hugo Rodger-Brown

1
これに取り組むためのより基本的な方法は、stackoverflow.com
questions / 4732200

試してみるCMD source activate django-py35
Belter

回答:


315

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


67
え?コマンドに対してのみ存在するシェル内のスクリプトをソースとする場合、そのアクションの合計が環境変数を設定していると仮定すると、今後実行されるコマンドに永続的な影響を与えることはできません。なぜあなたは使用するsource対だけで、まったくbash /usr/local/bin/virtualenvwrapper.shその場合には、?
Charles Duffy

13
RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh; my_command; my_command; my_command;"
2016

29
これは機能していますが、正しくありません。docs.docker.com/engine/reference/builder/#runを読み、2番目のコードサンプルの後に停止しないでください。すぐ後に続くを読んでください/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"]
ブルーノBronosky

8
これがネストされたを作成する理由を理解するために、stackoverflow.com / a / 45087082/117471を参照してください。したがって、回避する必要があります。bashsh
ブルーノブロノスキー2017

4
より良い答えはここにあります:stackoverflow.com/a/42216046/1663462
Chris Stryczynski

150

元の回答

FROM ubuntu:14.04
RUN rm /bin/sh && ln -s /bin/bash /bin/sh

これは、すべてのUbuntu Dockerベースイメージで機能します。通常、この行を、作成するすべてのDockerfileに追加します。

関係者による編集

コンテナー内のOS を変更したり損傷を与えたりせずに、「このDockerfile全体bashではなく使用する」という効果を得たい場合は、Dockerに意図を伝えることができます。それはそのように行われます:sh

SHELL ["/bin/bash", "-c"]

*可能性のある損傷は、Linuxの多くのスクリプト(Ubuntuの新規インストールgrep -rHInE '/bin/sh' /で2700以上の結果が返される)がで完全にPOSIXシェルを期待すること/bin/shです。bashシェルは、POSIXと追加のビルトインだけではありません。POSIXとはまったく異なる動作をする組み込み(およびそれ以上)があります。私はPOSIXを回避し(そして、他のシェルでテストしなかったスクリプトが誤解を回避したと考えているため機能する)、そしてバシズムを使用することを完全にサポートします。しかし、スクリプトの適切なシバンでそれを行います。OS全体からPOSIXシェルを引き出すのではありません。(Linuxに付属する2700以上のすべてのスクリプトと、インストールするパッケージ内のすべてのスクリプトを確認する時間がない場合)

以下のこの回答の詳細。https://stackoverflow.com/a/45087082/117471


18
これは少し簡略化できます:ln -snf /bin/bash /bin/sh
apottere

2
@ user1442219これにより、デフォルトのコマンドインタープリターがshto から置き換えられますbash
Bhargav Nanekalva '19年

27
ln -s /bin/bash /bin/shこれはひどい考えです。ubuntuは、理由により/ bin / shをダッシュ​​することをターゲットにしています。ダッシュはbashよりも桁違いに速い完全にposixのシェルです。/ bin / shをbashにリンクすると、サーバーのパフォーマンスが大幅に低下します。cite:wiki.ubuntu.com/DashAsBinSh
xero

7
これは汚いハックであり、解決策ではありません。あなたのスクリプトがすることによって実行されている場合はsh、シェルが、あなたがしたいbash、適切な解決策を持っているのいずれかであるshプロセスの呼び出しをbash一回限りの、例えばとしてbash -c 'source /script.sh && …'またはあなたも、これまで避けてbashisms(のようになど行くことができるsource代わりに、完全に)、および有効なPOSIXの同等物のみを使用することを選択します. /script.sh。(.!の後のスペースに注意してください。)最後に、スクリプトが実行可能である(単なるソースではない#!/bin/sh場合は、実際にsh互換でない場合は、スクリプトをシバンで横にしないでください。#!/bin/bash代わりに使用してください。
Mark G.

7
では、元の回答に反対票を投じ、「関係者」による編集に反対票を投じるにはどうすればよいですか。
スラバ

65

RUN命令のデフォルトのシェルは["/bin/sh", "-c"]です。

RUN "source file"      # translates to: RUN /bin/sh -c "source file"

SHELL命令を使用RUNすると、Dockerfileの後続の命令のデフォルトシェルを変更できます。

SHELL ["/bin/bash", "-c"] 

これで、デフォルトのシェルが変更され、すべてのRUN命令で明示的に定義する必要がなくなりました

RUN "source file"    # now translates to: RUN /bin/bash -c "source file"

追記--loginログインシェルを起動するオプションを追加することもできます。これは~/.bachrc、たとえば、読み取られ、コマンドの前に明示的にソースする必要がないことを意味します


1
使用に関する--login
優れた指針

1
使用するとSHELL ["/bin/bash", "-c", "-l"] 私は私が簡単に航空自衛隊のコマンドを実行することが許可さ.bashrcファイルに更なるアップデートを使用することができました。
Rowinson Gallego

46

同じ問題があり、virtualenv内でpip installを実行するために、次のコマンドを使用する必要がありました。

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"

お役に立てば幸いです。


あなたがROSの回答から来た場合、はい、それはうまくいきます。何か: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"
angelos.p

44

最も簡単な方法は、ソースの代わりにドット演算子を使用することです。これは、bash sourceコマンドと同等のshです。

の代わりに:

RUN source /usr/local/bin/virtualenvwrapper.sh

使用する:

RUN . /usr/local/bin/virtualenvwrapper.sh

「ソースはボーンシェルビルトインで あり、POSIXの「特別な」ビルトインです」-ss64.com/bash/source.html linux.die.net/man/1/sh ... . / sourceまた、ファイル名の後に位置パラメータを受け入れます
Wesターナー

5
各RUNコマンドは独立して機能するため、これは機能しません。変更しsourceたり.するときRUNコマンドが終了失われます。参照:stackoverflow.com/a/40045930/19501
amit

26

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"]です。SHELL命令は、DockerfileにJSON形式で書かれている必要があります。

SHELL命令は、一般的に使用される2つのまったく異なるネイティブシェル(cmdとpowershell、shを含む代替シェル)があるWindowsで特に役立ちます。

SHELL命令は複数回出現できます。各SHELL命令は、以前のすべてのSHELL命令をオーバーライドし、後続のすべての命令に影響します。例えば:

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で使用されている場合、SHELL命令の影響を受ける可能性があります:RUN、CMDおよびENTRYPOINT。

次の例は、Windowsで見られる一般的なパターンで、SHELL命令を使用して効率化できます。

...
RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
...

dockerによって呼び出されるコマンドは次のとおりです。

cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"

これは2つの理由で非効率的です。最初に、不要なcmd.exeコマンドプロセッサ(別名シェル)が呼び出されています。次に、シェル形式の各RUN命令には、コマンドの前に追加のpowershell -commandが必要です。

これをより効率的にするために、2つのメカニズムの1つを使用できます。1つは、次のようなRUNコマンドのJSON形式を使用することです。

...
RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 \"c:\\foo.txt\""]
...

JSONフォームはあいまいではなく、不要なcmd.exeを使用しませんが、二重引用符とエスケープによる冗長性が必要です。代替メカニズムは、SHELL命令とシェル形式を使用することです。これにより、特にエスケープパーサーディレクティブと組み合わせると、Windowsユーザーにとってより自然な構文になります。

# 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>

SHELL命令は、シェルの動作方法を変更するためにも使用できます。たとえば、WindowsでSHELL cmd / S / C / V:ON | OFFを使用すると、遅延した環境変数の展開セマンティクスを変更できます。

SHELL命令は、zsh、csh、tcshなどの代替シェルが必要な場合にLinuxでも使用できます。

SHELL機能はDocker 1.12で追加されました。


20

このページの回答に基づいて、各RUNステートメントが他のステートメントとは独立して実行されることに注意する必要があることを付け加えます。 /bin/sh -cされるため、通常はログインシェルでソースとなる環境変数を取得しないます。

これまでに見つけた最良の方法は、スクリプトをに追加して、/etc/bash.bashrc各コマンドをbashログインとして呼び出すことです。

RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc
RUN /bin/bash --login -c "your command"

たとえば、virtualenvwrapperをインストールしてセットアップし、仮想環境を作成し、bashログインを使用するときに仮想環境をアクティブにしてから、Pythonモジュールをこの環境にインストールします。

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スタートアップファイルのマニュアルを読むと、何がいつソースされるかを理解するのに役立ちます。


1
クール、私が説明しただけのソリューションに基づいて: 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-fileも。
daniel.kahlenberg 2015

1
これの問題は、各RUNコマンドの結果をキャッシュしないことにあると私は考えています。つまり、プロジェクトの依存関係の多くをインストールしてからソースコードをコピーして、次の利点を利用することができないということです。 Dockerの中間ステップキャッシング。毎回すべてのプロジェクトの依存関係を再インストールします。
erewok

上記の/etc/bashrc代わりにRedhatに使用/etc/bash.bashrc(Ubuntuの場合)
Jordan Gee

CentOSには/root/.bashrcを使用しました。
schmudu 2018

RUN echo "source /yourscript.bash" >> /etc/bash.bashrcがうまくいきます。docker内部でrosを使用していて、環境をセットアップしたい場合は、これを実行する必要があります
user27221

17

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"]

別のシェルを必要とする複数のコマンドがある場合は、https://docs.docker.com/engine/reference/builder/#shellを読み、RUNコマンドの前にこれを配置してデフォルトのシェルを変更する必要があります。

SHELL ["/bin/bash", "-c"]

最後に、必要なものをrootユーザーの.bashrcファイルに配置した場合は、-lフラグをSHELLor RUNコマンドに追加して、それをログインシェルにして、ソースが取得されるようにします。

注:RUNでの唯一のコマンドとしてスクリプトを入手しても意味がないという事実を意図的に無視しました。


1
SHELL ["/bin/sh", "-c", "-l"]したがって、ベースコンテナから環境設定がある場合は、〜/ .bashrcなどをソースにします
MortenB

1
@MortenB、しかし指定された(タイプされた?)/bin/shこれはbashが使用されない問題を解決しません。また、実行するときdocker buildに、rootユーザーの.bashrcに必要なものが役立つ可能性はほとんどありません。しかし、以前Dockerfileでそこに何かを置く場合には(多分のようなJAVA_HOME[はい、私は私の答えでそれについてのメモを入れます。。
ブルーノBronosky

タイプミスで申し訳ありませんが、私はpyenvを使用しています。これは〜/ .bashrcをソースとして使用して、ベースイメージに正しいpythonバージョンのパスを設定する必要があります。これにより、どのLinuxベースでも使用できるようになり、2行でpythonに任意のバージョンを追加します。基本pythonが3.5.2であるubuntu16.04のpython 3.7と同様
MortenB

11

Dockerドキュメントによると

「/ bin / sh」以外の別のシェルを使用するには、目的のシェルを渡すexecフォームを使用します。例えば、

RUN ["/bin/bash", "-c", "echo hello"]

https://docs.docker.com/engine/reference/builder/#runを参照してください


これが実際の正解です。選択した回答の作成者stackoverflow.com/a/25086628/117471は、リンク先のドキュメントの最初の例しか読んでいないようです。彼らはあなたが引用した次の段落を読んでいないようです。
Bruno Bronosky 2017

4

SHELL利用可能な場合は、この答えで行く必要があります- 受け入れられたものを使用しないでください。これにより、dockerfileの残りの部分をこのコメントごとに1つのコマンドに入れる必要があります。。

古いDockerバージョンを使用していて、へのアクセス権SHELLがない.bashrc場合、これは何も必要がない限り機能します(これはDockerfilesではまれなケースです)。

ENTRYPOINT ["bash", "--rcfile", "/usr/local/bin/virtualenvwrapper.sh", "-ci"]

-ibashにrcfileを読み込ませるために必要なことに注意してください。


3

bash -v何が供給されているかを確認するために実行したい場合があります。

私はシンボリックリンクで遊ぶ代わりに次のことをします:

RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc


3

ランニングにも問題があった sourceDockerfileました

これは、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

2

sourceはファイルシステムのどこかにバイナリではなくbashに組み込まれているため、これが発生している可能性があります。後でコンテナーを変更するために調達するスクリプトの意図はありますか?


1
スクリプトはコンテナを更新しますが、正直なところ、意味のないことをしようとしていたため、問題を回避しました。
Hugo Rodger-Brown

1

私は自分の環境を入れて、次のようなもの.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

3
"-c"は最後の引数である必要があります(実行される
command。の

0

pipを使用して何かをvirtualenvにインストールしようとしている場合は、PATH envを変更して、virtualenvのbinフォルダーを最初に確認できます。

ENV PATH="/path/to/venv/bin:${PATH}"

次にpip install、Dockerfileの後に続くコマンドは、最初に/ path / to / venv / bin / pipを見つけてそれを使用します。これにより、システムpythonではなく、virtualenvにインストールされます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.