سؤال كيف يمكنني استخدام متغيرات البيئة في Nginx.conf


[Cross-posted and edited down from https://stackoverflow.com/questions/21933955 كما كان يعتبر مسؤول النظام يشبه للغاية ل StackOverflow.]

لدي حاوية حاويات تعمل بنظام Nginx ، ترتبط بحاوية ميناء حاويات أخرى. يتم تحميل اسم المضيف وعنوان 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

EDIT 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

143
2018-02-21 15:02


الأصل


هذا ليس حلاً عامًا لمتغيرات البيئة ، ولكن إذا كنت تريد استخدام متغيرات البيئة لعناوين المضيف / عناوين IP للخوادم الأولية ، فلاحظ أن Docker (على الأقل في الإصدارات الحديثة) يعدل / etc / hosts لك. نرى docs.docker.com/userguide/dockerlinks    وهذا يعني ، إذا كانت الحاوية المرتبطة الخاصة بك تسمى "app_web_1" ، فسيقوم عامل الشحن بإنشاء خط في / etc / hosts في حاوية Nginx الخاصة بك. لذلك يمكنك فقط استبدال server $ENV{"APP_WEB_1_PORT_5000_TCP_ADDR"}:5000;    مع server app_web_1:5000; - mozz100
بفضل mozz100 @ - هذا مفيد للغاية - / etc / hosts إدخالات أكثر فاعلية من env vars في هذه الحالة. الشيء المفقود الوحيد هو ما يحدث في حالة إعادة تشغيل حاوية المنبع ، والحصول على عنوان IP جديد. أفترض أن حاويات الأطفال ستظل تشير إلى عنوان IP الأصلي ، وليس الجديد؟ - Hugo Rodger-Brown
نعم ، إذا قمت بإعادة التشغيل app_web_1 سيحصل على عنوان IP جديد ، لذا ستحتاج إلى إعادة تشغيل حاوية nginx أيضًا. إعادة تشغيل Docker مع تحديث /etc/hosts لذلك لن تحتاج إلى تغيير ملف (ملفات) تهيئة nginx. - mozz100


الأجوبة:


إذا كنت تستخدم رابطًا ، يقوم عامل التحميل بإعداد متغيرات البيئة ويضيف اسمًا مستعارًا للحاوية المرتبطة في /etc/hosts. إذا كنت قادراً على رمز المنفذ الثابت (أو إذا كان المنفذ 80 فقط) ، فيمكنك القيام بذلك ببساطة:

upstream gunicorn {
    server linked-hostname:5000;
}

المنفذ متاح فقط في متغير بيئة ، والذي لا يمكن استخدامه في upstream وحدة ، ولا في الخادم أو كتل الموقع. لا يمكن الرجوع إليها إلا في التهيئة الرئيسية ، والتي لا تساعدك. هل يمكن أن تفعل هذا مع حزمة openresty يتضمن لوا.

إذا كنت لا ترغب في استخدام openresty / Lua ، هناك خيار آخر هو إجراء بعض الاستبدال عند بدء تشغيل الحاوية. ك docker run الأمر يمكن إنشاء الارتباط ثم تشغيل برنامج نصي مجمّع الذي يقوم بإجراء الاستبدال المناسب:

#!/bin/bash
/usr/bin/sed -i "s/server<gunicorn_server_placeholder>/${APP_WEB_1_PORT_5000_TCP_ADDR}/" default
start nginx

56
2018-03-18 06:14



نعم - الحل الحالي (العمل) هو بالضبط هذا. فقط يبدو سخيف بعض الشيء. (ومع ذلك ، فهي بيئة محلية فقط ، لذا فإن القرصنة ليست مشكلة كبيرة). - Hugo Rodger-Brown
جريت في هذا ، لذلك قدمت أكثر عمومية بعض الشيء حاوية nginx التي توسع تلقائياً متغيرات البيئة في التكوين. - Shepmaster


من عند ملف Nginx docker الرسمي:

استخدام متغيرات البيئة في تهيئة 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 متغير على run_nginx.sh النصي الآن محتوى بلدي nginx.conf.template ملف Nginx نفسه متغير هو مثل هذا:

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

ولمتغيرتي المحددة هي كالتالي:

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

أيضا هنا، هناك حالة استخدام حقيقية لذلك.


62
2018-02-11 12:39



أن يقتل nginx confs مثل proxy_set_header Host $http_host; - shredding
@ shredding يمكنك تمرير في أسماء المتغيرات ليتم استبدالها - لا يتم لمس الآخرين: command: /bin/bash -c "envsubst '$VAR1 $VAR2' < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" يعمل بالنسبة لي ب / ج أعرف ما يطلق عليه ... - pkyeck
حسنا ، نسيت أن الهروب $، يجب ان يكون command: /bin/bash -c "envsubst '\$VAR1 \$VAR2' < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" - pkyeck
مع النظر في الخروج من هذه الأعمال في 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
هذا هو الحل الرائع. شكر. أيضا الرابط المذكور أعلاه github.com/docker-library/docs/issues/496 لديه حل رائع لهذه المشكلة. - kabirbaidhya


القيام بذلك مع 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

تصحيح:

على ما يبدو يتطلب هذا تثبيت وحدة لوا: https://github.com/openresty/lua-nginx-module

تحرير 2:

لاحظ أنه مع هذا النهج عليك أن تحدد env متغير في Nginx:

env ENVIRONMENT_VARIABLE_NAME

عليك القيام بذلك في سياق toplevel في nginx.conf أو أنها لن تعمل! ليس في كتلة الخادم أو في تهيئة بعض المواقع في /etc/nginx/sites-available، لأنها مدرجة من قبل nginx.conf في http السياق (وهو ليس سياق المستوى الأعلى).

لاحظ أيضًا أنه في ظل هذه الطريقة ، إذا حاولت إجراء عملية إعادة توجيه ، مثل:

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/.


26
2017-12-01 16:26



قد تحتاج env NGINX_SERVERNAME في مكان ما في nginx.conf الخاص بك. - hiroshi
هذا لم ينجح بالنسبة لي ، على الرغم من أن لدي وحدة لوا في صورة عامل ميناء nginx بلدي. هل يمكن أن يرتبط ذلك بحقيقة أنني قمت بتضمين ملف تهيئة داخل nginx.conf الخاص بي؟ كنت أحاول أن set_by_lua المتغير في ملف التكوين المرفق ، في حين أن env MY_VAR كان الإعلان في nginx.conf الرئيسي ، على النحو المقترح. يا له من عار ، كان هذا الحل الأنظف! - pederpansen
لا أحد يعرف الايجابيات / سلبيات لاستخدام هذه الطريقة envsubst؟ أعتقد أن المؤيد لا تحتاج إلى تشغيل envsubstr الأمر قبل بدء الخادم والخدع هو أنك بحاجة إلى تثبيت وحدة لوا؟ أتساءل عما إذا كان هناك أي آثار أمنية على أي من النهجين؟ - Mark Winterbottom
لم يختبر هذاMarkWinterbottom حتى الآن ولكن يبدو أنك لن تضطر إلى منح حق الوصول للكتابة إلى ملفات تهيئة nginx ، والتي يجب عليك استخدامها envsubst والذي هو عدم الذهاب في حالتي - Griddo


لقد كتبت شيئًا قد يكون أو لا يكون مفيدًا: https://github.com/yawn/envplate

يقوم بتحرير ملفات التكوين مع مراجع $ {key} إلى متغيرات البيئة ، وإنشاء نسخ احتياطية / تسجيل ما يفعله. تمت كتابتها في Go ويمكن تنزيل الملف الثنائي الثابت الناتج ببساطة من علامة تبويب الإصدار لـ Linux و MacOS.

ويمكن أيضا exec () العمليات ، والافتراضات البديلة والسجلات ولها دلالات فشل معقولة.


14
2017-11-15 16:02





ما فعلته هو استخدام إرب!

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
}

5
2018-02-20 00:11



هل يمكنك التوسع في هذه الإجابة؟ تجدر الإشارة إلى أن هناك إجابة مقبولة مسبقًا على هذا السؤال أعلاه ، ولكن إذا كنت تشعر أن إجابتك تضيف قيمة إلى ذلك ، فالرجاء التوسع فيها. - BE77Y


بالإشارة إلى الإجابة على استخدام erb ، يمكن القيام به على النحو التالي.

اكتب ملف تهيئة NGINX كملف erb يحتوي على متغير البيئة ، وقم بتقييمه باستخدام الأمر erb إلى ملف config عادي.

erb nginx.conf.erb > nginx.conf

داخل كتلة الخادم لملف nginx.conf.erb يمكن أن يكون هناك

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

4
2017-08-01 11:39



هل أحتاج إلى تثبيت روبي ، داخل الحاوية؟ (إذا لم يكن كذلك ، كيف يتم ذلك erb قادرة على القيام بدائل متغير ... بعد أن بدأت الحاوية ، أليس كذلك؟) - erb هل هذه الأشياء روبي الحق: stuartellis.name/articles/erb - KajMagnus
إنها أداة سطر الأوامر التي تأتي مع تركيب Ruby القياسي. جرّب خيارات أخرى إذا لم يكن لديك في الحاوية. - Ruifeng Ma
طيب شكرا على التوضيح - KajMagnus


أعرف أن هذا سؤال قديم ، ولكن فقط في حالة تعثر شخص ما في هذا الأمر (كما لدي الآن) ، فهناك طريقة أفضل بكثير للقيام بذلك. ولأن عامل الميناء يقوم بإدراج الاسم المستعار للحاوية المرتبطة في / etc / hosts ، فيمكنك القيام بذلك

upstream upstream_name {
    server docker_link_alias;
}

بافتراض أن أمر رصيف الميناء هو شيء من هذا القبيل docker run --link othercontainer:docker_link_alias nginx_container.


3
2018-03-17 05:16



يمكنك الحصول على المضيف باستخدام هذه الطريقة ولكن ليس المنفذ. يجب عليك إما رمز القرص الثابت أو تفترض أنه يستخدم المنفذ 80. - Ben Whaley