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


183

[ StackOverflow için çok fazla sysadmin benzeri olduğu düşünüldüğü için, çapraz yayınlanmış ve https://stackoverflow.com/questions/21933955 adresinden yazılmıştır.]

Başka bir liman işçisi konteynerine bağlanan Nginx çalışan bir liman işçisi var. İkinci kabın ana bilgisayar adı ve IP adresi, Nginx kabına başlangıçta ortam değişkenleri olarak yüklenir, ancak ondan önce bilinmez (dinamiktir). nginx.confBu değerleri kullanmamı istiyorum - örneğin

upstream gunicorn {
    server $APP_HOST_NAME:$APP_HOST_PORT;
}

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

1 EDIT

Aşağıda önerilen cevaptan sonra tüm dosya budur:

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 yeniden yükleniyor 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

8
Bu, ortam değişkenleri için genel bir çözüm değildir, ancak akış yukarı sunucuların ana bilgisayar adları / IP adresleri için ortam değişkenleri kullanmak istiyorsanız, Docker'ın (en azından son sürümlerde) sizin için / etc / hosts dosyasını değiştirdiğini unutmayın. Bkz docs.docker.com/userguide/dockerlinks Bunun anlamı bağlantılı konteyner 'app_web_1' denir, eğer liman işçisi sizin Nginx kapta / etc / hosts bir çizgi oluşturur. Yani sadece yerini alabilir server $ENV{"APP_WEB_1_PORT_5000_TCP_ADDR"}:5000; ile server app_web_1:5000;
mozz100

1
Thanks @ mozz100 - bu inanılmaz derecede kullanışlı - / etc / hosts girdileri bu durumda env değişkenlerinden çok daha etkili. Eksik olan tek bit, yukarı akış kabı yeniden başlatıldığında ve yeni bir IP edindiğinde gerçekleşen şeydir. Çocuk konteynırlarının hala yeni IP’yi değil, orijinal IP’yi göstereceğini sanıyorum.
Hugo Rodger-Brown

1
Evet, yeniden başlattıysanız app_web_1yeni bir IP adresi alırsa , nginx kabınızı da yeniden başlatmanız gerekir. Docker, güncellenmiş bir sürümle yeniden başlatır, /etc/hostsböylece nginx config dosyalarını değiştirmenize gerek kalmaz.
mozz100

Yanıtlar:


100

Gönderen resmi Nginx liman işçisi dosyası:

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

Kutudan çıkan Nginx, çoğu yapılandırma bloğunun içindeki ortam değişkenlerini kullanmayı desteklemiyor.

Ancak envsubstnginx yapılandırmanızı dinamik olarak nginx başlamadan önce yapmanız gerekiyorsa, geçici çözüm olarak kullanılabilir.

Docker-compose.yml dosyasını kullanan 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ı daha sonra şöyle değişken referanslar içerebilir:

listen ${NGINX_PORT};

Güncelleme:

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

proxy_set_header        X-Forwarded-Host $host;

zarar görmüş:

proxy_set_header        X-Forwarded-Host ;

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

docker-composeDosyada Nginx sunucusu için komut seçeneği olarak kullanılan Nginx'i çalıştırmak için bir komut dosyası kullandım run_nginx.sh:

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

Ve betiğin tanımlanmış yeni DOLLARdeğişkeni nedeniyle run_nginx.sh, artık nginx.conf.templateNginx'in değişkenleri için dosyamın içeriği şu şekilde:

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

Ve benim tanımlı değişkenim şöyle:

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

Ayrıca burada , bunun için gerçek kullanım davam var.


2
Bu, Nginx'i öldüren şeyleri öldürüyorproxy_set_header Host $http_host;
parçalanmak

22
@ shredding, değiştirilecek isimlerle başa çıkabilirsiniz - diğerleri dokunulmaz: 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 benim için ne işe yaradığını biliyorum ...
pkyeck

4
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

2
Bu kaçmayı göz önünde bulundurarak kendi eserlerinizdeki 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
Bu harika bir çözüm. Teşekkürler. Ayrıca yukarıda belirtilen bağlantı, github.com/docker-library/docs/issues/496 konusu için mükemmel bir çözümdür.
kabirbaidhya

34

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

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üzenleme 2:

Bu yaklaşımla envNginx'te değişken tanımlamanız gerektiğini unutmayın :

env ENVIRONMENT_VARIABLE_NAME

Bunu üst düzey bağlamda nginx.confyapmalısınız, yoksa işe yaramaz! Değil sunucu bloğunda veya bazı sitenin config /etc/nginx/sites-availableo tarafından dahil olduğu için, nginx.confiçinde http(değil üst düzey bağlamında) bağlamında.

Ayrıca, bu yönlendirme ile örneğin bir yönlendirme yapmaya çalışırsanız, örneğin:

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 ona ayrı bir değişken adı 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 yönlendirecek https://%24server_name_from_env/.


3
env NGINX_SERVERNAMEnginx.conf dosyasında bir yere ihtiyacınız olabilir .
hiroshi

Bu benim için işe yaramadı, ama nginx docker resmimde lua modülü var. Bu benim nginx.conf'umda bir config dosyası eklemem gerçeğiyle ilgili olabilir mi? set_by_luaİçerdiği config dosyasındaki değişkene çalışıyordum , env MY_VARbildirimde belirtildiği gibi bildirimi ana nginx.conf içinde yaptım. Ne ayıp, bu en temiz çözüm olurdu!
pederpansen

Bu yöntemi kullanmanın artılarını / eksilerini bilen var mı envsubst? Sanırım profesyonel, envsubstrsunucuyu başlatmadan önce komutu çalıştırmanıza gerek kalmaması ve con, lua modülünü yüklemeniz gerektiği mi? Her iki yaklaşımda da herhangi bir güvenlik çıkarımı olup olmadığını merak ediyorum.
Mark Winterbottom

@MarkWinterbottom henüz bunu test etmedi, ancak sanırım nginx config dosyalarına yazma erişimi vermek zorunda değilsiniz, kullanmanız gereken envsubstve benim durumumda
olmayanlar

14

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

Satır içi, yapılandırma dosyalarını $ {key} referanslarıyla çevre değişkenlerine yönlendirerek, isteğe bağlı olarak yedekleri / günlük kaydını oluşturur. Go ile yazılmıştır ve sonuçta ortaya çıkan statik ikili Linux ve MacOS için yayımlanan sekmeden kolayca indirilebilir.

Ayrıca exec () işlemlerini yapabilir, varsayılanları değiştirebilir, günlükleri ve mantıklı bir hata anlambilimine sahip olabilir.


10

Resmi nginx görüntüsü kullanılmasını önerirenvsubst , ancak başkalarının da belirttiği gibi$host , arzu edilmeyen diğer değişkenleri de değiştirecektir . Ancak neyse ki envsubst, değiştirilecek değişkenlerin adlarını parametre olarak alabilir .

Kapsayıcıya çok karmaşık bir komut parametresini önlemek için (bağlantılı örnekte olduğu gibi), komutu çalıştırmadan önce ortam değişkenlerini dolduracak bir Docker giriş noktası komut dosyası yazabilirsiniz. Giriş noktası komut dosyası ayrıca parametreleri doğrulamak ve varsayılan değerleri ayarlamak için iyi bir yerdir.

Burada, ortam değişkenleri olarak alınan API_HOSTve API_PORTparametrelerini alan bir nginx kabı örneği verilmiştir .

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

Yaptığım erb kullanmaktı !

cat nginx.conf  | grep -i error_log

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

- erb kullandıktan sonra

export APP_ROOT=/tmp

erb nginx.conf  | grep -i error_log

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

Bu, Cloudfoundry staticfile-buildpack öğesinde kullanılır.

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

4

Erb kullanımı ile ilgili cevaba atıfta bulunarak, aşağıdaki gibi yapılabilir.

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

erb nginx.conf.erb > nginx.conf

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

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

1
Ruby'yi kabın içine kurmam gerekiyor mu? ( Olmazsaerb değişken konteyneri başladıktan sonra nasıl değişken ikame yapabiliriz, doğru mu?) - erbBu Ruby şey doğru mu: stuartellis.name/articles/erb
KajMagnus

1
Standart Ruby kurulumu ile birlikte gelen bir komut satırı aracıdır. Kapta yoksa diğer seçenekleri deneyin.
Ruifeng Ma,

3

Bunun eski bir soru olduğunu biliyorum, ancak sadece birinin (buna sahip olduğum gibi) buna tökezlemesi durumunda, bunu yapmanın çok daha iyi bir yolu var. Docker, bağlantılı kapsayıcının diğer adını / etc / hosts dizinine eklediğinden, bunu yapabilirsiniz

upstream upstream_name {
    server docker_link_alias;
}

liman işçisi komutunun böyle bir şey olduğunu varsaymak docker run --link othercontainer:docker_link_alias nginx_container.


1
Bu yöntemi kullanarak ana bilgisayarı elde edebilirsiniz ancak bağlantı noktasını değil. Bağlantı noktasını sabit kodlamanız veya bağlantı noktası 80'i kullandığını varsaymanız gerekir.
Ben Whaley

2

Başka bir seçenek ... Bugün bu aracı buldum: https://github.com/kreuzwerker/envplate ... Go ile yazılmış, çok kolay kurulabilir. Kullanımı oldukça basittir. Yine de, şablon değişkenlerini nginx.conf dosyasına yerleştirmeniz gerekecek.

Örneğin ${SOME_ENV_VAR}, dosyada envplate'nin epkomutu çağrıldığında değiştirilecektir . Dockerfile bu ikili dosyayı alamazsa ya da bir nedenden dolayı çalışmamalıysa, config geçersiz olacaktır. Perl veya lua uzantılarının kullanılması gibi diğer çözümlerle karşılaştırıldığında sadece küçük bir not.

Ortam değişkeni ayarlanmadığında da varsayılan değerleri nasıl ayarlayabileceğinizi gerçekten seviyorum. Ör. ${SOME_ENV_VAR:default-value}(ve değerleri kaçabilirsiniz). Yine, envplate hala başarılı bir şekilde çalışmalıdır.

Bunun gibi bir yaklaşım kullanmanın bir yararı, gerekenden daha büyük olan bir Docker görüntüsü vermeyecek olmanızdır, çünkü aksi takdirde ihtiyacınız olmayan her türlü ekstra modülü kurmaya başladınız. İşler karmaşıklaşmaya başlarsa sed'i kullanmaktan daha kolay olabilir ve bu varsayılan değer işlevselliğini içerir.


Envplate ile ilgili birçok hata ve sorunla karşılaştığım için github.com/gliderlabs/sigil'i tavsiye ediyorum.
Nick,

2

Bunu bir kabuk betiği kullanarak başardım.

İşte nginx şablonu:

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

}

Ve ortam değişkenlerini değiştirmek için komut dosyası burada:

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

Diğer bir olasılık da 'sed' komutunu normal ifadelerle kullanmaktır, daha sonra config dosyalarınızı karıştırmayacaksınız! Bu şekilde config dosyalarınızı normal şekilde kullanabilirsiniz, ancak docker çalıştırdığınızda, değerleri env değişkenleriyle değiştirir. Bunların hiçbiri "aradığınız ve değiştirdiğiniz yapılandırma dosyalarınıza bir metin dizisi ekleyin."

Ortam değişkenlerinizi kullanarak değiştirme değerleri olan bir run.sh dosyası oluşturabilirsiniz.

Bu satırdaki "7s" yi değiştirmek için:

client_body_timeout 7s;         #Default 60s

Client_body_timeout'u arama satırı olarak ve $ client_body_timeout'u değiştirme env değişkeni olarak kullanarak Sed Komutu :

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

Client_body_timeout komutunu ayarlamak ve değiştirmek istediğiniz her parametre için bu satırı kopyalayın / yapıştırın ve env değişkeniyle birlikte $ client_body_timeout ile ilişkilendirin. Mevcut yapılandırma dosyası ile kullanın ve sadece çalışacak.


0

İşte sedyaklaşımı kullanmanın bir örneği, mutlaka daha iyi değil ama bazıları için faydalı olabilir. İlk önce, conf dosyası içinde değiştirilecek özel bir anahtar kelime ekleyin. İkinci olarak, bir ENVdeğişken bildiren bir docker dosyası oluşturun ve daha sonra nginx komutunu açıkça çalıştırmadan önce config düzenlemek için CMDkullanılan bir dosya oluşturun sed.

Bu nedenle, default.conf dosyanızın bunu anahtar kelimeyle içerdiğini düşünündocker_host :

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

Ve Dockerfile'nizi şöyle yazın:

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

Ardından görüntüyü oluşturun ve kapsayıcıyı kullanarak çalıştırın

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

0

Lu ile yapmanın doğru yolu, çünkü yukarıdaki cevap bayat.

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


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.