私は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 login Shellのようにbashの違いにあるかのように見えました。 _、およびダッシュ、Ubuntu システムシェル、ダッシュsource
コマンドをサポートしていません。
しかし、これに対する答えはsource
の代わりに '。'を使用することであるように見えますが、これは単にDockerランタイムをゴーパニックで爆発させます例外。
これを回避するためにDockerfile RUN命令からシェルスクリプトを実行するための最善の方法は何ですか(Ubuntu 12.04 LTSのデフォルトのベースイメージから実行しています)。
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に対してこの行を追加します。
alteringやを使わずに、「このDockerfile全体でbash
の代わりにsh
を使う」という効果を得たい場合は*コンテナの中のOS、あなたは Dockerにあなたの意図を伝えることができます 。それはこんな感じです:
Shell ["/bin/bash", "-c"]
*考えられる被害は、Linuxのmanyscripts(新鮮なUbuntuインストールで
grep -rHInE '/bin/sh' /
が2700以上の結果を返す)が/bin/sh
で完全にPOSIXシェルを期待することです。 bashシェルはPOSIXと追加の組み込み関数だけではありません。 POSIXのものとは完全に異なる振る舞いをする(そしてそれ以上の)組み込み関数があります。私は完全にPOSIXを避け(そしてあなたが他のシェルでテストしなかったどんなスクリプトもあなたが基本主義を避けたと思うのでうまくいくだろうという誤謬)そして単にバシズムを使うことを支持する。しかし、あなたはそれをあなたのスクリプトの中の適切なShebangで行います。 OS全体の下からPOSIXシェルを引き出すのではありません。 (Linuxに付属している2700以上のスクリプトすべてと、インストールしたパッケージ内のすべてのスクリプトを確認する時間がない限り)
この回答の詳細は下記をご覧ください。 https://stackoverflow.com/a/45087082/117471
私は同じ問題を抱えていて、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"
助けになれば幸いです。
最も簡単な方法は、sourceの代わりにドット演算子を使用することです。これは、bash source
コマンドと同じshです。
の代わりに:
RUN source /usr/local/bin/virtualenvwrapper.sh
つかいます:
RUN . /usr/local/bin/virtualenvwrapper.sh
RUN
命令のデフォルトのシェルは["/bin/sh", "-c"]
です。
RUN "source file" # translates to: RUN /bin/sh -c "source file"
シェル命令 を使用して、Dockerfileの後続のRUN
命令のデフォルトシェルを変更できます。
Shell ["/bin/bash", "-c"]
これで、デフォルトのシェルが変更され、すべてのRUN命令で明示的に定義する必要がなくなりました。
RUN "source file" # now translates to: RUN /bin/bash -c "source file"
追加の注意事項:ログインシェルを開始する--login
オプションを追加することもできます。これは例えば~/.bachrc
が読まれることを意味します、そしてあなたはあなたのコマンドの前にそれを明示的に供給する必要はありません。
このページの答えを基にして、各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起動ファイル のマニュアルを読むと、何がいつ提供されるのかを理解するのに役立ちます。
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命令は、Shell形式のコマンドに使用されるデフォルトのShellをオーバーライドすることを可能にします。 Linuxのデフォルトのシェルは["/ bin/sh"、 "-c"]で、Windowsのデフォルトのシェルは["cmd"、 "/ S"、 "/ C"]です。シェル命令はDockerfileにJSON形式で記述する必要があります。
Shell命令は、cmdとpowershellの2つの一般的に使用されているまったく異なるネイティブシェル、およびshを含む利用可能な代替シェルがあるWindowsで特に便利です。
シェル命令は複数回現れることがあります。各シェル命令は、以前のすべてのシェル命令をオーバーライドし、後続のすべての命令に影響を与えます。例えば:
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をRock、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コマンドを追加する必要があります。
これをより効率的にするために、2つのメカニズムのうちの1つを使用することができる。 1つは、JSON形式のRUNコマンドを使用することです。
... RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 \"c:\\foo.txt\""] ...
JSON形式はあいまいさがなく、不要なcmd.exeを使用していませんが、二重引用符とエスケープによる冗長性が必要です。代替のメカニズムは、特にエスケープパーサーディレクティブと組み合わせたときに、シェル命令とシェルフォームを使用して、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>
シェル命令はまた、シェルが動作する方法を修正するためにも使用され得る。たとえば、WindowsでShell cmd/S/C/V:ON | OFFを使用すると、遅延環境変数展開セマンティクスを変更できます。
Zsh、csh、tcshなどの代替シェルが必要な場合は、シェル命令をLinuxでも使用できます。
シェル機能はDocker 1.12で追加されました。
https://docs.docker.com/engine/reference/builder/#run によると、RUN
のデフォルトの[Linux]シェルは/bin/sh -c
です。あなたはバシズムを期待しているように見えるので、あなたのシェルを指定するためにRUN
の "exec形式"を使うべきです。
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
ファイルに配置した場合は、Shell
またはRUN
コマンドに-l
フラグを追加して、それをログインシェルにして、確実にソースにすることができます。
注:スクリプトをRUN内の唯一のコマンドとして使用するのは無意味であるという事実を意図的に無視しました。
Dockerのドキュメントによると
/ bin/sh以外の別のシェルを使用するには、目的のシェルを渡したexecフォームを使用します。例えば、
RUN ["/bin/bash", "-c", "echo hello"]
https://docs.docker.com/engine/reference/builder/#run を参照してください。
Dockerfileでsource
を実行する際にも問題がありました
これは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
これは、source
がファイルシステム上のどこかにあるバイナリではなく、bashに組み込まれているために起こります。あなたがソースとなっているスクリプトが後でコンテナを変更することを意図していますか?
何が供給されているのかを見るためにbash -v
を実行したいと思うかもしれません。
シンボリックリンクで遊ぶ代わりに、次のようにします。
RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc
Pipを使ってvirtualenvに何かをインストールしようとしているのであれば、まずPATH envを変更してvirtualenvのbinフォルダーを調べます。
ENV PATH="/path/to/venv/bin:${PATH}"
それから、Dockerfileに続くpip install
コマンドは、最初に/ path/to/venv/bin/pipを見つけてそれを使用します。これはシステムpythonではなくそのvirtualenvにインストールされます。
私は自分の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