distroless なイメージでも envsubst が使いたい
本番環境向けのコンテナイメージを作成する際、イメージサイズやセキュリティを考慮して distroless
イメージを使うことがあります。
またコンテナイメージを作成する際、docker-entrypoint.sh
を作成してコンテナの起動時に envsubst
を実行し、環境変数から各種設定ファイル等を生成するパターンも定番です。
しかし distroless
イメージでこれをやろうとすると、次のような問題からうまくいきません。
envsubst
がない
distroless
イメージは必要最小限のパッケージのみを含めることで省サイズと高いセキュリティを実現しています。そこには /bin/sh
すら含まれておらず、当然ながら envsubst
も残念ながら含まれていません。
ただし、以下のようにすることで distroless
ベースのイメージに envsubst
を追加することは可能です。
FROM debian:bookworm AS envsubst
RUN apt-get update && apt-get install -y gettext-base
FROM gcr.io/distroless/base-debian12:nonroot AS app
COPY /usr/bin/envsubst /usr/bin/envsubst
しかし例え envsubst
を追加しても、次の問題が残り、うまくいきません。
/bin/sh
がない
前述の通り distroless
イメージには /bin/bash
はおろか /bin/sh
すら含まれていません。そのため、仮に docker-entrypoint.sh
などを作成し ENTRYPOINT
に指定したとしても当然ながらそれが動くことはありません……。
envsubst
と同じように COPY
命令で /bin/sh
をいずれかのイメージから持ってくることはできるかもしれませんが、それでは distroless
イメージのメリットが半減してしまいます。
解決策
そもそも envsubst
をコンテナの起動時に実行したい理由は、コンテナを起動するタイミングで任意の環境変数を渡し、それを反映した状態でコンテナを実行したいからです。
しかし例えば HTTP サーバーにおけるドメイン名やポート番号、パフォーマンスチューニングのための設定値など、本番環境においてはあらかじめ決めておくことが可能な値であることが多いのではないでしょうか。
もしそうであれば、実行時ではなくイメージのビルド時に envsubst
を実行し、対象の設定ファイルを生成することで、任意の設定値が埋め込まれたイメージを生成すれば事足ります。
FROM nginxinc/nginx-unprivileged:1.27-bookworm
ARG APP_DOMAIN_NAME="example.com"
RUN echo "$APP_DOMAIN_NAME" && \
envsubst '$APP_DOMAIN_NAME' < /tmp/app.conf.template > /opt/etc/nginx/conf.d/app.conf
条件付きではあるものの、多くのケースではこれで課題は解決できるんじゃないでしょうか。
Discussion