Nginx.confで環境変数を使用するにはどうすればよいですか


183

[ StackOverflowではシステム管理者に似ていると考えられたため、https://stackoverflow.com/questions/21933955からクロス投稿および編集されました。]

別のdockerコンテナーにリンクするNginxを実行しているdockerコンテナーがあります。2番目のコンテナのホスト名とIPアドレスは、起動時に環境変数としてNginxコンテナにロードされますが、それまではわかりません(動的です)。nginx.confこれらの値を使用したい-例えば

upstream gunicorn {
    server $APP_HOST_NAME:$APP_HOST_PORT;
}

起動時に環境変数をNginx構成に取得するにはどうすればよいですか?

編集1

これは、以下の提案された回答の後のファイル全体です。

env APP_WEB_1_PORT_5000_TCP_ADDR;
# Nginx host configuration for django_app

# Django app is served by Gunicorn, running under port 5000 (via Foreman)
upstream gunicorn {
    server $ENV{"APP_WEB_1_PORT_5000_TCP_ADDR"}:5000;
}

server {
    listen 80;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    location /static/ {
        alias /app/static/;
    }
    location /media/ {
        alias /app/media/;
    }
    location / {
        proxy_pass http://gunicorn;
    }
}

nginxをリロードしてからエラー:

$ nginx -s reload
nginx: [emerg] unknown directive "env" in /etc/nginx/sites-enabled/default:1

編集2:詳細

現在の環境変数

root@87ede56e0b11:/# env | grep APP_WEB_1
APP_WEB_1_NAME=/furious_turing/app_web_1
APP_WEB_1_PORT=tcp://172.17.0.63:5000
APP_WEB_1_PORT_5000_TCP=tcp://172.17.0.63:5000
APP_WEB_1_PORT_5000_TCP_PROTO=tcp
APP_WEB_1_PORT_5000_TCP_PORT=5000
APP_WEB_1_PORT_5000_TCP_ADDR=172.17.0.63

ルートnginx.conf:

root@87ede56e0b11:/# head /etc/nginx/nginx.conf
user www-data;
worker_processes 4;
pid /var/run/nginx.pid;
env APP_WEB_1_PORT_5000_TCP_ADDR;

サイトnginxの構成:

root@87ede56e0b11:/# head /etc/nginx/sites-available/default
# Django app is served by Gunicorn, running under port 5000 (via Foreman)
upstream gunicorn {
    server $ENV{"APP_WEB_1_PORT_5000_TCP_ADDR"}:5000;
}

server {
    listen 80;

nginx設定をリロードします。

root@87ede56e0b11:/# nginx -s reload
nginx: [emerg] directive "server" is not terminated by ";" in /etc/nginx/sites-enabled/default:3

8
これは環境変数の一般的なソリューションではありませんが、アップストリームサーバーのホスト名/ IPアドレスに環境変数を使用する場合は、Docker(少なくとも最近のバージョンでは)が/ etc / hostsを変更することに注意してください。docs.docker.com/userguide/dockerlinksを参照してください これは、リンクされたコンテナーが「app_web_1」と呼ばれる場合、DockerはNginxコンテナーの/ etc / hostsに行を作成することを意味します。だから、あなただけ置き換えることができ server $ENV{"APP_WEB_1_PORT_5000_TCP_ADDR"}:5000;server app_web_1:5000;
mozz100

1
@ mozz100に感謝します-これは非常に便利です-この場合、/ etc / hostsエントリはenv varsよりもはるかに効果的です。唯一欠けているのは、アップストリームコンテナが再起動され、新しいIPを取得した場合に起こることです。私は、子コンテナが新しいIPではなく、元のIPを引き続き指すと推測していますか?
ヒューゴロジャーブラウン14

1
はい、再起動app_web_1すると新しいIPアドレスが取得されるため、nginxコンテナも再起動する必要があります。Dockerは更新された/etc/hosts状態で再起動するため、nginxの設定ファイルを変更する必要はありません。
mozz100

回答:


100

公式nginxのドッキングウィンドウのファイル:

nginx設定で環境変数を使用する:

すぐに使えるNginxは、ほとんどの構成ブロック内での環境変数の使用をサポートしていません。

ただしenvsubst、nginxを開始する前にnginx構成を動的に生成する必要がある場合は、回避策として使用できます。

docker-compose.ymlを使用した例を次に示します。

image: nginx
volumes:
 - ./mysite.template:/etc/nginx/conf.d/mysite.template
ports:
 - "8080:80"
environment:
 - NGINX_HOST=foobar.com
 - NGINX_PORT=80
command: /bin/bash -c "envsubst < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" 

mysite.templateファイルには、次のような変数参照が含まれる場合があります。

listen ${NGINX_PORT};

更新:

しかし、これは次のようなNginx変数の原因であることがわかります。

proxy_set_header        X-Forwarded-Host $host;

損傷を受けた:

proxy_set_header        X-Forwarded-Host ;

それを防ぐために、私はこのトリックを使用します:

私はNginxを実行するスクリプトを持っていdocker-composeます。これはNginxサーバーのコマンドオプションとしてファイルで使用されますrun_nginx.sh

#!/usr/bin/env bash
export DOLLAR='$'
envsubst < nginx.conf.template > /etc/nginx/nginx.conf
nginx -g "daemon off;"

また、スクリプトで定義された新しいDOLLAR変数のため、Nginx自体の変数のファイルのrun_nginx.sh内容nginx.conf.templateは次のようになります。

proxy_set_header        X-Forwarded-Host ${DOLLAR}host;

そして、私の定義された変数の場合は次のようになります。

server_name  ${WEB_DOMAIN} www.${WEB_DOMAIN};

またここでは、そのための私の本当のユースケースがあります。


2
それは次のようなnginxのconfsを殺しますproxy_set_header Host $http_host;
細断

22
@shredding置換する変数名を渡すことができます-他の人は触れません:command: /bin/bash -c "envsubst '$VAR1 $VAR2' < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"私のために動作しますb / c私はそれらが何と呼ばれているか知っています
...-pkyeck

4
OK、エスケープするのを忘れた$はずですcommand: /bin/bash -c "envsubst '\$VAR1 \$VAR2' < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
-pkyeck

2
エスケープを考慮すると、これは独自のDockerfileで機能します。– CMD ["/bin/sh","-c", "if [ -n \"${SOME_ENV}\" ]; then echo envsubst '${SOME_ENV}' with ${SOME_ENV} && envsubst '${SOME_ENV}' < /etc/nginx/conf.d/default.template > /etc/nginx/conf.d/default.conf; fi ; nginx -g 'daemon off;'"]
KCD

1
これは素晴らしい解決策です。ありがとう。また、上記のリンクgithub.com/docker-library/docs/issues/496には、この問題に対する優れたソリューションがあります。
kabirbaidhya

34

Luaでこれを行うことは、思ったよりもかなり簡単です。

server {
    set_by_lua $server_name 'return os.getenv("NGINX_SERVERNAME")';
}

私はそれをここで見つけました:

https://docs.apitools.com/blog/2014/07/02/using-environment-variables-in-nginx-conf.html

編集:

どうやら、これにはLuaモジュールのインストールが必要です:https : //github.com/openresty/lua-nginx-module

編集2:

このアプローチではenv、Nginxで変数を定義する必要があることに注意してください。

env ENVIRONMENT_VARIABLE_NAME

これをトップレベルのコンテキストで行うnginx.conf必要があります。そうしないと機能しません。ないサーバブロック内またはでいくつかのサイトの設定で/etc/nginx/sites-available、それがで含まれているため、nginx.confhttp(ないトップレベルのコンテキスト)コンテキスト。

また、リダイレクトを作成しようとする場合、このアプローチでは次のことに注意してください。

server {
    listen 80;
    server_name $server_name;
    return 301 https://$server_name$request_uri;
}

それもうまくいきません:

2016/08/30 14:49:35 [emerg] 1#0: the duplicate "server_name" variable in /etc/nginx/sites-enabled/default:8

また、別の変数名を指定すると:

set_by_lua $server_name_from_env 'return os.getenv("NGINX_SERVERNAME")';

server {
    listen 80;
    server_name $server_name_from_env;
    return 301 https://$server_name$request_uri;
}

nginxはそれを解釈せず、にリダイレクトしますhttps://%24server_name_from_env/


3
env NGINX_SERVERNAMEnginx.confのどこかが必要になる場合があります。

nginx dockerイメージにluaモジュールがありますが、これはうまくいきませんでした。これは、nginx.conf内に設定ファイルを含めるという事実と関係があるでしょうか?提案されているようにset_by_luaenv MY_VAR宣言がメインのnginx.confにある間に、含まれている設定ファイルの変数を試しました。なんて恥ずかしい、これは最もクリーンなソリューションだったでしょう!
-pederpansen

誰もがこの方法を使用する賛否両論を知っていenvsubstますか?私はenvsubstr、サーバーを起動する前にコマンドを実行する必要がないという長所と、luaモジュールをインストールする必要があるという短所があると思いますか?どちらのアプローチにもセキュリティ上の意味があるのだろうか?
マークWinterbottom

@MarkWinterbottomはまだこれをテストしていないが、あなたは、あなたが使用する必要がありますnginxの設定ファイルへの書き込みアクセス許可する必要はないように見えますenvsubstし、その私の場合には無行くある
Griddo

14

https://github.com/yawn/envplate:役に立つかもしれないし、そうでないかもしれない何かを書きました

環境変数への$ {key}参照を使用して構成ファイルをインライン編集し、オプションでバックアップの作成/実行内容の記録を行います。Goで書かれており、結果の静的バイナリはLinuxおよびMacOSのリリースタブから簡単にダウンロードできます。

また、exec()プロセスを実行したり、デフォルトを置き換えたり、ログを記録したり、適切な障害セマンティクスを使用したりすることもできます。


10

公式のnginxイメージはの使用を推奨してenvsubstいますが、他の指摘したように$host、他の変数も置き換えますが、これは望ましくありません。ただし、幸いなenvsubstことに、置換する変数の名前をパラメーターとして使用できます

コンテナに対する非常に複雑なコマンドパラメータを回避するため(リンクされた例のように)、コマンドを実行する前に環境変数を入力するDockerエントリポイントスクリプトを作成できます。エントリポイントスクリプトは、パラメーターの検証とデフォルト値の設定にも適しています。

ここでとるのnginxのコンテナの例ですAPI_HOSTAPI_PORT、環境変数などのパラメータを。

nginx-default.conf.template

resolver  127.0.0.11 valid=10s;  # recover from the backend's IP changing

server {
  listen  80;

  location / {
    root  /usr/share/nginx/html;
  }

  location /api {
    proxy_pass  http://${API_HOST}:${API_PORT};
    proxy_set_header  Host $http_host;
  }
}

docker-entrypoint.sh

#!/usr/bin/env sh
set -eu

envsubst '${API_HOST} ${API_PORT}' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf

exec "$@"

Dockerfile

FROM nginx:1.15-alpine

COPY nginx-default.conf.template /etc/nginx/conf.d/default.conf.template

COPY docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

5

私がしたことは、erbを使うことでした

cat nginx.conf  | grep -i error_log

error_log <%= ENV["APP_ROOT"] %>/nginx/logs/error.log;

--erbを使用した後

export APP_ROOT=/tmp

erb nginx.conf  | grep -i error_log

error_log /tmp/nginx/logs/error.log;

これはCloudfoundry staticfile-buildpackで使用されます

サンプルnginx構成:https : //github.com/cloudfoundry/staticfile-buildpack/blob/master/conf/nginx.conf

あなたの場合

head /etc/nginx/nginx.conf
user www-data;
worker_processes 4;
pid /var/run/nginx.pid;
env APP_WEB_1_PORT_5000_TCP_ADDR;
upstream gunicorn {
    server $APP_HOST_NAME:$APP_HOST_PORT;
}

なる

head /etc/nginx/nginx.conf
user www-data;
worker_processes 4;
pid /var/run/nginx.pid;
env <%= ENV["APP_WEB_1_PORT_5000_TCP_ADDR"] %>
upstream gunicorn {
    server <%= ENV["APP_HOST_NAME"] %>:<%= ENV["APP_HOST_PORT"] %>
}

#After applying erb

export APP_WEB_1_PORT_5000_TCP_ADDR=12.12.12.12
export APP_HOST_NAME=test
export APP_HOST_PORT=7089 

erb /etc/nginx/nginx.conf

head /etc/nginx/nginx.conf
user www-data;
worker_processes 4;
pid /var/run/nginx.pid;
env 12.12.12.12
upstream gunicorn {
    server test: 7089
}

4

erbの使用に関する回答を参照すると、次のように実行できます。

NGINX構成ファイルを環境変数を含むerbファイルとして記述し、erbコマンドを使用して通常の構成ファイルに評価します。

erb nginx.conf.erb > nginx.conf

nginx.conf.erbファイルのサーバーブロック内には、

listen <%= ENV["PORT"] %>;

1
コンテナ内にRubyをインストールする必要がありますか?(そうでない場合erb、コンテナの開始後に変数置換を行う方法はありますか?)— erbこのRubyの内容は正しいですか:stuartellis.name/articles/erb
KajMagnus

1
これは、標準のRubyインストールに付属するコマンドラインツールです。コンテナにない場合は、他のオプションを試してください。
瑞風馬

3

私はこれが古い質問であることを知っていますが、誰かがこれに出くわした場合に備えて(私が今持っているように)、これを行うためのはるかに良い方法があります。dockerはリンクされたコンテナのエイリアスを/ etc / hostsに挿入するため、次のようにできます。

upstream upstream_name {
    server docker_link_alias;
}

dockerコマンドがのようなものであると仮定しますdocker run --link othercontainer:docker_link_alias nginx_container


1
このメソッドを使用してホストを取得できますが、ポートは取得できません。あなたは、ハードコードポートのいずれかに持っているか、それがポート80を使用していますと仮定
ベンWhaleyらによって行われま

2

別のオプション...私は今日このツールを見つけました:https : //github.com/kreuzwerker/envplate ... Goで書かれており、非常に簡単にインストールできます。使い方はとても簡単です。ただし、nginx.confにテンプレート変数を配置する必要があります。

たとえば${SOME_ENV_VAR}、envplateのepコマンドがファイルで呼び出されると置き換えられます。したがって、Dockerfileがそのバイナリの取得に失敗した場合、または何らかの理由で実行されなかった場合、設定が無効になります。perlまたはlua拡張機能を使用するなどの他のソリューションと比較して少しだけ注意してください。

環境変数が設定されていない場合にもデフォルト値を設定できる方法がとても気に入っています。例 ${SOME_ENV_VAR:default-value}(そして値をエスケープできます)。繰り返しますが、envplateは引き続き正常に実行する必要があります。

このようなアプローチを使用する利点の1つは、必要のないあらゆる種類の追加モジュールをインストールする必要がなくなったために、必要以上に大きいDockerイメージが作成されないことです。物事が複雑になり始め、そのデフォルト値機能が含まれている場合、sedを使用するよりも簡単かもしれません。


私は助言github.com/gliderlabs/sigil、私は多くのバグやenvplateの問題に走ったとして。
ニック

2

これは、シェルスクリプトを使用して行います。

nginxテンプレートは次のとおりです。

server {

    listen 80;
    server_name ___MY_DOMAIN_NAME___;
    charset utf-8;

    location /proxy {
        proxy_pass http://___PROXY_IP___:___PROXY_PORT___;
        proxy_set_header Host            $host;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto https;
    }

    location / {
        return         200;
    }

}

環境変数を置き換えるスクリプトは次のとおりです。

echo sleep 3
sleep 3

echo build starting nginx config


echo replacing ___MY_DOMAIN_NAME___/$MY_DOMAIN_NAME
echo replacing ___PROXY_IP___/$LETSENCRYPT_IP
echo replacing ___PROXY_PORT___/$PROXY_PORT

sed -i "s/___MY_DOMAIN_NAME___/$MY_DOMAIN_NAME/g" /etc/nginx/nginx.conf
sed -i "s/___PROXY_IP___/$PROXY_IP/g" /etc/nginx/nginx.conf
sed -i "s/___PROXY_PORT___/$PROXY_PORT/g" /etc/nginx/nginx.conf

cat /etc/nginx/nginx.conf

if [ -z "$MY_DOMAIN_NAME" ]; then
    echo "Need to set MY_DOMAIN_NAME"
    exit 1
fi  
if [ -z "$LETSENCRYPT_IP" ]; then
    echo "Need to set LETSENCRYPT_IP"
    exit 1
fi  
if [ -z "$LETSENCRYPT_PORT" ]; then
    echo "Need to set LETSENCRYPT_PORT"
    exit 1
fi
if [ -z "$LETSENCRYPT_HTTPS_IP" ]; then
    echo "Need to set LETSENCRYPT_HTTPS_IP"
    exit 1
fi 
if [ -z "$LETSENCRYPT_HTTPS_PORT" ]; then
    echo "Need to set LETSENCRYPT_HTTPS_PORT"
    exit 1
fi

nginx -g 'daemon off;'

1

別の可能性は、正規表現で「sed」コマンドを使用することです。そうすれば、設定ファイルをまったく混乱させる必要がなくなります!そうすれば、構成ファイルを通常どおり使用できますが、dockerを実行すると、値がenv変数と交換されます。このいずれも、「検索して置換する設定ファイルにテキスト文字列を追加します。」

環境変数を使用して、置換値でrun.shファイルを作成できます。

この行の「7」を変更するには:

client_body_timeout 7s;         #Default 60s

検索行としてclient_body_timeoutを使用し、置換env変数として$ client_body_timeoutを使用するSedコマンド:

sed -i "s/\(client_body_timeout\).*\?\;/\1 $client_body_timeout;/" /usr/local/nginx/conf/nginx.conf

設定するパラメーターごとにこの行をコピーして貼り付け、client_body_timeoutをconfigオプションで、$ client_body_timeoutを関連するenv変数で変更します。既存の設定ファイルで使用すると、動作します。


0

sedアプローチの使用例を次に示します。必ずしも良いとは限りませんが、一部の人にとっては便利かもしれません。最初に、confファイル内で置換されるカスタムキーワードを追加します。ENV次に、変数を宣言するdockerfileを作成CMDしてsedから、nginxを明示的に実行する前に構成を編集するために使用します。

default.confにキーワードとともにこれが含まれているとしますdocker_host

location /api { proxy_pass http://docker_host:9000/api; }

そして、次のようなDockerfileを作成します。

ENV docker_host localhost
ADD default.conf /etc/nginx/conf.d/default.conf
CMD sed -i.bak s/docker_host/$docker_host/g /etc/nginx/conf.d/default.conf &&   nginx -g "daemon off;"

次に、イメージをビルドし、次を使用してコンテナを実行します

docker run -d -p 80:80 -e "docker_host=${env:COMPUTERNAME}" imagename

0

上記の答えは古いので、luaでこれを行う適切な方法:

server {
    set_by_lua $curr_server_name 'return os.getenv("NGINX_SERVERNAME")';
    server_name = $curr_server_name;
}


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.