tl;dr
Docker イメージをビルドする際に、--build-arg
に指定した条件に応じて、処理を変えたかったので試行錯誤してみました。
Dockerfile 例
以下のような Dockerfile があったとする。
FROM alpine # 条件 A の時 ADD scripts/test1.sh /tmp/test.sh # 条件 B の時 ADD scripts/test2.sh /tmp/test.sh # /tmp/test.sh を実行 RUN /tmp/test.sh
- 条件
test1
の時 (--build-arg TEST_ARG=test1
) には、test1.sh
を/tmp/test.sh
にADD
したい - 条件
test2
の時 (--build-arg TEST_ARG=test2
) には、test2.sh
を/tmp/test.sh
にADD
したい - 最後に
/tmp/test.sh
を実行する
各スクリプトは以下のような内容。
$ cat scripts/test1.sh #!/bin/sh echo "test1" $ cat scripts/test2.sh #!/bin/sh echo "test2"
先述の Dockerfile をそのまま実行すると、以下のように出力される。
$ docker build --no-cache=true --tag test-build . Sending build context to Docker daemon 5.632kB Step 1/4 : FROM alpine ---> a24bb4013296 Step 2/4 : ADD scripts/test1.sh /tmp/test.sh ---> 0a4e47647476 Step 3/4 : ADD scripts/test2.sh /tmp/test.sh ---> 7cac3bdbf5f7 Step 4/4 : RUN /tmp/test.sh ---> Running in d2b82c5d3aef test2 Removing intermediate container d2b82c5d3aef ---> 3ebafdf8e1ec Successfully built 3ebafdf8e1ec Successfully tagged test-build:latest
さて、どうしようか。
試行錯誤 (1) シェルスクリプトに手をいれる
それぞれのシェルスクリプトを結合して、以下のような内容に修正。
$ vim scripts/tests.sh #!/bin/sh if [ "${TEST_ARG}" = "test1" ];then echo "test1" else echo "test2" fi
Dockerfile を以下のように修正。
FROM alpine ARG TEST_ARG ADD scripts/tests.sh /tmp/test.sh RUN /tmp/test.sh
実行してみる。
# TEST_ARG=test1 $ docker build --build-arg TEST_ARG=test1 --no-cache=true --tag test-build . Sending build context to Docker daemon 5.632kB Step 1/4 : FROM alpine ---> a24bb4013296 Step 2/4 : ARG TEST_ARG ---> Running in 6bee4b0a77d4 Removing intermediate container 6bee4b0a77d4 ---> 18791606eb7d Step 3/4 : ADD scripts/tests.sh /tmp/test.sh ---> 2ef0dc18c220 Step 4/4 : RUN /tmp/test.sh ---> Running in 1bdcf49a1b3f test1 Removing intermediate container 1bdcf49a1b3f ---> b44ffe9d5479 Successfully built b44ffe9d5479 Successfully tagged test-build:latest # TEST_ARG=test2 $ docker build --build-arg TEST_ARG=test2 --no-cache=true --tag test-build . Sending build context to Docker daemon 5.632kB Step 1/4 : FROM alpine ---> a24bb4013296 Step 2/4 : ARG TEST_ARG ---> Running in 0dcfd7ce440f Removing intermediate container 0dcfd7ce440f ---> 5383560dc479 Step 3/4 : ADD scripts/tests.sh /tmp/test.sh ---> 4827a378a33c Step 4/4 : RUN /tmp/test.sh ---> Running in 061058c84bac test2 Removing intermediate container 061058c84bac ---> cef33b3ef95d Successfully built cef33b3ef95d Successfully tagged test-build:latest
一応、意図した挙動になっている。
念の為、docker history
で確認する。
$ docker build --build-arg TEST_ARG=test1 --no-cache=true --tag test-build . $ docker history test-build IMAGE CREATED CREATED BY SIZE COMMENT 00b3da2b79ae 3 seconds ago |1 TEST_ARG=test1 /bin/sh -c /tmp/test.sh 0B 1d612168b8e3 4 seconds ago /bin/sh -c #(nop) ADD file:802b1103fc27ad8ee… 85B 32af95883761 4 seconds ago /bin/sh -c #(nop) ARG TEST_ARG 0B a24bb4013296 7 months ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B <missing> 7 months ago /bin/sh -c #(nop) ADD file:c92c248239f8c7b9b… 5.57MB
ただ、このパターンだと、シェルスクリプト (≒アプリケーション) に手を入れる必要があるし、インフラ側の都合をアプリケーション側に押し付けるような感じがする。
試行錯誤 (2) Dockerfile に手をいれる
シェルスクリプトには手を入れずに Dockerfile 内で完結したい場合、以下のように Dockerfile を修正した。
ARG TEST_ARG FROM alpine AS build_test1 ONBUILD ADD scripts/test1.sh /tmp/test.sh FROM alpine AS build_test2 ONBUILD ADD scripts/test2.sh /tmp/test.sh FROM build_${TEST_ARG} RUN /tmp/test.sh
マルチステージビルド を使う。
実行してみる。
# TEST_ARG=test1 $ docker build --build-arg TEST_ARG=test1 --no-cache=true --tag test-build . Sending build context to Docker daemon 5.632kB Step 1/7 : ARG TEST_ARG Step 2/7 : FROM alpine AS build_test1 ---> a24bb4013296 Step 3/7 : ONBUILD ADD scripts/test1.sh /tmp/test.sh ---> Running in 533fe2b2f259 Removing intermediate container 533fe2b2f259 ---> 354bf4f2c5b6 Step 4/7 : FROM alpine AS build_test2 ---> a24bb4013296 Step 5/7 : ONBUILD ADD scripts/test2.sh /tmp/test.sh ---> Running in 5dd2be2f59e8 Removing intermediate container 5dd2be2f59e8 ---> ef43e969bb08 Step 6/7 : FROM build_${TEST_ARG} # Executing 1 build trigger ---> 3454bad7d13f Step 7/7 : RUN /tmp/test.sh ---> Running in 0387de5f001c test1 Removing intermediate container 0387de5f001c ---> be4d9823b31a Successfully built be4d9823b31a Successfully tagged test-build:latest # TEST_ARG=test2 $ docker build --build-arg TEST_ARG=test2 --no-cache=true --tag test-build . Sending build context to Docker daemon 5.632kB Step 1/7 : ARG TEST_ARG Step 2/7 : FROM alpine AS build_test1 ---> a24bb4013296 Step 3/7 : ONBUILD ADD scripts/test1.sh /tmp/test.sh ---> Running in f481f96b5139 Removing intermediate container f481f96b5139 ---> 70758139a3f8 Step 4/7 : FROM alpine AS build_test2 ---> a24bb4013296 Step 5/7 : ONBUILD ADD scripts/test2.sh /tmp/test.sh ---> Running in c2f835a5bdfe Removing intermediate container c2f835a5bdfe ---> 6b435562e6b6 Step 6/7 : FROM build_${TEST_ARG} # Executing 1 build trigger ---> 6436710016c2 Step 7/7 : RUN /tmp/test.sh ---> Running in 364a63da9c54 test2 Removing intermediate container 364a63da9c54 ---> 16ab720a3284 Successfully built 16ab720a3284 Successfully tagged test-build:latest
念の為、docker history
で確認する。
$ docker build --build-arg TEST_ARG=test1 --no-cache=true --tag test-build . $ docker history test-build IMAGE CREATED CREATED BY SIZE COMMENT d664199dd041 3 seconds ago /bin/sh -c /tmp/test.sh 0B ecf320aaadc6 3 seconds ago /bin/sh -c #(nop) ADD file:1ab674a4350c46957… 24B 34b4004c7932 4 seconds ago /bin/sh -c #(nop) ONBUILD ADD scripts/test1… 0B a24bb4013296 7 months ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B <missing> 7 months ago /bin/sh -c #(nop) ADD file:c92c248239f8c7b9b… 5.57MB
なるほど。
TEST_ARG=test1
の条件でイメージが生成されていることが判る。
ということで
試行錯誤 (1) と試行錯誤 (2) のどちらが良いのか。
- 試行錯誤 (1) パターンは、イメージ生成に合わせて、アプリケーション (本記事ではシェルスクリプト) の改修が必要
- 試行錯誤 (2) パターンは、アプリケーションの改修は不要、ちょっと Dockerfile が長くなる
という理由で、個人的には、(2) が良いかな。