Pertanyaan Bagaimana saya bisa menggunakan variabel lingkungan di Nginx.conf


[Diposkan silang dan diedit dari https://stackoverflow.com/questions/21933955 karena dianggap terlalu sysadmin-like untuk StackOverflow.]

Saya memiliki kontainer buruh pelabuhan yang menjalankan Nginx, yang menautkan ke kontainer docker lain. Nama host dan alamat IP dari kontainer kedua dimuat ke dalam kontainer Nginx sebagai variabel lingkungan saat startup, tetapi tidak diketahui sebelumnya (itu dinamis). Saya mau nginx.conf untuk menggunakan nilai-nilai ini - mis.

upstream gunicorn {
    server $APP_HOST_NAME:$APP_HOST_PORT;
}

Bagaimana saya bisa mendapatkan variabel lingkungan ke dalam konfigurasi Nginx saat startup?

EDIT 1

Ini adalah seluruh file, setelah jawaban yang disarankan di bawah ini:

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;
    }
}

Reload nginx lalu kesalahan:

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

EDIT 2: detail selengkapnya

Variabel lingkungan saat ini

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

Root 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;

Konfigurasi nginx situs:

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;

Muat ulang konfigurasi 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




Ini bukan solusi umum untuk variabel lingkungan, tetapi jika Anda ingin menggunakan variabel lingkungan untuk nama host / alamat IP server hulu, perhatikan bahwa Docker (setidaknya dalam versi terbaru) memodifikasi / etc / hosts untuk Anda. Lihat docs.docker.com/userguide/dockerlinks    Ini berarti, jika wadah tertaut Anda disebut 'app_web_1', buruh pelabuhan akan membuat garis di / etc / hosts dalam wadah Nginx Anda. Jadi Anda bisa mengganti server $ENV{"APP_WEB_1_PORT_5000_TCP_ADDR"}:5000;    dengan server app_web_1:5000; - mozz100
Terima kasih @ mozz100 - itu sangat berguna - / etc / host entri jauh lebih efektif daripada env vars dalam kasus ini. Satu-satunya yang hilang adalah apa yang terjadi jika wadah hulu dimulai kembali, dan memperoleh IP baru. Saya menganggap bahwa wadah anak akan tetap mengarah ke IP asli, bukan yang baru? - Hugo Rodger-Brown
Ya, jika Anda memulai ulang app_web_1 itu akan mendapatkan alamat IP baru, jadi Anda harus me-restart nginx container Anda juga. Docker akan memulai ulang dengan pembaruan /etc/hosts jadi Anda tidak perlu mengubah file config nginx (s). - mozz100


Jawaban:


Jika Anda menggunakan tautan, buruh pelabuhan menyiapkan variabel lingkungan dan menambahkan alias untuk penampung tertaut di /etc/hosts. Jika Anda dapat mem-hard kode port (atau jika itu hanya port 80), Anda cukup melakukan:

upstream gunicorn {
    server linked-hostname:5000;
}

Port hanya tersedia dalam variabel lingkungan, yang tidak dapat digunakan dalam upstream modul, atau di server atau blok lokasi. Mereka hanya bisa direferensikan di konfigurasi utama, yang tidak membantu Anda. Anda bisa melakukan ini dengan bundel openresty itu termasuk Lua.

Jika Anda tidak ingin menggunakan openresty / Lua, opsi lain adalah melakukan substitusi di startup kontainer. Anda docker run perintah dapat membuat tautan kemudian menjalankan skrip pembungkus yang melakukan substitusi yang sesuai:

#!/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



Yup - solusi saat ini (bekerja) adalah persis seperti ini. Sepertinya agak sedikit hacky. (Yang dikatakan, itu hanya lingkungan dev lokal, jadi peretasan bukanlah masalah besar.) - Hugo Rodger-Brown
Saya mengalami ini, jadi saya membuat sedikit lebih umum wadah nginx yang secara otomatis memperluas variabel lingkungan dalam konfigurasi. - Shepmaster


Dari file docker Nginx resmi:

Menggunakan variabel lingkungan dalam konfigurasi nginx:

Out-of-the-box, Nginx tidak mendukung penggunaan variabel lingkungan   di dalam sebagian besar blok konfigurasi.

Tapi envsubst dapat digunakan sebagai   solusi jika Anda perlu membuat konfigurasi nginx Anda   dinamis sebelum nginx dimulai.

Berikut ini contoh menggunakan 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;'" 

File mysite.template dapat berisi referensi variabel seperti   ini:

listen ${NGINX_PORT};

Memperbarui:

Tetapi Anda tahu ini disebabkan oleh variabel Nginx-nya seperti ini:

proxy_set_header        X-Forwarded-Host $host;

rusak ke:

proxy_set_header        X-Forwarded-Host ;

Jadi, untuk mencegah itu, saya menggunakan trik ini:

Saya memiliki skrip untuk menjalankan Nginx, yang digunakan pada docker-compose file sebagai opsi perintah untuk server Nginx, saya menamakannya run_nginx.sh:

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

Dan karena didefinisikan baru DOLLAR variabel aktif run_nginx.sh skrip, sekarang isi dari saya nginx.conf.template file untuk variabel Nginx sendiri adalah seperti ini:

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

Dan untuk variabel yang saya definisikan adalah seperti ini:

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

Juga sini, ada kasus penggunaan nyata saya untuk itu.


61
2018-02-11 12:39



Itu membunuh nginx seperti proxy_set_header Host $http_host; - shredding
@shredding Anda dapat meneruskan nama variabel untuk diganti - yang lain tidak disentuh: command: /bin/bash -c "envsubst '$VAR1 $VAR2' < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" bekerja untuk saya b / c saya tahu apa yang mereka sebut ... - pkyeck
ok, lupa untuk melarikan diri $, seharusnya command: /bin/bash -c "envsubst '\$VAR1 \$VAR2' < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" - pkyeck
Dengan pertimbangan untuk melarikan diri ini bekerja di Dockerfile Anda sendiri: 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
Ini adalah solusi yang bagus. Terima kasih. Juga tautan yang disebutkan di atas github.com/docker-library/docs/issues/496 memiliki solusi bagus untuk masalah ini. - kabirbaidhya


Melakukan ini dengan Lua secara substansial lebih mudah daripada yang terdengar:

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

Saya menemukan itu di sini:

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

Edit:

Rupanya ini membutuhkan menginstal modul lua: https://github.com/openresty/lua-nginx-module

Edit 2:

Perhatikan bahwa dengan pendekatan ini Anda harus menentukan env variabel dalam Nginx:

env ENVIRONMENT_VARIABLE_NAME

Anda harus melakukan ini dalam konteks level teratas di nginx.conf atau itu tidak akan berhasil! Tidak di blok server atau dalam konfigurasi beberapa situs di /etc/nginx/sites-available, karena termasuk oleh nginx.conf di http konteks (yang bukan konteks tingkat atas).

Perhatikan juga bahwa dengan pendekatan ini jika Anda mencoba untuk membuat redirect e.g .:

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

itu tidak akan berfungsi juga:

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

Dan jika Anda memberikan nama variabel terpisah untuk itu:

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 tidak akan menafsirkannya dan akan mengarahkan Anda ke https://%24server_name_from_env/.


26
2017-12-01 16:26



Anda mungkin perlu env NGINX_SERVERNAME di suatu tempat di nginx.conf Anda. - hiroshi
Ini tidak bekerja untuk saya, meskipun saya memiliki modul lua dalam gambar docker nginx saya. Mungkinkah ini terkait dengan fakta bahwa saya menyertakan file konfigurasi dalam nginx.conf saya? Saya berusaha set_by_lua variabel dalam file konfigurasi yang disertakan, sedangkan env MY_VAR deklarasi berada di nginx.conf utama, seperti yang disarankan. Sayang sekali, ini akan menjadi solusi terbersih! - pederpansen
Apakah ada yang tahu pro / kontra untuk menggunakan metode ini envsubst? Saya kira pro adalah Anda tidak perlu menjalankan envsubstr perintah sebelum memulai server dan con adalah bahwa Anda perlu menginstal modul lua? Saya ingin tahu apakah ada implikasi keamanan pada kedua pendekatan tersebut? - Mark Winterbottom
@MarkWinterbottom belum menguji ini tetapi sepertinya Anda tidak perlu memberikan akses tulis ke file konfigurasi nginx, yang harus Anda gunakan envsubst dan yang tidak ada dalam kasus saya - Griddo


Saya menulis sesuatu yang mungkin atau mungkin tidak membantu: https://github.com/yawn/envplate

Ini mengedit file konfigurasi dengan referensi $ {key} ke variabel lingkungan, secara opsional membuat backup / penebangan apa yang dilakukannya. Ini ditulis dalam Go dan biner statis yang dihasilkan dapat dengan mudah diunduh dari tab rilis untuk Linux dan MacOS.

Dapat juga exec () memproses, mengganti default, log dan memiliki semantik kegagalan yang masuk akal.


14
2017-11-15 16:02





Apa yang saya lakukan adalah menggunakan erb!

cat nginx.conf  | grep -i error_log

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

--Setelah menggunakan erb

export APP_ROOT=/tmp

erb nginx.conf  | grep -i error_log

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

Ini digunakan dalam Cloudfoundry staticfile-buildpack

Contoh konfigurasi nginx: https://github.com/cloudfoundry/staticfile-buildpack/blob/master/conf/nginx.conf

Dalam kasusmu

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;
}

menjadi

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



Bisakah Anda memperluas jawaban ini? Perlu dicatat bahwa ada jawaban yang sudah diterima untuk pertanyaan ini di atas, tetapi jika Anda merasa bahwa jawaban Anda menambah nilai untuk ini, maka harap luaskan. - BE77Y


Mengacu pada jawaban menggunakan erb, dapat dilakukan seperti di bawah ini.

Tulis file konfigurasi NGINX sebagai file erb berisi variabel lingkungan, dan evaluasi menggunakan perintah erb ke file konfigurasi normal.

erb nginx.conf.erb > nginx.conf

Di dalam blok server dari file nginx.conf.erb mungkin ada

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

4
2017-08-01 11:39



Apakah saya perlu menginstal Ruby, di dalam wadah? (Jika tidak, bagaimana caranya erb dapat melakukan substitusi variabel ... setelah wadah dimulai, kan?) - erb apakah ini benar Ruby: stuartellis.name/articles/erb - KajMagnus
Ini adalah alat baris perintah yang datang dengan instalasi Ruby standar. Coba opsi lain jika Anda tidak memilikinya di penampung. - Ruifeng Ma
Ok, terima kasih sudah menjelaskan - KajMagnus


Saya tahu ini adalah pertanyaan lama, tetapi untuk berjaga-jaga jika seseorang tersandung pada ini (seperti yang saya miliki sekarang), ada cara yang jauh lebih baik untuk melakukan ini. Karena buruh pelabuhan menyisipkan alias penampung yang tertaut di / etc / hosts, Anda bisa melakukannya

upstream upstream_name {
    server docker_link_alias;
}

dengan asumsi perintah docker Anda adalah sesuatu seperti docker run --link othercontainer:docker_link_alias nginx_container.


3
2018-03-17 05:16



Anda bisa mendapatkan host menggunakan metode ini tetapi tidak port. Anda harus baik hard code port atau menganggapnya menggunakan port 80. - Ben Whaley