過去の記事からの続きです。
- ■はじめに
- ■RUNコマンドとCMD/ENTRYPOINTの違い
- ■RUNコマンド
- ■RUNコマンドの例
- ■CMDコマンドとENTRYPOINTの違い
- ■CMDコマンドとENTRYPOINTの併用時の挙動
- ■CMDコマンドとENTRYPOINTの使い分けについて
■はじめに
Dockerfileで指定するコマンドのうち、コマンド自体を実行するためにはRUN、CMD/ENTRYPOINTを利用します。
■RUNコマンドとCMD/ENTRYPOINTの違い
両者の違いは、以下の通りです。
【RUN】
イメージ作成時(=docker build時)に指定したコマンドが実行されます。
【CMD/ENTRYPOINT】
コンテナ開始時(=docker start時)/作成時(=docker run時)に実行されます。
■RUNコマンド
RUNコマンドの使いどころは、
・ソフトウェアのパッケージインストール
・ファイルコピー、変更
などです。
イメージ作成時に実行されるのがRUNコマンドのため、最初にDcokerイメージに仕込んでおきたい設定を行っておく際に利用します。
■RUNコマンドの例
RUNコマンドの書式は以下の通り2つあります。
① シェル形式(シェルを経由する)
② exec形式(シェルを経由しない)
シェルと記載しましたが、/bin/sh -c を利用したコマンド実行かどうか、ということです。
今回は上記②は割愛します。※個人的に①を使う機会の方が多いと思っているので。。。
■① シェル形式(シェルを経由する)
/var/tmp/cmdディレクトリの中に、Dockerfileが予め以下の通り作成済みとします。
この状態でdocker build(タグ名はtestとしました)を実行します。
Dockerイメージは以下の通り作成されます。
では、実際に今作成したDockerイメージを使ってUbuntuコンテナを作成します。
curlコマンドがインストールされた状態でUbuntuコンテナを起動することができています。
念のため、通常のUbuntuイメージを使ったUbuntuコンテナにはcurlコマンドは入ってないです。
■CMDコマンドとENTRYPOINTの違い
CMDもENTRYPOINTも、コンテナ開始時に実行されます。
大きな違いは以下の通りです。
【CMD】
docker run時に指定するコマンド(CMD)のデフォルト値をDockerfileのCMDのコマンド記載に変更します。
【ENTRYPOINT】
docker run時にコマンドの実行を強制します。
正直、上記の説明だけだとイメージも中々掴みづらいので、具体的な例を下記します。
■CMDの例
まずはCMDからです。
通常、UbuntuコンテナをUbuntuイメージから作成した場合、以下のように「COMMAND」列は/bin/bashになります。
UbuntuイメージのデフォルトのCMD実行が/bin/bashのため、
docker run時に特にコマンドを指定しない場合には、/bin/bashが起動されます。
Dockerイメージを確認するとUbuntu:latestの場合は以下の通り、5行目にデフォルトのCMD(/bin/bash) が指定されております。
では、Dockerfileを以下の通り作成してUbuntuコンテナ(Ubuntu1)を作成してみます。
少しわかりにくいですが、
最後のdocker ps -aコマンドの「COMMAND」列は"/bin/sh -c ping lo・・・"となっており、Dockerfileで記述したCMDの内容をデフォルトコマンドとして実行していることを意味します。
そのため、Ubuntu1コンテナにログインしpsコマンドを実行すると、シェル経由でpingコマンドが実行され続けていることがわかります。
余談ですが、/bin/sh -c ping localhostのプロセスをkillするとUbuntu1コンテナも停止します。(デフォルトコマンドが終了するとコンテナも終了するというDockerの仕様によるものです。)
プロセスID1 は/bin/sh -c ping localhostなのですが、プロセスID8がping localhostそのもののため、プロセスID8をkillしてみると、自動的にプロンプトがDockerホスト側に戻ります。
また、docker ps -aの結果もExitedとなっていることがわかります。
■CMDのまとめ
少し長くなりましたが、
Dockerfileで記述したCMDは、Dockerイメージで指定されているデフォルトのCMDを上書きします。
例外として、docker run時にコマンドを指定すると、DockerfileのCMD内容を更に上書きします。(cat /etc/*release*の実行はすぐに完了するため、Ubuntu1コンテナの起動もすぐに終了します。)
つまり、強弱関係は
DockerイメージのデフォルトのCMD<DockerfileのCMD<docker run時のコマンド指定
です。
■CMDの注意点
Dockerfileに記載するCMDコマンドは一つしか記載できません。
複数記載されていた場合には、最後のCMDのみが実行されます。
■ENTRYPOINTの例
CMDと考え方は一緒です。
ただし、ENTRYPOINTで指定した内容は基本的には上書きすることができません。
■ENTRYPOINTの注意点
Dockerfileに記載するENTRYPOINTは一つしか記載できません。
複数記載されていた場合には、最後のENTRYPOINTのみが実行されます。
■CMDコマンドとENTRYPOINTの併用時の挙動
CMDとENTRYPOINTが併用されているDockerfileの場合、
CMDの動作が若干変わります。
ENTRYPOINTにコマンド名、CMDにはENTRYPOINTで指定したコマンドの引数を記載致します。
docker ps -a の「COMMAND」列は想定通り、ping -c 100 localhostが実行されています。
■CMDコマンドとENTRYPOINTの使い分けについて
DockerfileのCMDの性質としてdocker run時のコマンド指定の方が強いというものがありました。
それを利用して、CMDには変数のような意味合いを持たせることができます。
例えば、
・docker run実行時に何も指定しなければlocalhostへのPing疎通を実施
・docker run実行時にping先を指定すれば、指定したping先に疎通を実施
のようなことができます。
下記では、docker run実行時に8.8.8.8を引数として指定している為、Dockerコンテナが実行される際にENTRYPOINTのコマンドと、この引数(8.8.8.8)を合わせたコマンドを実行するDockerコンテナが生成されることになります。
以上です。