Dockerのコンテナを実行可能ファイルのように使う

dockerコンテナを実行可能ファイルとして扱う。

やりたいこと

docker run <IMAGE_NAME> paramsで単一の処理を行いたいということです。docker hubでよくある形式だと思います。サーバやCLIなどでよく見る実行方法ですね。

docker runの後ろにpython ...などを書くのは面倒なので、これを使ってみたいなと思った次第です。

自分の場合では、pythonファイルの実行を行いたいので、pythonを使って実践してみることにしました。

すること

DockerfileENTRYPOINTCMDを使えばできます。実験では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が渡れば対応したメッセージが表示されます。

何が起きているか

ENTRYPOINTCMDが両方指定されているとき、CMDENTRYPOINTの引数として機能します。そのため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で引数を渡すとどうなるか調べました。

Dockerfilemain.pyは先ほどと同じものを利用しています。(CMDENTRYPOINTに置換しただけです):

$ 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アソシエイト

Bitly

コメント

タイトルとURLをコピーしました