388 votes

Comment puis-je utiliser des variables d'environnement dans Nginx.conf ?

J'ai un conteneur docker exécutant 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 ne sont pas connus avant (elles sont dynamiques). Je veux que mon nginx.conf utilise ces valeurs - par exemple

upstream gunicorn {
    server $APP_HOST_NAME:$APP_HOST_PORT;
}

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

EDIT 1

Voici l'intégralité du fichier, après la réponse suggérée ci-dessous :

env APP_WEB_1_PORT_5000_TCP_ADDR;
# Configuration hôte Nginx pour l'application django_app 

# L'application Django est servie par Gunicorn, fonctionnant sous le 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 produit une erreur :

$ nginx -s reload
nginx: [emerg] directive inconnue "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

Nginx.conf racine :

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
# L'application Django est servie par Gunicorn, fonctionnant sous le port 5000 (via Foreman)
upstream gunicorn {
    server $ENV{"APP_WEB_1_PORT_5000_TCP_ADDR"}:5000;
}

server {
    listen 80;

Recharger la configuration nginx :

root@87ede56e0b11:/# nginx -s reload
nginx: [emerg] directive "server" is not terminated by ";" in /etc/nginx/sites-enabled/default:3

11 votes

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ôtes / 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 de votre conteneur Nginx. Vous pouvez donc simplement remplacer server $ENV{"APP_WEB_1_PORT_5000_TCP_ADDR"}:5000; par server app_web_1:5000;

1 votes

Merci @mozz100 - c'est incroyablement utile - les entrées /etc/hosts sont beaucoup plus efficaces que les variables d'environnement dans ce cas. La seule chose qui manque, c'est ce qui se passe si le conteneur amont est redémarré et acquiert une nouvelle adresse IP. Je suppose que les conteneurs enfants pointeront toujours vers l'adresse IP d'origine, pas la nouvelle ?

1 votes

Oui, si vous redémarriez app_web_1, il recevrait une nouvelle adresse IP, vous devriez donc redémarrer votre conteneur nginx aussi. Docker le redémarrerait avec un /etc/hosts mis à jour, vous n'auriez donc pas besoin de modifier le(s) fichier(s) de configuration nginx.

1voto

tomcam Points 183

En plus de la méthode lua et de la méthode js, il existe un moyen avec perl, surtout si nginx est déjà compilé avec --with-http_perl_module. Les parties importantes sont commentées en ligne :

# déclarer la variable
env ENDPOINT;

events {
    worker_connections 1024;
}

http {
    include mime.types;

    # stocker la variable de l'environnement en tant que variable nginx
    perl_set $endpoint 'sub { return $ENV{"ENDPOINT"}; }';

    server {
        listen 8080;
        root /usr/local/nginx;
        location / {
            sub_filter_once off;
            sub_filter_last_modified on;
            sub_filter_types application/javascript;

            # utiliser la variable, par exemple :
            sub_filter 'ENDPOINT' $endpoint;

            try_files $uri /testfile.js;
        }
    }
}

Soyez conscient que perl est un module dynamique et que vous avez probablement besoin d'installer libnginx-mod-http-perl ou nginx-extras :

apt-get install libnginx-mod-http-perl

0voto

Rich Points 727

Si vous avez besoin de le garder simple : bash eval sed
Et suivez deux règles simples : ${ENV_IN_PARENTHESIS} et utilisez toujours des guillemets ' dans le modèle
Vous pouvez échanger tous les variables d'environnement en un seul appel générique.

 eval "echo \"$(sed 's/\$/##/g; s/\##{/${/g;' some.template)\"" | sed 's/\##/$/g' > some.conf

Ce qui se passe :

A. $(sed 's/\$/##/g; s/\##{/${/g;' some.template)

Exécutez le modèle à travers sed et :
1. remplacez tous les caractères $ par ##
2. remplacez tous les ##{ par ${

B. eval "echo \"$(sed 's/\$/##/g; s/\##{/${/g;' some.template)\""

Exécute le modèle modifié à travers eval qui remplace les ${ENV_IN_PARENTHESIS} visibles

C. ... | sed 's/\##/$/g' > some.conf

Pipe le résultat de eval à un autre appel sed qui remet tous les $ originaux de ## et produit le résultat final dans votre nouveau fichier de configuration étincelant.

0voto

Dryice Liu Points 1

Reprenant la solution d'@omid, voici une façon de le faire sans script personnalisé et/ou sans modifier le script de point d'entrée par défaut de l'image Docker officielle de Nginx :

dans Dockerfile :

FROM nginx

# remplacez si nécessaire
ENV MY_VARIABLE='quelque chose'

# NE remplacez PAS ceci
ENV DOLLAR_SIGN='$'

COPY ./nginx.conf.template /etc/nginx/templates/default.conf.template

Dans le fichier local nginx.conf.template :

amont amont_server {
 server ${MY_VARIABLE}:8001 fail_timeout=0;
}

server {
 ...
 location / {
   proxy_set_header Host ${DOLLAR_SIGN}http_host;
   ....
   }
 }
}

0voto

ho raj Points 1

Nginx 1.19 prend en charge les variables d'environnement et les modèles dans Docker

Dans ce blog

1 votes

Bonjour! Veuillez publier des réponses complètes plutôt que des liens vers des articles de blog. Les liens peuvent se détériorer ou ne pas répondre directement à la question posée.

0voto

Cela a fonctionné pour moi.

set_by_lua $curr_domain_name 'return os.getenv("DOMAIN")';
add_header Content-Security-Policy 'script-src  ${curr_domain_name}';

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X