しょーもないことでハマってしまったのでお焚き上げ。
ハマったこと
FROM debian
ADD entrypoint.sh /
RUN chmod +x /entrypoint.sh
ENTRYPOINT /entrypoint.sh
#!/bin/bash
exec "$@"
よくある、シェルスクリプトを ENTRYPOINT に指定した Docker イメージ。(実際には exec "$@"
の前で何かしらの処理を実行することになる)
これを動かしてみるが、なんと動かない。
$ docker build . -t tmp
$ docker run -it tmp echo foo # 何も表示されない (本当は foo と表示されてほしい)
しかも何のエラーも出ないので困ってしまった。
ナンデ???
原因
Dockerfile の ENTRYPOINT の指定が shell 形式になっていたことが原因。
shell 形式と exec 形式
Dockerfile の ENTRYPOINT や CMD には shell 形式 (shell form) と exec 形式 (exec form) の二種類があって、どちらでもビルドはできるが実行のされ方が異なる。1
ENTRYPOINT /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
exec 形式は指定したコマンドと引数がそのまま実行されるが、shell 形式で指定した場合は /bin/sh -c
に渡される。
つまり、shell 形式で /entrypoint.sh
と指定した場合は以下と同じ振る舞いになる。
ENTRYPOINT ["/bin/sh", "-c", "/entrypoint.sh"]
なぜ shell 形式だと動かなかったか
shell 形式だと shell -c
に渡されるため、冒頭のやり方だと実行されるコマンドがこうなってしまう。
$ /bin/sh -c '/entrypoint.sh' echo foo
これでは /entrypoint.sh
プロセスに echo foo
というパラメータが渡らないので、echo foo
は実行されずに /bin/sh
プロセスは正常終了してしまう。
どうすればいいか
ENTRYPOINT や CMD は exec 形式で書こう。
FROM debian
ADD entrypoint.sh /
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
#!/bin/bash
exec "$@"
$ docker build . -t tmp
$ docker run --rm -it tmp echo foo
foo