Soru Nginx.conf'ta ortam değişkenlerini nasıl kullanabilirim


[Gönderilen ve aşağı düzenlenmiş https://stackoverflow.com/questions/21933955 StackOverflow için çok sysadmin-gibi kabul edildi.]

Başka bir docker konteynerine bağlanan Nginx çalıştıran bir docker konteyneri var. İkinci kapsayıcının ana bilgisayar adı ve IP adresi, başlangıçta ortam değişkenleri olarak Nginx konteynerine yüklenir, ancak daha önce bilinmez (dinamik). İstiyorum benim nginx.conf bu değerleri kullanmak için - ör.

upstream gunicorn {
    server $APP_HOST_NAME:$APP_HOST_PORT;
}

Başlangıçta Nginx yapılandırmasına ortam değişkenlerini nasıl alabilirim?

DÜZENLE 1

Bu, aşağıdaki yanıtın ardından tüm dosyadır:

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

Yeniden yükleme nginx sonra hataları:

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

EDIT 2: daha fazla detay

Mevcut ortam değişkenleri

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

Kök 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;

Site nginx yapılandırması:

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 yapılandırmasını yeniden yükle:

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


Menşei


Bu, ortam değişkenleri için genel bir çözüm değildir, ancak giriş sunucularının ana makine adları / IP adresleri için ortam değişkenleri kullanmak istiyorsanız, Docker'ın (en son sürümlerde) sizin için / etc / hosts değiştirdiğini unutmayın. Görmek docs.docker.com/userguide/dockerlinks    Bunun anlamı, bağlı kabanıza 'app_web_1' denirse, docker Nginx kapsayıcınızda / etc / hosts dosyasında bir satır oluşturacaktır. Yani sadece yerini alabilirsin server $ENV{"APP_WEB_1_PORT_5000_TCP_ADDR"}:5000;    ile server app_web_1:5000; - mozz100
Teşekkürler @ mozz100 - bu inanılmaz yararlı - / etc / hosts girişleri bu durumda env vars çok daha etkilidir. Tek bit eksik, yukarı akış konteyneri yeniden başlatıldığında ne olur ve yeni bir IP alır. Çocuk kaplarının hala yeni IP'ye değil, orijinal IP'ye işaret edeceğini tahmin ediyorum. - Hugo Rodger-Brown
Evet, yeniden başlattıysanız app_web_1 Yeni bir IP adresi alırdı, bu yüzden nginx konteynerinizi de yeniden başlatmanız gerekiyordu. Docker güncellenmiş bir şekilde yeniden başlatacaktı /etc/hosts bu yüzden nginx yapılandırma dosyalarını değiştirmenize gerek kalmayacak. - mozz100


Cevaplar:


Bağlantı kullanıyorsanız, docker ortam değişkenlerini ayarlar ve bağlantılı konteyner için bir takma ad ekler. /etc/hosts. Bağlantı noktasını sabit kodlayabiliyorsanız (veya 80 numaralı bağlantı noktasıysa) aşağıdakileri yapabilirsiniz:

upstream gunicorn {
    server linked-hostname:5000;
}

Bağlantı noktası yalnızca, kullanılamayan bir ortam değişkeninde kullanılabilir. upstream modül, ne de sunucu veya konum blokları. Sadece size yardımcı olmayan ana yapılandırmada başvuruda bulunabilirler. Bunu yapabilirsin açıklık demeti Lua içerir.

Eğer açıklık / Lua kullanmak istemiyorsanız, başka bir seçenek konteyner başlangıçta bazı ikame yapmaktır. Sizin docker run Komut, bağlantıyı oluşturabilir ve ardından uygun ikameyi gerçekleştiren bir sarmalayıcı komut dosyasını çalıştırabilir:

#!/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 - mevcut (çalışma) çözümü tam olarak budur. Sadece biraz hacky görünüyor. (Yani, bu sadece yerel bir dev ortam, bu yüzden hacking çok büyük bir sorun değil.) - Hugo Rodger-Brown
Buna koştum, bu yüzden biraz daha jenerik yaptım nginx konteyner Bu, yapılandırmadaki ortam değişkenlerini otomatik olarak genişletir. - Shepmaster


itibaren resmi Nginx docker dosyası:

Nginx yapılandırmasında ortam değişkenlerini kullanma:

Kutudan çıktığında, Nginx ortam değişkenlerini desteklemiyor   çoğu yapılandırma bloğu içinde.

Fakat envsubst bir olarak kullanılabilir   nginx yapılandırmanızı oluşturmanız gerekiyorsa geçici çözüm   nginx başlamadan dinamik olarak başlar.

İşte docker-compose.yml kullanarak bir örnek:

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 dosyası gibi değişken referanslar içerebilir   bu :

listen ${NGINX_PORT};

Güncelleştirme:

Ancak bunun bunun Nginx değişkenlerine neden olduğunu biliyorsunuz:

proxy_set_header        X-Forwarded-Host $host;

hasarlı:

proxy_set_header        X-Forwarded-Host ;

Yani, bunu önlemek için bu numarayı kullanıyorum:

Üzerinde kullanılan Nginx'i çalıştırmak için bir komut dosyası var. docker-compose Nginx sunucusu için komut seçeneği olarak dosya, onu adlandırdı run_nginx.sh:

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

Ve tanımlı yeni nedeniyle DOLLAR değişken run_nginx.sh komut dosyası, şimdi içerik nginx.conf.template Nginx kendisi için değişken değişken şöyle:

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

Ve tanımlanmış değişkenim için böyle:

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

Ayrıca İşteBunun için benim gerçek kullanım durumum var.


62
2018-02-11 12:39



O nginx'i öldürür proxy_set_header Host $http_host; - shredding
@shredding değiştirilecek değişken isimlerini iletebilirsiniz - diğerleri dokunulamaz: command: /bin/bash -c "envsubst '$VAR1 $VAR2' < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" Benim için çalışıyor b / c Ne çağrıldığını biliyorum. - pkyeck
Tamam, kaçmayı unuttum $, olmalı command: /bin/bash -c "envsubst '\$VAR1 \$VAR2' < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" - pkyeck
Bu çalışmalardan kaçmak için kendi Dockerfile'ınızda: 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
Bu harika bir çözüm. Teşekkürler. Ayrıca yukarıda belirtilen bağlantı github.com/docker-library/docs/issues/496 Bu konu için harika bir çözüm var. - kabirbaidhya


Bunu Lua ile yapmak, göründüğünden çok daha kolay:

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

Bunu burada buldum:

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

Düzenle:

Görünüşe göre bu lua modülünün kurulmasını gerektirir: https://github.com/openresty/lua-nginx-module

Düzenle 2:

Bu yaklaşımla tanımlamanız gerektiğini unutmayın. env Nginx değişken:

env ENVIRONMENT_VARIABLE_NAME

Bunu üst düzey bağlamda yapmak zorundasınız nginx.conf ya da işe yaramaz! Sunucu bloğunda veya bazı site yapılandırmalarında değil /etc/nginx/sites-available, çünkü nginx.conf içinde http bağlam (üst düzey bağlam değil).

Ayrıca, bir yönlendirme yapmayı denerseniz, bu yaklaşımla şunu unutmayın:

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

o da işe yaramaz:

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

Ve buna ayrı bir değişken isim verirseniz:

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 bunu yorumlamayacak ve sizi yönlendirecek https://%24server_name_from_env/.


26
2017-12-01 16:26



ihtiyacın olabilir env NGINX_SERVERNAME senin nginx.conf içinde bir yerde. - hiroshi
Bu benim için işe yaramadı, nginx docker resmimdeki lua modülüne sahip olmama rağmen. Bu benim nginx.conf içinde bir config dosyası içerdiği gerçeği ile ilgili olabilir mi? deniyordum set_by_lua dahil edilen yapılandırma dosyasındaki değişken env MY_VAR beyan edildiği gibi ana nginx.conf'ta beyan edildi. Ne ayıp, bu en temiz çözüm olurdu! - pederpansen
Bu yöntemi kullanmanın artıları / eksilerini bilen var mı? envsubst? Sanırım yanlısı koşmanız gerekmiyor. envsubstr sunucuyu başlatmadan önce komut ve con lua modülünü yüklemeniz gerekiyor mu? Her iki yaklaşımda herhangi bir güvenlik etkisi olup olmadığını merak ediyorum? - Mark Winterbottom
@MarkWinterbottom bunu henüz test etmedi, ancak kullanmak zorunda olduğunuz nginx yapılandırma dosyalarına yazma erişimi vermek zorunda kalmayacak gibi görünüyor. envsubst ve benim durumumda olmayan bir şey - Griddo


Yardımcı olabilecek veya yardımcı olabilecek bir şey yazdım: https://github.com/yawn/envplate

İsteğe bağlı olarak yedekler oluşturma / günlüğe kaydetme işlemlerini gerçekleştirerek, konfigürasyon dosyalarını $ {key} çevre değişkenlerine referanslar ile düzenler. Go'da yazılmıştır ve ortaya çıkan statik ikili Linux ve MacOS için serbest bırakma sekmesinden kolayca indirilebilir.

Aynı zamanda exec () süreçlerini, varsayılanları değiştirebilir, günlükleri ve mantıklı hata anlambilimine sahip olabilir.


14
2017-11-15 16:02





Yaptığım şey kullanmaktı. erb!

cat nginx.conf  | grep -i error_log

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

- erb kullanıldıktan sonra

export APP_ROOT=/tmp

erb nginx.conf  | grep -i error_log

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

Bu kullanılır Cloudfoundry statik dosya-buildpack

Örnek nginx yapılandırması: https://github.com/cloudfoundry/staticfile-buildpack/blob/master/conf/nginx.conf

Senin durumunda

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

olmak

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



Bu cevabı genişletebilir misin? Yukarıda bu soruya zaten kabul edilmiş bir cevap olduğunu belirtmek gerekir, ancak cevabınızın buna değer kattığını düşünüyorsanız, lütfen bunun üzerinde genişletin. - BE77Y


Erb kullanarak cevaba bakarak, aşağıdaki gibi yapılabilir.

NGINX yapılandırma dosyasını, ortam değişkenini içeren bir erb dosyası olarak yazın ve erb komutunu kullanarak normal bir yapılandırma dosyasına değerlendirin.

erb nginx.conf.erb > nginx.conf

Nginx.conf.erb dosyasının sunucu bloğu içinde

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

4
2017-08-01 11:39



Ruby'yi daha sonra konteynerin içine yerleştirmem gerekiyor mu? (Değilse nasıl olur erb konteyner ikamesi yapıldıktan sonra değişken ikame yapabilir ... doğru mu?) - erb Ruby bu doğru şeyler: stuartellis.name/articles/erb - KajMagnus
Standart Ruby kurulumuyla birlikte gelen bir komut satırı aracıdır. Konteynerin içinde yoksa diğer seçenekleri deneyin. - Ruifeng Ma
Tamam, açıkladığın için teşekkürler - KajMagnus


Bunun eski bir soru olduğunu biliyorum, ama sadece birisinin buna karşı gelmesi durumunda (şimdi sahip olduğum gibi) bunu yapmak için daha iyi bir yol var. Docker, bağlı muhafazanın diğer adlarını / etc / hosts dizinine eklediğinden, bunu yapabilirsiniz

upstream upstream_name {
    server docker_link_alias;
}

senin docker komutunun olduğu gibi bir şey docker run --link othercontainer:docker_link_alias nginx_container.


3
2018-03-17 05:16



Bu yöntemi kullanarak ana bilgisayarı alabilirsiniz, ancak bağlantı noktasını değil. Bağlantı noktasını sabit kodlamanız veya 80 numaralı bağlantı noktasını kullanmanız gerektiğini varsayalım. - Ben Whaley