dockerコンテナを実行可能ファイルとして扱う。
やりたいこと
docker run <IMAGE_NAME> paramsで単一の処理を行いたいということです。docker hubでよくある形式だと思います。サーバやCLIなどでよく見る実行方法ですね。
docker runの後ろにpython ...などを書くのは面倒なので、これを使ってみたいなと思った次第です。
自分の場合では、pythonファイルの実行を行いたいので、pythonを使って実践してみることにしました。
すること
DockerfileでENTRYPOINTとCMDを使えばできます。実験ではpythonは引数の表示だけさせます。
ENTRYPOINTとCMDの両方を指定する
引数に何もしないときはヘルプメッセージを表示して、適切な引数を指定したときは適切な処理を行います。
Dockerfileを次にようにします:
FROM python:alpine
COPY main.py /etc/src/main.py
WORKDIR /etc/src/
CMD [ "--help" ]
ENTRYPOINT [ "python", "main.py" ]
こうすることで、docker run --rm <IMAGE_NAME>ではヘルプが表示されます。
main.pyは実験では以下のようなとてもシンプルなものです:
from sys import argv
print(argv);
実際はargparseを使うので、--helpが渡れば対応したメッセージが表示されます。
何が起きているか
ENTRYPOINTとCMDが両方指定されているとき、CMDはENTRYPOINTの引数として機能します。そのためENTRYPOINTで["python", "main.py"]を指定して、CMDで["--help"]を指定しているわけです。
一方で、docker run --rm <IMAGE_NAME> tekisetsuなどで起動すれば、CMDのヘルプの引数--helpは上書きされて、ENTRYPOINTの引数にはtekisetsuが渡されて期待通りの動作をします。
$ docker run --rm -it <image_name>
['main.py', '--help']
$ docker run --rm -it sugukesu tekisetsu
['main.py', 'tekisetsu']
このような出力になります。
片方だけ指定する場合
片方だけ設定した場合について調べたので、下に結果をまとめておきます。
CMDだけ指定するとき
CMD ["python", "main.py"]だけ定義して、ENTRYPOINTを定義しないとき、docker runで引数を渡すとどうなるか調べました。
pythonにはargvだけ出力させました:
$ docker run --rm -it <image_name>
['main.py']
$ docker run --rm -it <image_name> foobar
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"foobar\": executable file not found in $PATH": unknown.
となり、docker runで引数を与えると、CMDを上書きすることがわかります。この場合では、存在しないファイルfoobarを実行してエラーが発生しています。
ENTRYPOINTだけ指定するとき
今度はENTRYPOINT ["python", "main.py"]だけを定義して、CMDを定義しないとき、docker runで引数を渡すとどうなるか調べました。
Dockerfileとmain.pyは先ほどと同じものを利用しています。(CMDをENTRYPOINTに置換しただけです):
$ docker run --rm -it <image_name>
['main.py']
$ docker run --rm -it <image_name> foo
['main.py', 'foo']
$ docker run --rm -it <image_name> foo bar
['main.py', 'foo', 'bar']
$ docker run --rm -it <image_name> "foo bar"
['main.py', 'foo bar']
ENTRYPOINTの後ろに引数が追加されていくことがわかります。
エントリポイントの名称の通りの動作だと実感できます。確実に実行されるexcutableだということですね。
おわり
引数を["aa", "bb", ...]のように指定するexec形式と呼ばれる指定方法を前提にしていました。これが推奨されている記述方法であり、他の方法では/bin/bash -cに渡されて起動したりするようなので、場合によっては想定外の動作をすると思います。
日本語化してあるドキュメントに助けられました: Dockerfile リファレンス — Docker-docs-ja 20.10 ドキュメント
実際に色々変えて動かしてみるって大事ですね。思ったよりENTRYPOINTがエントリポイントになっていて、よくできているなと感じます。
以上です。
Amazonアソシエイト



コメント