16
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

DockerfileのRUNやCMDをBashのログインシェルで実行させる

Posted at

または、sdkman, rbenv, nvmなどのパッケージマネージャをDockerfileやコンテナで動かす方法について。

TL;DR

DockerfileのRUNがbashかつログインシェルで動いてほしいとき

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

DockerfileのCMDや、docker runに渡したコマンドがbashのログインシェルで動いてほしいとき

Dockerfile
RUN echo '#!/bin/bash\nexec /bin/bash -l -c "$*"' > /entrypoint.sh && \
    chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

経緯

諸事情でJava, Gradle, Ruby, Node.jsをそれぞれ指定されたバージョンでインストール済みのコンテナイメージを作る必要があった。
apt-getなどOS標準のパッケージマネージャで過去のバージョンを指定してインストールしたり、個別にインストールするのが面倒に感じたため、sdkman, rbenv, nvmといったバージョンマネージャをDockerfile内でインストールして使うことにした(いろいろあって結局使うのをやめたが……)。

しかしこれらのツールは、Dockerfile内ではうまく動作しなかった。
なぜならsdkmanなどのバージョンマネージャは

  • bashを前提としているものがある(関数やsourceコマンドなど)
  • .bashrcで初期化スクリプト(PATHの設定など)が実行される

つまり、動作にはbashかつログインシェルで実行される必要がある。一方、DockerfileのRUN命令はデフォルトで

  • /bin/sh -cの引数として実行される
  • bashでもログインシェルでもないため.bash_profile.bashrcが実行されない

解決策

SHELL命令を使うとDockerfile内のRUNがどのシェル+引数によって実行されるかを指定できる。

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

また、ENTRYPOINT命令でCMDdocker runに渡したコマンドを実行するプロセスを指定できる。これは以下のシェルスクリプトを実行させると大抵の場合うまくいくという結論に達した。

/entrypoint.sh
#!/bin/bash
exec /bin/bash -l -c "$*"
ENTRYPOINT ["/entrypoint.sh"]

ENTRYPOINTの指定について

上のentrypoint.shはずいぶん回りくどく感じると思うので、いくつか他にも試して問題があったケースを挙げておく。

SHELLと同じ指定をした場合

ENTRYPOINT ["/bin/bash", "-l", "-c"]

-cオプションが引数を1つしか受け取らないため、CMDdocker runでコマンドをまとめて1つの文字列として渡す必要があり、かなり面倒。

shebangでログインシェルを指定してexecだけで実行させた場合

/enrtypoint.sh
#!/bin/bash -l
exec $*

execコマンドの第1引数には実行ファイルを指定する必要があるため、関数やbash組み込みのコマンドが実行できない。
sdk, rbenv, nvmはそれぞれ関数として実装されているため実行できなかった。

16
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?