Dockerfileのrun、cmd、entrypointの違い
1. 概要
Dockerfileでは、 run 、 cmd、、entrypointなどの命令が頻繁に発生します。 一見すると、これらはすべてコマンドの指定と実行に使用されます。 しかし、それらの違いは何ですか? そして、それらはどのように相互作用しますか?
このチュートリアルでは、これらの質問に答えます。 これらの各手順の機能と機能について説明します。 また、イメージの構築とDockerコンテナーの実行においてそれらがどのような役割を果たしているかについても見ていきます。
2. 設定
まず、スクリプト log-event.sh。を作成しましょう。ファイルに1行追加して、次のように出力します。
#!/bin/sh
echo `date` $@ >> log.txt;
cat log.txt;
それでは、簡単なDockerfileを作成しましょう。
FROM alpine
ADD log-event.sh /
さまざまなシナリオでlog.txtに行を追加することにより、スクリプトを利用します。
3. runコマンド
run 命令は、イメージをビルドするときに実行されます。 つまり、 run に渡されたコマンドは、新しいレイヤーの現在の画像の上で実行されます。 次に、結果が画像にコミットされます。 これが実際にどのように見えるか見てみましょう。
まず、Dockerfileにrun命令を追加します。
FROM alpine
ADD log-event.sh /
RUN ["/log-event.sh", "image created"]
次に、次のコマンドを使用してイメージを作成しましょう。
docker build -t myimage .
これで、 log.txtファイルを含むDockerイメージがあり、その中に imagecreated行が1つ含まれているはずです。 イメージに基づいてコンテナを実行して、これを確認しましょう。
docker run myimage cat log.txt
ファイルの内容を一覧表示すると、次のような出力が表示されます。
Fri Sep 18 20:31:12 UTC 2020 image created
コンテナを数回実行すると、ログファイルの日付が変更されていないことがわかります。 runステップは、コンテナーの実行時ではなく、イメージのビルド時で実行されるため、これは理にかなっています。
もう一度イメージを作成しましょう。 ログの作成時間は変更されていません。 これは、Dockerfileが変更されていない場合、Dockerが実行命令の結果をキャッシュするために発生します。 キャッシュを無効にする場合は、 –no-cacheオプションをビルドコマンドに渡す必要があります。
4. cmdコマンド
cmd命令を使用すると、コンテナーの起動時に実行されるデフォルトのコマンドを指定できます。Dockerfileにcmdエントリを追加して、どのように機能するかを見てみましょう。
...
RUN ["/log-event.sh", "image created"]
CMD ["/log-event.sh", "container started"]
イメージを作成したら、それを実行して出力を確認しましょう。
$ docker run myimage
Fri Sep 18 18:27:49 UTC 2020 image created
Fri Sep 18 18:34:06 UTC 2020 container started
これを複数回実行すると、 imagecreatedエントリが同じままであることがわかります。 ただし、コンテナはエントリを実行するたびに更新します。 これは、コンテナが起動するたびにcmdが実際にどのように実行されるかを示しています。
今回は、わずかに異なる dockerrunコマンドを使用してコンテナーを起動したことに注意してください。 以前と同じコマンドを実行するとどうなるか見てみましょう。
$ docker run myimage cat log.txt
Fri Sep 18 18:27:49 UTC 2020 image created
今回は、Dockerfileで指定されたcmdは無視されます。 これは、 dockerrunコマンドに引数を指定したためです。
次に進み、Dockerfileに複数のcmdエントリがある場合に何が起こるかを見てみましょう。 別のメッセージを表示する新しいエントリを追加しましょう。
...
RUN ["/log-event.sh", "image created"]
CMD ["/log-event.sh", "container started"]
CMD ["/log-event.sh", "container running"]
イメージをビルドしてコンテナを再度実行すると、次の出力が表示されます。
$ docker run myimage
Fri Sep 18 18:49:44 UTC 2020 image created
Fri Sep 18 18:49:58 UTC 2020 container running
ご覧のとおり、 コンテナが開始されましたエントリは存在せず、 実行中のコンテナは
5. エントリポイントコマンド
上で見たように、コンテナの起動時に引数を渡す場合、cmdは無視されます。 より柔軟性が必要な場合はどうなりますか? 追加されたテキストをカスタマイズして、 dockerrunコマンドの引数として渡したいとします。 この目的のために、を使用しましょう
Dockerfileのcmdエントリをentrypoint:に置き換えましょう。
...
RUN ["/log-event.sh", "image created"]
ENTRYPOINT ["/log-event.sh"]
次に、カスタムテキストエントリを提供してコンテナを実行しましょう。
$ docker run myimage container running now
Fri Sep 18 20:57:20 UTC 2020 image created
Fri Sep 18 20:59:51 UTC 2020 container running now
どのように見ることができますエントリポイントは次のように動作します cmd。
cmd と同様に、複数の entrypoint エントリの場合、最後のエントリのみが考慮されます。
6. cmdとエントリポイント間の相互作用
cmdとentrypointの両方を使用して、コンテナーの実行時に実行されるコマンドを定義しました。 次に、cmdとentrypointを組み合わせて使用する方法を見てみましょう。
そのようなユースケースの1つは、のデフォルト引数を定義することです。
...
RUN ["/log-event.sh", "image created"]
ENTRYPOINT ["/log-event.sh"]
CMD ["container started"]
それでは、引数を指定せずに、 cmd で指定されたデフォルトを使用して、コンテナーを実行してみましょう。
$ docker run myimage
Fri Sep 18 21:26:12 UTC 2020 image created
Fri Sep 18 21:26:18 UTC 2020 container started
選択した場合は、それらをオーバーライドすることもできます。
$ docker run myimage custom event
Fri Sep 18 21:26:12 UTC 2020 image created
Fri Sep 18 21:27:25 UTC 2020 custom event
注意すべき点は、シェル形式で使用した場合のentrypointの動作の違いです。 Dockerfileのentrypointを更新しましょう。
...
RUN ["/log-event.sh", "image created"]
ENTRYPOINT /log-event.sh
CMD ["container started"]
この状況で、コンテナーを実行すると、Dockerが dockerrunまたはcmdのいずれかに渡された引数を無視する方法がわかります。
7. 結論
この記事では、Docker命令の違いと類似点を確認しました: run 、 cmd、、entrypoint。 それらがどの時点で呼び出されるかを観察しました。 また、それらの使用法とそれらがどのように連携するかについても見てきました。