Question Comment utiliser les variables d'environnement dans Nginx.conf


[Cross-posté et édité en bas de https://stackoverflow.com/questions/21933955 comme il a été jugé trop sysadmin-like pour StackOverflow.]

J'ai un conteneur Docker sous Nginx, qui est lié à un autre conteneur Docker. Le nom d'hôte et l'adresse IP du deuxième conteneur sont chargés dans le conteneur Nginx en tant que variables d'environnement au démarrage, mais ils ne sont pas connus auparavant (dynamique). je veux mon nginx.conf utiliser ces valeurs - par ex.

upstream gunicorn {
    server $APP_HOST_NAME:$APP_HOST_PORT;
}

Comment obtenir des variables d'environnement dans la configuration de Nginx au démarrage?

EDIT 1

Ceci est le fichier entier, après la réponse suggérée ci-dessous:

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

Le rechargement de nginx alors des erreurs:

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

EDIT 2: plus de détails

Variables d'environnement actuelles

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

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

Configuration du site 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;

Rechargez la configuration 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


origine


Ce n'est pas une solution générique pour les variables d'environnement, mais si vous souhaitez utiliser des variables d'environnement pour les noms d'hôte / adresses IP des serveurs en amont, notez que Docker (du moins dans les versions récentes) modifie / etc / hosts pour vous. Voir docs.docker.com/userguide/dockerlinks    Cela signifie que si votre conteneur lié s'appelle 'app_web_1', docker créera une ligne dans / etc / hosts dans votre conteneur Nginx. Donc, vous pouvez simplement remplacer server $ENV{"APP_WEB_1_PORT_5000_TCP_ADDR"}:5000;    avec server app_web_1:5000; - mozz100
Merci @ mozz100 - c'est incroyablement utile - les entrées / etc / hosts sont beaucoup plus efficaces que env vars dans ce cas. Le seul élément manquant est ce qui se produit si le conteneur en amont est redémarré et acquiert une nouvelle adresse IP. Je suppose que les conteneurs enfants indiqueront toujours l'adresse IP d'origine, pas la nouvelle? - Hugo Rodger-Brown
Oui, si vous avez redémarré app_web_1 il obtiendrait une nouvelle adresse IP, vous devrez donc également redémarrer votre conteneur nginx. Docker le relancerait avec une mise à jour /etc/hosts vous n’avez donc pas besoin de modifier le (s) fichier (s) de configuration de nginx. - mozz100


Réponses:


Si vous utilisez un lien, docker configure les variables d’environnement et ajoute un alias pour le conteneur lié dans /etc/hosts. Si vous êtes capable de coder en dur le port (ou s'il ne s'agit que du port 80), vous pouvez simplement faire:

upstream gunicorn {
    server linked-hostname:5000;
}

Le port n’est disponible que dans une variable d’environnement, qui ne peut pas être utilisée dans upstream module, ni dans les blocs de serveur ou d’emplacement. Ils ne peuvent être référencés que dans la configuration principale, ce qui ne vous aide pas. Vous pouvez le faire avec le paquet ouvert cela inclut Lua.

Si vous ne voulez pas utiliser openresty / Lua, une autre option consiste à effectuer une substitution au démarrage du conteneur. Votre docker run La commande pourrait créer le lien, puis exécuter un script de wrapper qui effectue la substitution appropriée:

#!/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 - solution actuelle (de travail) est exactement cela. Semble juste un peu hacky. (Cela dit, il s’agit d’un environnement de développement local, le piratage informatique n’est donc pas un problème énorme.) - Hugo Rodger-Brown
Je suis tombé dessus, alors j'ai fait un peu plus générique conteneur nginx qui étend automatiquement les variables d’environnement dans la configuration. - Shepmaster


De le fichier officiel de docker Nginx:

Utilisation de variables d’environnement dans la configuration de nginx:

En sortie d'usine, Nginx ne prend pas en charge l'utilisation de variables d'environnement.   dans la plupart des blocs de configuration.

Mais envsubst peut être utilisé comme   solution de contournement si vous devez générer votre configuration nginx   dynamiquement avant que nginx ne commence.

Voici un exemple utilisant 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;'" 

Le fichier mysite.template peut alors contenir des références variables telles que   ce :

listen ${NGINX_PORT};

Mettre à jour:

Mais vous savez que cela a causé à ses variables Nginx comme ceci:

proxy_set_header        X-Forwarded-Host $host;

endommagé à:

proxy_set_header        X-Forwarded-Host ;

Donc, pour éviter cela, j'utilise cette astuce:

J'ai un script pour exécuter Nginx, utilisé sur le docker-compose fichier en tant qu'option de commande pour le serveur Nginx, je l'ai nommé run_nginx.sh:

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

Et à cause de la nouvelle définition DOLLAR variable sur run_nginx.sh script, maintenant contenu de mon nginx.conf.template Le fichier pour Nginx lui-même, la variable ressemble à ceci:

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

Et pour ma variable définie, c'est comme ça:

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

Également ici, il y a mon cas d'utilisation réel pour cela.


61
2018-02-11 12:39



Cela tue nginx confs comme proxy_set_header Host $http_host; - shredding
@shredding vous pouvez donner des noms de variables à remplacer - les autres ne sont pas touchés: command: /bin/bash -c "envsubst '$VAR1 $VAR2' < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" travaille pour moi b / c je sais comment ils s'appellent ... - pkyeck
ok, j'ai oublié d'échapper à la $, devrait être command: /bin/bash -c "envsubst '\$VAR1 \$VAR2' < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" - pkyeck
Si vous envisagez de vous échapper, cela fonctionne dans votre propre fichier 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
C'est une excellente solution. Merci. Aussi le lien mentionné ci-dessus github.com/docker-library/docs/issues/496 a une excellente solution pour le problème. - kabirbaidhya


Faire cela avec Lua est nettement plus facile qu'il n'y paraît:

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

J'ai trouvé ça ici:

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

Modifier:

Apparemment, cela nécessite l’installation du module lua: https://github.com/openresty/lua-nginx-module

Edit 2:

Notez qu'avec cette approche, vous devez définir env variable dans Nginx:

env ENVIRONMENT_VARIABLE_NAME

Vous devez le faire dans un contexte de niveau supérieur dans nginx.conf ou ça ne marchera pas! Pas dans le bloc serveur ou dans la config de certains sites en /etc/nginx/sites-available, car il est inclus par nginx.conf dans http contexte (qui n'est pas le contexte de niveau supérieur).

Notez également qu'avec cette approche, si vous essayez d'effectuer une redirection, par exemple:

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

ça ne marchera pas aussi bien:

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

Et si vous lui attribuez un nom de variable distinct:

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 ne l'interprète pas et vous redirigera vers https://%24server_name_from_env/.


26
2017-12-01 16:26



Tu pourrais avoir besoin de env NGINX_SERVERNAME quelque part dans votre nginx.conf. - hiroshi
Cela n'a pas fonctionné pour moi, bien que j'ai le module lua dans mon image de docker nginx. Cela pourrait-il être lié au fait que j'inclus un fichier de configuration dans mon nginx.conf? j'étais en train d'essayer de set_by_lua la variable dans le fichier de configuration inclus, tandis que le env MY_VAR la déclaration était dans le fichier principal nginx.conf, comme suggéré. Quel dommage, cela aurait été la solution la plus propre! - pederpansen
Est-ce que quelqu'un connaît le pour et le contre d'utiliser cette méthode? envsubst? Je suppose que le pro est que vous n'avez pas besoin d'exécuter le envsubstr commande avant de démarrer le serveur et le con est que vous devez installer le module lua? Je me demande s'il y a des implications pour la sécurité de l'une ou l'autre approche? - Mark Winterbottom
@MarkWinterbottom n'a pas encore testé cela, mais il semblerait que vous n'auriez pas à accorder un accès en écriture aux fichiers de configuration nginx que vous devez utiliser. envsubst et qui est un non-aller dans mon cas - Griddo


J'ai écrit quelque chose qui peut ou peut ne pas être utile: https://github.com/yawn/envplate

Il édite en ligne les fichiers de configuration avec des références $ {clé} aux variables d’environnement, en créant éventuellement des sauvegardes / journalisations. Il est écrit en Go et le binaire statique résultant peut être simplement téléchargé à partir de l'onglet de publication pour Linux et MacOS.

Il peut également exécuter des processus exec (), substituer des valeurs par défaut, des journaux et présenter une sémantique d’échec sensible.


14
2017-11-15 16:02





Ce que j'ai fait était d'utiliser le erb!

cat nginx.conf  | grep -i error_log

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

--Après l'utilisation de erb

export APP_ROOT=/tmp

erb nginx.conf  | grep -i error_log

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

Ceci est utilisé dans le Cloudfoundry staticfile-buildpack

Exemple de configuration de nginx: https://github.com/cloudfoundry/staticfile-buildpack/blob/master/conf/nginx.conf

Dans ton cas

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

devenir

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



Pouvez-vous développer sur cette réponse? Il convient de noter qu’il existe déjà une réponse acceptée à la question ci-dessus, mais si vous estimez que votre réponse ajoute de la valeur à cette question, développez-la. - BE77Y


En vous référant à la réponse sur l'utilisation de erb, cela peut être fait comme ci-dessous.

Ecrivez le fichier de configuration NGINX en tant que fichier erb contenant la variable d’environnement et évaluez-le à l’aide de la commande erb dans un fichier de configuration normal.

erb nginx.conf.erb > nginx.conf

Dans le bloc serveur du fichier nginx.conf.erb, il pourrait y avoir

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

4
2017-08-01 11:39



Dois-je installer Ruby dans le conteneur? (Si non, comment erb capable de faire la substitution de variable ... après le démarrage du conteneur, non?) - erb Ruby a-t-il raison? stuartellis.name/articles/erb - KajMagnus
C'est un outil de ligne de commande fourni avec l'installation standard de Ruby. Essayez d'autres options si vous ne l'avez pas dans le conteneur. - Ruifeng Ma
Ok, merci d'avoir expliqué - KajMagnus


Je sais que c'est une vieille question, mais juste au cas où quelqu'un tomberait (comme je l'ai maintenant), il y a une bien meilleure façon de le faire. Parce que docker insère l’alias du conteneur lié dans / etc / hosts, vous pouvez simplement faire

upstream upstream_name {
    server docker_link_alias;
}

en supposant que votre commande docker est quelque chose comme docker run --link othercontainer:docker_link_alias nginx_container.


3
2018-03-17 05:16



Vous pouvez obtenir l'hôte en utilisant cette méthode, mais pas le port. Vous devez coder le port en dur ou supposer qu’il utilise le port 80. - Ben Whaley