あるコマンドラインプログラムを Docker コンテナとしてカプセル化して利用するといった手段の可能性について調べた。
コンテナが起動(実行)される際の処理について
指定するイメージからコンテナを動かした際に実行されるコマンド(プログラム)は、Dockerfile 内の定義として CMD
あるいは ENTRYPOINT
で指定することができる。両者の違いはドキュメントと、日本語で明確な解説が書かれた記事がわかりやすい。
両者は似ているようで微妙に違っていて、ENTRYPOINT
の内容変更は docker run 時の --entrypoint で指定するのに対して CMD
の方は docker run の引数であること、両者を指定するとコマンド実行が "ENTRYPOINT
CMD
" という解決が行われること、ということで CMD
の方を比較的カジュアルに差し替えることを想定しているように思われる。
従って今回のような内部でコマンドラインを実行する用途や目的で考えた場合 ENTRYPOINT
+ CMD
の組み合わせの上で、プログラムの実行パスを ENTRYPOINT
, そのプログラムに渡すオプションや引数を CMD
で指定するのが良さそう。
実験1: Ping サービス
ping を実行してその結果を返すサービスを提供するコンテナを考える。
次のような Dockerfile を用意した。
FROM busybox
ENTRYPOINT [ "ping" ]
CMD [ "--help" ]
このイメージから作られるコンテナを実行すると、引数を与えない限り ping --help
が実行されることになる。早速試してみる。
$ docker build -t ping-service .
$ docker run --rm ping-service
BusyBox v1.22.1 (2014-05-22 23:22:11 UTC) multi-call binary.
Usage: ping [OPTIONS] HOST
Send ICMP ECHO_REQUEST packets to network hosts
-c CNT Send only CNT pings
-s SIZE Send SIZE data bytes in packets (default:56)
-t TTL Set TTL
-I IFACE/IP Use interface or IP address as source
-W SEC Seconds to wait for the first response (default:10)
(after all -c CNT packets are sent)
-w SEC Seconds until ping exits (default:infinite)
(can exit earlier with -c CNT)
-q Quiet, only displays output at start
and when finished
(BusyBox とか出力されているので)Docker コンテナの中で ping --help
したであろう出力内容が表示された。ping-service を利用するには、HOST を指定しなければならないとわかる。
それでは HOST や OPTIONS を docker run 時に指定して再びサービスを実行してみる。
$ docker run --rm ping-service -c 5 google.com
PING google.com (216.58.220.238): 56 data bytes
64 bytes from 216.58.220.238: seq=0 ttl=61 time=23.672 ms
64 bytes from 216.58.220.238: seq=1 ttl=61 time=24.050 ms
64 bytes from 216.58.220.238: seq=2 ttl=61 time=23.656 ms
64 bytes from 216.58.220.238: seq=3 ttl=61 time=24.878 ms
64 bytes from 216.58.220.238: seq=4 ttl=61 time=24.027 ms
--- google.com ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 23.656/24.056/24.878 ms
今度は ping を実行した結果が出力された。オプション指定した -c 5 も正しく機能している。
実験2: ImageMagick サービス
続いて、ファイルを指定してファイルを出力するサービスの例として ImageMagick による画像変換を行う。
次のような Dockerfile を用意した。通常(何も指定しなかった場合)は --help を出力するのは先ほどと同じ。
FROM ubuntu:trusty
RUN apt-get update && apt-get install -y imagemagick
ENTRYPOINT [ "convert" ]
CMD [ "--help" ]
イメージを作ってコンテナを実行する。
実行時に渡す入力画像のファイルパス、および出力先となるファイルパスは Docker エンジンのホストではなくローカルマシン上にあるはずなので、Data volume としてローカルパスをそのままの内容でマウントする。こうすると同一パスが Docker エンジンホスト側にあると見なすことができる。
$ docker build -t imagemagick .
$ docker run --rm -v $PWD:$PWD imagemagick $PWD/image.png $PWD/image.jpg
この方法だと、入力ファイルと出力ファイルのディレクトリパスが異なる場合は当然ながらそれぞれのディレクトリを Data volume としてマウントする必要がある。
このようなシチュエーション下でより良い方法が知りたい。
備考
今回作成したようなサービス提供コンテナをベースにした拡張コンテナを作成する場合、その Dockerfile 内で ENTRYPOINT
, CMD
を定義すれば上書きされ、逆に定義しなければベース側の内容が採用される。普通に docker run する際に --entrypoint や引数を指定して ENTRYPOINT
, CMD
を上書きして実行しているのと同じといえる。