Vraag Hoe kan ik omgevingsvariabelen gebruiken in Nginx.conf


[Cross-geplaatst en gereduceerd van https://stackoverflow.com/questions/21933955 omdat het te sysadmin-achtig werd geacht voor StackOverflow.]

Ik heb een docker-container met Nginx die linkt naar een andere docker-container. De hostnaam en het IP-adres van de tweede container worden tijdens het opstarten in de Nginx-container geladen als omgevingsvariabelen, maar zijn niet eerder bekend (het is dynamisch). ik wil mijn nginx.conf om deze waarden te gebruiken - b.v.

upstream gunicorn {
    server $APP_HOST_NAME:$APP_HOST_PORT;
}

Hoe kan ik bij het opstarten omgevingsvariabelen in de Nginx-configuratie krijgen?

EDIT 1

Dit is het volledige bestand, na het voorgestelde antwoord hieronder:

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 herladen en vervolgens fouten:

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

EDIT 2: meer details

Huidige omgevingsvariabelen

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;

Site nginx-configuratie:

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;

Reload nginx-configuratie:

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


oorsprong


Dit is geen generieke oplossing voor omgevingsvariabelen, maar als u omgevingsvariabelen voor de hostnamen / IP-adressen van upstream-servers wilt gebruiken, moet u er rekening mee houden dat Docker (althans in recente versies) / etc / hosts voor u wijzigt. Zien docs.docker.com/userguide/dockerlinks    Dit betekent dat, als uw gekoppelde container 'app_web_1' heet, docker een regel in / etc / hosts in uw Nginx-container zal maken. U kunt dus gewoon vervangen server $ENV{"APP_WEB_1_PORT_5000_TCP_ADDR"}:5000;    met server app_web_1:5000; - mozz100
Bedankt @ mozz100 - dat is ongelooflijk handig - / etc / hosts entries zijn in dit geval veel effectiever dan env vars. Het enige wat ontbreekt is wat er gebeurt als de upstream-container opnieuw wordt opgestart en een nieuw IP-adres krijgt. Ik veronderstel dat de child-containers nog steeds naar het oorspronkelijke IP-adres wijzen, niet naar het nieuwe IP-adres? - Hugo Rodger-Brown
Ja, als u opnieuw bent opgestart app_web_1 het zou een nieuw IP-adres krijgen, dus je zou ook je nginx-container opnieuw moeten opstarten. Docker zou het opnieuw opstarten met een update /etc/hosts dus je zou het nginx-configuratiebestand (en) niet hoeven aan te passen. - mozz100


antwoorden:


Als u een koppeling gebruikt, worden door de koppelaar omgevingsvariabelen ingesteld en wordt een alias voor de gekoppelde container toegevoegd /etc/hosts. Als je in staat bent om de poort te coderen (of als het gewoon poort 80 is) kun je gewoon:

upstream gunicorn {
    server linked-hostname:5000;
}

De poort is alleen beschikbaar in een omgevingsvariabele, die niet kan worden gebruikt in de upstream module, noch in server- of locatievlakken. Er kan alleen naar worden verwezen in de hoofdconfiguratie, wat u niet helpt. Je zou dit kunnen doen met de openresty-bundel dat omvat Lua.

Als u geen gebruik wilt maken van openresty / Lua, is een andere optie om een ​​substitutie uit te voeren bij het opstarten van de container. Jouw docker run opdracht kan de koppeling maken en vervolgens een wrapper-script uitvoeren dat de juiste vervanging uitvoert:

#!/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 - de huidige (werk) oplossing is precies dit. Het lijkt gewoon een beetje hacky. (Dat gezegd hebbende, het is slechts een lokale dev-omgeving, dus hacking is geen groot probleem.) - Hugo Rodger-Brown
Ik kwam dit tegen, dus ik maakte een iets meer generieke nginx-container die omgevingsvariabelen automatisch uitbreidt in de configuratie. - Shepmaster


Van het officiële dockingsbestand van Nginx:

Omgevingsvariabelen in nginx-configuratie gebruiken:

Out-of-the-box, Nginx biedt geen ondersteuning voor het gebruik van omgevingsvariabelen   in de meeste configuratieblokken.

Maar envsubst kan worden gebruikt als een   workaround als u uw nginx-configuratie moet genereren   dynamisch voordat nginx start.

Hier is een voorbeeld met 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;'" 

Het bestand mysite.template kan dan variabele verwijzingen bevatten, zoals   deze :

listen ${NGINX_PORT};

Bijwerken:

Maar je weet dat dit zijn Nginx-variabelen als volgt heeft veroorzaakt:

proxy_set_header        X-Forwarded-Host $host;

beschadigd aan:

proxy_set_header        X-Forwarded-Host ;

Dus om dit te voorkomen, gebruik ik deze truc:

Ik heb een script om Nginx uit te voeren, dat gebruikt op de docker-compose bestand als opdrachtoptie voor Nginx-server, ik heb het genoemd run_nginx.sh:

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

En vanwege gedefinieerd nieuw DOLLAR variabele aan run_nginx.sh script, nu inhoud van mijn nginx.conf.template bestand voor Nginx zelf variabele is als volgt:

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

En voor mijn gedefinieerde variabele is dit als volgt:

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

Ook hier, daar is mijn echte use-case voor.


61
2018-02-11 12:39



Dat doodt nginx, zoals proxy_set_header Host $http_host; - shredding
@shredding kun je in namen van variabelen doorgeven om vervangen te worden - anderen worden niet aangeraakt: command: /bin/bash -c "envsubst '$VAR1 $VAR2' < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" werkt voor mij b / c Ik weet hoe ze heten ... - pkyeck
ok, vergat te ontsnappen aan de $, zou moeten zijn command: /bin/bash -c "envsubst '\$VAR1 \$VAR2' < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" - pkyeck
Met de overweging om te ontsnappen aan dit werk in je eigen 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
Dit is een geweldige oplossing. Bedankt. Ook de link hierboven vermeld github.com/docker-library/docs/issues/496 heeft een geweldige oplossing voor het probleem. - kabirbaidhya


Dit doen met Lua is aanzienlijk eenvoudiger dan het klinkt:

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

Ik vond dat hier:

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

Bewerk:

Blijkbaar vereist dit de installatie van de lua-module: https://github.com/openresty/lua-nginx-module

Bewerk 2:

Merk op dat je met deze benadering moet definiëren env variabele in Nginx:

env ENVIRONMENT_VARIABLE_NAME

Je moet dit doen in topniveau in nginx.conf of het zal niet werken! Niet in serverblok of in config van een bepaalde site in /etc/nginx/sites-available, omdat het is opgenomen door nginx.conf in http context (wat geen context op het hoogste niveau is).

Merk ook op dat met deze benadering als u een omleiding probeert te maken, bijvoorbeeld:

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

het zal niet zo goed werken:

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

En als je er een aparte variabele naam aan geeft:

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 zal het niet interpreteren en zal u doorverwijzen naar https://%24server_name_from_env/.


26
2017-12-01 16:26



je zou nodig kunnen hebben env NGINX_SERVERNAME ergens in je nginx.conf. - hiroshi
Dit werkte niet voor mij, hoewel ik de lua-module in mijn nginx docker-afbeelding heb. Kan dit te maken hebben met het feit dat ik een configuratiebestand opneem in mijn nginx.conf? ik probeerde set_by_lua de variabele in het meegeleverde configuratiebestand, terwijl de env MY_VAR verklaring was in de belangrijkste nginx.conf, zoals gesuggereerd. Wat een schande, dit zou de schoonste oplossing zijn geweest! - pederpansen
Kent iemand de voors en tegens van het gebruik van deze methode envsubst? Ik denk dat je de professional niet hoeft te gebruiken envsubstr commando voor het starten van de server en de con is dat je de lua-module moet installeren? Ik vraag me af of er gevolgen zijn voor de veiligheid van beide benaderingen? - Mark Winterbottom
@MarkWinterbottom heeft dit nog niet getest, maar het lijkt erop dat u geen schrijftoegang zou moeten verlenen aan de nginx-configuratiebestanden, die u moet gebruiken envsubst en die in mijn geval een no-go is - Griddo


Ik schreef iets dat al dan niet nuttig kan zijn: https://github.com/yawn/envplate

Inline bewerkt configuratiebestanden met $ {key} -referenties naar omgevingsvariabelen, waarbij optioneel back-ups worden gemaakt / vastgelegd wat deze doet. Het is geschreven in Go en het resulterende statische binaire bestand kan eenvoudig worden gedownload van het tabblad Release voor Linux en MacOS.

Het kan ook exec () processen uitvoeren, defaults vervangen, logs en heeft zinvolle faalsemantiek.


14
2017-11-15 16:02





Wat ik deed was om de erb!

cat nginx.conf  | grep -i error_log

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

- Na het gebruik van erb

export APP_ROOT=/tmp

erb nginx.conf  | grep -i error_log

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

Dit wordt gebruikt in de Cloudfoundry staticfile-buildpack

Voorbeeld van een nginx-configuratie: https://github.com/cloudfoundry/staticfile-buildpack/blob/master/conf/nginx.conf

In jouw geval

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

worden

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



Kun je dit antwoord uitbreiden? Het is vermeldenswaard dat er hierboven al een geaccepteerd antwoord op deze vraag is, maar als u vindt dat uw antwoord hier waarde aan geeft, kunt u dit uitbreiden. - BE77Y


Verwijzend naar het antwoord over het gebruik van erb, kan het worden gedaan zoals hieronder.

Schrijf het NGINX-configuratiebestand als een erb-bestand dat de omgevingsvariabele bevat en evalueer het met de opdracht erb naar een normaal configuratiebestand.

erb nginx.conf.erb > nginx.conf

Binnen het serverblok van het bestand nginx.conf.erb zou dat kunnen

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

4
2017-08-01 11:39



Moet ik Ruby dan in de container installeren? (Zo niet, hoe is het erb in staat om variabele vervanging te doen ... nadat de container is gestart, toch?) - erb is dit Ruby goed, goed: stuartellis.name/articles/erb - KajMagnus
Het is een opdrachtregelprogramma dat wordt geleverd met standaard Ruby-installatie. Probeer andere opties als u het niet in de container hebt. - Ruifeng Ma
Ok, bedankt voor het uitleggen - KajMagnus


Ik weet dat dit een oude vraag is, maar voor het geval iemand hier tegenaan loopt (zoals ik nu heb), is er een veel betere manier om dit te doen. Omdat docker de alias van de gekoppelde container invoegt in / etc / hosts, kunt u het gewoon doen

upstream upstream_name {
    server docker_link_alias;
}

in de veronderstelling dat je docker-commando zoiets is docker run --link othercontainer:docker_link_alias nginx_container.


3
2018-03-17 05:16



U kunt de host gebruiken met deze methode, maar niet met de poort. Je moet de poort ofwel hard coderen of aannemen dat hij poort 80 gebruikt. - Ben Whaley