タイトルは「実行可能な Docker イメージ」の間違いではありません。「実行可能な Dockerfile」で正解です。実行するとこのようにイメージのビルドが走ります:
chmod +x Dockerfile
./Dockerfile
仕掛けは単純で、シバンで docker build を呼び出しているだけです:
#!/usr/bin/env -S docker build . -f
# syntax=docker/dockerfile:1.5.0
FROM busybox
Dockerfile は # で始まる行がコメントとして扱われるため、1 行目のコメントとしてシバンを仕込めるわけですね。
env コマンドの -S オプションはシバン行で複数の引数を渡すのに使用されます。このオプションを付加しないと docker build . -f で 1 コマンド扱いとなり No such file or directory となります。
/usr/bin/env: `docker build . -f': そのようなファイルやディレクトリはありません
/usr/bin/env: shebang 行でオプションを渡すには -[v]S を使ってください
docker build の -f オプションは Dockerfile のパスを指定するものです。シバン行で指定されたインタプリタには実行されたファイルのパスが渡されるので、これを -f オプションで受けられる順番にしています。
syntax ディレクティブとの相性問題(解決済み)
このトリックは以前から使用可能だったのですが、syntax ディレクティブとの相性問題がありました。syntax ディレクティブは通常 1 行目にありますが、シバンを書くと 2 行目に移動してしまいます。この結果、Buildkit はその行を syntax ディレクティブではなく通常のコメントとして理解し、拡張構文が使用できない状態になってました。
この点について、2023-01-10 リリースの Dockerfile v1.5.0 で syntax ディレクティブの拡張が行われ、シバン行の次にある場合でも理解されるようになりました。同時に // syntax = ... や { "syntax": "..." } といった形式の表記も理解されるようになっています:
// DetectSyntax returns the syntax of provided input.
//
// The traditional dockerfile directives '# syntax = ...' are used by default,
// however, the function will also fallback to c-style directives '// syntax = ...'
// and json-encoded directives '{ "syntax": "..." }'. Finally, starting lines
// with '#!' are treated as shebangs and ignored.
//
// This allows for a flexible range of input formats, and appropriate syntax
// selection.
Buildkit には同日リリースの v0.11.0 でビルトインされ、Docker Engine には 2023-05-17 リリースの v24.0 で取り込まれました。
Dockerfile が実行可能であることのメリットは正直あまりないですが、タグ等 docker build に渡してほしいオプションを明示する際には使えそうです:
#!/usr/bin/env -S docker build --no-cache --progress plain --tag tag --build-arg KEY=build-time . -f
# syntax=docker/dockerfile:1.5.0
FROM busybox
ARG KEY
RUN echo $KEY
なお、ARG についてはこんなことをしなくても ARG KEY=value形式でデフォルト値を明示可能です。
