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.

6voto

Sabith K S Points 61

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

cat nginx.conf | grep -i error_log

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

--Après avoir utilisé 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

Configuration nginx d'exemple : https://github.com/cloudfoundry/staticfile-buildpack/blob/master/conf/nginx.conf

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

devient

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"] %>
}

#Après l'application de 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
}

6voto

Ruifeng Ma Points 181

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

Écrivez le fichier de configuration NGINX en tant que fichier erb contenant la variable d'environnement, et évaluez-le en utilisant la commande erb vers un fichier de configuration normal.

erb nginx.conf.erb > nginx.conf

À l'intérieur du bloc serveur du fichier nginx.conf.erb, il pourrait y avoir

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

1 votes

Est-ce que j'ai besoin d'installer Ruby ensuite, à l'intérieur du conteneur ? (Sinon, comment erb peut-il effectuer la substitution de variables ... après que le conteneur ait été démarré, n'est-ce pas ?) - erb est cette chose en Ruby, non : stuartellis.name/articles/erb

1 votes

C'est un outil en ligne de commande qui est livré avec l'installation standard de Ruby. Essayez d'autres options si vous ne l'avez pas dans le conteneur.

6voto

Geige V Points 161

J'accomplis cela en utilisant un script shell.

Voici le modèle nginx:

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

}

Et le script pour remplacer les variables d'environnement est ici:

echo "dormir 3"
dormir 3

echo "Construction de la configuration nginx en cours"

echo "remplacement de ___MY_DOMAIN_NAME___/$MY_DOMAIN_NAME"
echo "remplacement de ___PROXY_IP___/$LETSENCRYPT_IP"
echo "remplacement de ___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 "Besoin de définir MY_DOMAIN_NAME"
    exit 1
fi  
if [ -z "$LETSENCRYPT_IP" ]; then
    echo "Besoin de définir LETSENCRYPT_IP"
    exit 1
fi  
if [ -z "$LETSENCRYPT_PORT" ]; then
    echo "Besoin de définir LETSENCRYPT_PORT"
    exit 1
fi
if [ -z "$LETSENCRYPT_HTTPS_IP" ]; then
    echo "Besoin de définir LETSENCRYPT_HTTPS_IP"
    exit 1
fi 
if [ -z "$LETSENCRYPT_HTTPS_PORT" ]; then
    echo "Besoin de définir LETSENCRYPT_HTTPS_PORT"
    exit 1
fi

nginx -g 'daemon off;'

0 votes

Fonctionne parfaitement avec docker-compose.

5voto

Trung Lê Points 151

Il existe de nombreuses façons. Certaines ont été décrites dans certaines réponses.

Si vous utilisez le ngx_http_js_module, il existe également un moyen de le faire avec JS :

## /etc/nginx/fetch_env.js
function fetch_upstream_host(r) {
  return process.env.UPSTREAM_HOST;
}

function fetch_upstream_port(r) {
  return process.env.UPSTREAM_PORT;
}

et

## /etc/nginx/nginx.conf
load_module modules/ngx_http_js_module.so;

env UPSTREAM_HOST;
env UPSTREAM_PORT;

http {
  js_include fetch_env.js;
  js_set $upstream_host fetch_upstream_host;
  js_set $upstream_port fetch_upstream_port;

  server {
    ...

    location / {
      ...

      proxy_pass http://$upstream_host:$upstream_port;
    }
  }

Veuillez vous assurer d'utiliser le module njs 0.33 ou plus récent

1 votes

Une approche propre, cependant limitée en ce que les variables nginx ne peuvent être utilisées que dans les directives d'exécution, lors du traitement de chaque requête; nginx.org/en/docs/faq/variables_in_config.html. Par exemple, l'approche njs ne fonctionnera pas pour la plupart des directives de configuration telles que listen, server_name, etc.

4voto

TheAviator Points 1

Voici un exemple d'utilisation de l'approche sed, pas nécessairement meilleure mais cela peut être utile pour certains. Tout d'abord, ajoutez un mot-clé personnalisé à remplacer dans le fichier de configuration. Ensuite, créez un dockerfile qui déclare une variable ENV puis une CMD qui utilise sed pour modifier la configuration avant de lancer explicitement nginx.

Supposons que votre fichier default.conf contienne ceci avec le mot-clé docker_host:

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

Et écrivez votre Dockerfile de la manière suivante :

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

Ensuite, construisez l'image et exécutez le conteneur en utilisant

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

0 votes

Il pourrait être formulé un peu plus clairement proxy_pass http://__DOCKER_HOST__:9000/api;

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