tl;dr
Alpine Linux な Docker イメージを利用して Dockerfile を認めた際, カジュアルに if eles
を使ったらちょっとハマったのでメモしておきます.
要件
- Alpine Linux なコンテナイメージを使う
- ビルド時の引数に
FOO=foo1
を渡す, 尚,FOO
の値はfooN
とN
の部分は連番となる - ビルド引数
FOO
がfoo*
の時とそれ以外で処理を分岐させる
Dockerfile
以下, サンプルの Dockerfile です.
FROM alpine ARG FOO ENV FOO=${FOO} RUN apk update && apk add bash RUN bash -c "if [[ ${FOO} =~ foo* ]]; then \ echo 'fooooooooooooooooooooooooooooooooo'; \ else \ echo 'No foo'; \ fi"
今回, 実は bash
をインストールしている点が肝です.
実際にビルドすると以下のような結果となります.
# --build-arg FOO=foo1000 の場合 $ docker build -t alpine-docker:sample . --build-arg FOO=foo1000 Sending build context to Docker daemon 3.072kB ... 略 ... ---> a10df44fcd50 Step 5/5 : RUN bash -c "if [[ ${FOO} =~ foo* ]]; then echo 'fooooooooooooooooooooooooooooooooo'; else echo 'No foo'; fi" ---> Running in 84ead69e85aa fooooooooooooooooooooooooooooooooo Removing intermediate container 84ead69e85aa ---> c6fea257b9c4 Successfully built c6fea257b9c4 Successfully tagged alpine-docker:sample # --build-arg FOO=bar $ docker build -t alpine-docker:sample . --build-arg FOO=bar --no-cache Sending build context to Docker daemon 3.072kB ... 略 ... Step 5/5 : RUN bash -c "if [[ ${FOO} =~ foo* ]]; then echo 'fooooooooooooooooooooooooooooooooo'; else echo 'No foo'; fi" ---> Running in 4a4ae9072ebb No foo Removing intermediate container 4a4ae9072ebb ---> be1603b0ba4b Successfully built be1603b0ba4b Successfully tagged alpine-docker:sample
いい感じです.
ハマったところ
今回, ハマった原因は if 文を使ったことというよりも, Bash でしか利用出来ない比較演算子を利用して正規表現比較をやろうとしたことでした.
if [[ ${FOO} =~ foo* ]]; then echo 'fooooooooooooooooooooooooooooooooo'; else echo 'No foo' fi
これですね.
Alpine Linux コンテナを素で起動した後, シェルは sh
又は ash
です. sh
も ash
も以下のように /bin/busybox
のシンボリックリンクです.
$ docker run --rm -t -i alpine ash / # which ash /bin/ash / # which sh /bin/sh / # ls -l /bin/ash lrwxrwxrwx 1 root root 12 Apr 23 06:25 /bin/ash -> /bin/busybox / # ls -l /bin/sh lrwxrwxrwx 1 root root 12 Apr 23 06:25 /bin/sh -> /bin/busybox
試しに上記のスクリプトを実行してみます.
/ # if [[ "foo" =~ foo* ]]; then > echo 'fooooooooooooooooooooooooooooooooo'; > else > echo 'No foo' > fi ash: =~: unknown operand No foo
ash: =~: unknown operand
となり正しい比較が出来ません...ちなみに, 以下のように書いても正しい比較が出来ません.
/ # if [[ "foo1" == foo* ]]; then > echo 'fooooooooooooooooooooooooooooooooo'; > else > echo 'No foo' > fi No foo
そうですね. Alpine Linux を利用する場合, 何も考えずにコマンドを並べると ash
の限定的な機能にハマる可能性があるということですね.
ちなみに, bash をインストールして確認してみました.
/ # apk add bash fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/main/x86_64/APKINDEX.tar.gz fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/community/x86_64/APKINDEX.tar.gz (1/4) Installing ncurses-terminfo-base (6.1_p20200118-r4) (2/4) Installing ncurses-libs (6.1_p20200118-r4) (3/4) Installing readline (8.0.1-r0) (4/4) Installing bash (5.0.11-r1) Executing bash-5.0.11-r1.post-install Executing busybox-1.31.1-r9.trigger OK: 8 MiB in 18 packages / # / # bash bash-5.0# bash-5.0# if [[ "foo1" == foo* ]]; then > echo 'fooooooooooooooooooooooooooooooooo'; > else > echo 'No foo' > fi fooooooooooooooooooooooooooooooooo bash-5.0# if [[ "foo1" =~ foo* ]]; then > echo 'fooooooooooooooooooooooooooooooooo'; > else > echo 'No foo' > fi fooooooooooooooooooooooooooooooooo
意図したような結果となりました.
以上
メモでした. そもそも, Dockerfile の中で if else
を使うことが正しいのかどうか判りませんが, 今後も多分ハマると思います.