🍇

Dockerのnginxイメージで環境変数によって動作を変更させる

2023/09/10に公開

nginxの設定ファイルには環境変数を埋め込めないため、Dockerコンテナ起動時に環境変数を与えて動きを変えるためには一工夫が必要です。

nginxの公式Dockerイメージ (https://hub.docker.com/_/nginx/) は、起動時にdocker-entrypoint.shというスクリプトを実行し、このスクリプトは/docker-entrypoint.d 配下にあるシェルスクリプト(.shファイル)をすべて実行した上でnginxを起動します。これを利用して設定ファイルの書き換えを行います。

つまり、

  1. 設定ファイルに環境変数を埋め込む
  2. /docker-entrypoint.d/配下に設定ファイルの環境変数を置換するシェルスクリプトを配置する

という形になります。

具体例: プロキシエンドポイントの動的設定

ここでは、nginxのバックエンドにAPIサーバが存在し、そのAPIサーバ向けのプロキシとしてnginxを設定したい、ただしAPIサーバのURLはデプロイ毎に異なるため環境変数で与えたいという状況を考えます。

まず設定ファイル。

default.conf.template
server {
    listen 80;
    location / {
        proxy_pass $API_ADDRESS;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

$API_ADDRESSがAPIサーバのURLだとします。

次にシェルスクリプト

reflect_envs.sh
#!/bin/sh

# 環境変数を使用して設定ファイルを生成
envsubst '$API_ADDRESS' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf
echo `cat /etc/nginx/conf.d/default.conf`

/etc/nginx/conf.d/default.conf.templateを入力として環境変数を置換したうえで/etc/nginx/conf.d/default.confを出力」するようになっています。
また、一応設定ファイルの埋め込み結果をログ確認できるように出力しています。

そしてDockerfileは以下のようになります。

Dockerfile
FROM nginx:latest

# 設定ファイルテンプレートとエントリポイントスクリプトをコンテナにコピー
COPY default.conf.template /etc/nginx/conf.d/default.conf.template
COPY reflect_envs.sh /docker-entrypoint.d/reflect_envs.sh

# 実行可能にする
RUN chmod +x /docker-entrypoint.d/reflect_envs.sh

# 80番ポートを公開
EXPOSE 80

あとはコンテナ起動時に
API_ADDRESS=https://example.com
のような形でバックエンドのエンドポイントを指定すればよいでしょう


追記: PaaSなどの環境ではさらにいくつかの点に気を付けたほうが良いかもしれません。

default.conf.template
server {
    listen 80;
    location / {
        proxy_pass $API_ADDRESS;
        proxy_ssl_server_name on;
        proxy_http_version 1.1;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
  • proxy_ssl_server_name: 一つのIPで複数のサーバをホストするような環境ではURLでアクセス対象を確定する必要があります。本オプションを指定することでSNI (Server Name Indication)が有効になりこのような環境下でもアクセスが成立します
  • proxy_http_version: アクセスするHTTPバージョンを明示します
  • proxy_set_header: PaaSによってはHostヘッダが指定されていると403 Errorなどになるため、そのような場合には削っても良いでしょう

Discussion