Pregunta ¿Cómo puedo usar las variables de entorno en Nginx.conf?


[Publicada y editada en forma cruzada desde https://stackoverflow.com/questions/21933955 ya que se consideró demasiado similar a sysadmin para StackOverflow.]

Tengo un contenedor docker que ejecuta Nginx, que enlaza con otro contenedor docker. El nombre de host y la dirección IP del segundo contenedor se cargan en el contenedor Nginx como variables de entorno en el inicio, pero no se conocen antes (es dinámico). Quiero mi nginx.conf para utilizar estos valores, p. ej.

upstream gunicorn {
    server $APP_HOST_NAME:$APP_HOST_PORT;
}

¿Cómo puedo obtener las variables de entorno en la configuración de Nginx en el inicio?

EDITAR 1

Este es el archivo completo, después de la respuesta sugerida a continuación:

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

Recargando nginx entonces errores:

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

EDIT 2: más detalles

Variables de entorno actuales

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

Raíz 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;

Configuración del sitio 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;

Recargar la configuración de 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


origen


Esta no es una solución genérica para las variables de entorno, pero si desea utilizar variables de entorno para los nombres de host / direcciones IP de los servidores ascendentes, tenga en cuenta que Docker (al menos en las versiones recientes) modifica / etc / hosts por usted. Ver docs.docker.com/userguide/dockerlinks    Esto significa que si su contenedor vinculado se llama 'app_web_1', la ventana acoplable creará una línea en / etc / hosts en su contenedor Nginx. Así que solo puedes reemplazar server $ENV{"APP_WEB_1_PORT_5000_TCP_ADDR"}:5000;    con server app_web_1:5000; - mozz100
Gracias @ mozz100 - eso es increíblemente útil - las entradas de / etc / hosts son mucho más efectivas que las de env en este caso. Lo único que falta es lo que sucede si se reinicia el contenedor ascendente y adquiere una nueva IP. Supongo que los contenedores secundarios seguirán apuntando a la IP original, no a la nueva? - Hugo Rodger-Brown
Si reiniciaste app_web_1 obtendría una nueva dirección IP, por lo que también necesitaría reiniciar su contenedor nginx. Docker lo reiniciaría con una actualización. /etc/hosts por lo que no necesitarías alterar los archivos de configuración de nginx. - mozz100


Respuestas:


Si está utilizando un enlace, la ventana acoplable configura las variables de entorno y agrega un alias para el contenedor vinculado en /etc/hosts. Si puede codificar el puerto (o si es solo el puerto 80) simplemente puede hacer:

upstream gunicorn {
    server linked-hostname:5000;
}

El puerto solo está disponible en una variable de entorno, que no se puede utilizar en el upstream Módulo, ni en servidor o bloques de ubicación. Solo pueden ser referenciados en la configuración principal, lo que no ayuda. Podrías hacer esto con el paquete abierto Eso incluye a Lua.

Si no desea utilizar openresty / Lua, otra opción es hacer alguna sustitución al iniciar el contenedor. Tu docker run comando podría crear el enlace y luego ejecutar un script de envoltorio que realice la sustitución apropiada:

#!/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



Sí, la solución actual (en funcionamiento) es exactamente esto. Simplemente parece un poco hacky. (Dicho esto, es solo un entorno de desarrollo local, por lo que la piratería no es un gran problema). - Hugo Rodger-Brown
Me encontré con esto, así que hice un poco más genérico contenedor nginx Eso expande automáticamente las variables de entorno en la configuración. - Shepmaster


Desde el archivo docker oficial de Nginx:

Usando variables de entorno en la configuración de nginx:

Fuera de la caja, Nginx no admite el uso de variables de entorno   Dentro de la mayoría de los bloques de configuración.

Pero envsubst puede ser utilizado como un   solución alternativa si necesita generar su configuración nginx   dinámicamente antes de que comience el nginx.

Aquí hay un ejemplo usando 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;'" 

El archivo mysite.template puede contener referencias de variables como   esta :

listen ${NGINX_PORT};

Actualizar:

Pero sabes que esto causó a sus variables Nginx como esta:

proxy_set_header        X-Forwarded-Host $host;

dañado a

proxy_set_header        X-Forwarded-Host ;

Entonces, para evitar eso, uso este truco:

Tengo un script para ejecutar Nginx, que se utiliza en el docker-compose Archivo como opción de comando para el servidor Nginx, lo nombré run_nginx.sh:

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

Y debido a la nueva definición DOLLAR variable en run_nginx.sh guión, ahora contenido de mi nginx.conf.template El archivo para la propia variable Nginx es así:

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

Y para mi variable definida es así:

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

también aquí, hay un caso de uso real para eso.


61
2018-02-11 12:39



Eso mata nginx confs como proxy_set_header Host $http_host; - shredding
@shredding puede pasar los nombres de las variables que se van a reemplazar, otros no se tocan: command: /bin/bash -c "envsubst '$VAR1 $VAR2' < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" trabaja para mí b / c sé cómo se llaman ... - pkyeck
ok olvidé escapar del $, debiera ser command: /bin/bash -c "envsubst '\$VAR1 \$VAR2' < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" - pkyeck
Con consideración para escapar, esto funciona en su propio archivo Docker: 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
Esta es una gran solución. Gracias. También el enlace mencionado anteriormente. github.com/docker-library/docs/issues/496 Tiene una gran solución para el problema. - kabirbaidhya


Hacer esto con Lua es mucho más fácil de lo que parece:

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

Lo encontré aquí:

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

Editar:

Al parecer esto requiere instalar el módulo lua: https://github.com/openresty/lua-nginx-module

Edición 2:

Tenga en cuenta que con este enfoque tiene que definir env variable en Nginx:

env ENVIRONMENT_VARIABLE_NAME

Tienes que hacer esto en un contexto de alto nivel en nginx.conf o no funcionará! No en el bloque del servidor o en la configuración de algún sitio en /etc/nginx/sites-available, porque está incluido por nginx.conf en http contexto (que no es el contexto de nivel superior).

También tenga en cuenta que con este enfoque, si intenta realizar una redirección, por ejemplo:

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

no funcionará tan bien

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

Y si le das un nombre de variable separado:

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 no lo interpretará y lo redireccionará a https://%24server_name_from_env/.


26
2017-12-01 16:26



tu puedes necesitar env NGINX_SERVERNAME En algún lugar en su nginx.conf. - hiroshi
Esto no funcionó para mí, aunque tengo el módulo lua en mi imagen nginx docker. ¿Podría estar relacionado con el hecho de que incluya un archivo de configuración en mi nginx.conf? Estaba intentando set_by_lua la variable en el archivo de configuración incluido, mientras que la variable env MY_VAR La declaración estaba en el nginx.conf principal, como se sugirió. ¡Qué pena, esta habría sido la solución más limpia! - pederpansen
¿Alguien sabe los pros / contras de usar este método de envsubst? Supongo que el profesional es que no necesita ejecutar el envsubstr comando antes de iniciar el servidor y la contra es que necesita instalar el módulo lua? Me pregunto si hay implicaciones de seguridad en cualquiera de los enfoques. - Mark Winterbottom
@MarkWinterbottom no probó esto todavía, pero parece que no tendría que otorgar acceso de escritura a los archivos de configuración nginx, que tiene que usar envsubst y que es un no-go en mi caso - Griddo


Escribí algo que puede o no ser útil: https://github.com/yawn/envplate

Edita en línea los archivos de configuración con las referencias de $ {clave} a las variables de entorno, creando opcionalmente copias de seguridad / registro de lo que hace. Está escrito en Go y el binario estático resultante se puede descargar simplemente desde la pestaña de lanzamiento para Linux y MacOS.

También puede exec () procesos, sustituir valores predeterminados, registros y tiene una semántica de fallos sensible.


14
2017-11-15 16:02





Lo que hice fue usar el erb!

cat nginx.conf  | grep -i error_log

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

--Después de usar erb

export APP_ROOT=/tmp

erb nginx.conf  | grep -i error_log

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

Esto se usa en el Cloudfoundry staticfile-buildpack

Ejemplo de configuración nginx: https://github.com/cloudfoundry/staticfile-buildpack/blob/master/conf/nginx.conf

En tu caso

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

volverse

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



¿Puedes ampliar esta respuesta? Vale la pena señalar que hay una respuesta ya aceptada a esta pregunta anterior, pero si cree que su respuesta agrega valor a esto, entonces amplíelo. - BE77Y


Refiriéndose a la respuesta sobre el uso de erb, se puede hacer de la siguiente manera.

Escriba el archivo de configuración NGINX como un archivo erb que contiene la variable de entorno y evalúelo usando el comando erb para obtener un archivo de configuración normal.

erb nginx.conf.erb > nginx.conf

Dentro del bloque del servidor del archivo nginx.conf.erb podría haber

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

4
2017-08-01 11:39



¿Necesito instalar Ruby entonces, dentro del contenedor? (Si no, como esta erb capaz de hacer una sustitución variable ... después de que se inició el contenedor, ¿verdad?) - erb Es esto correcto Ruby: stuartellis.name/articles/erb - KajMagnus
Es una herramienta de línea de comandos que viene con la instalación estándar de Ruby. Prueba otras opciones si no lo tienes en el contenedor. - Ruifeng Ma
Ok gracias por explicar - KajMagnus


Sé que esta es una pregunta antigua, pero en caso de que alguien se tropiece con esto (como ahora lo he hecho), hay una manera mucho mejor de hacerlo. Debido a que la ventana acoplable inserta el alias del contenedor vinculado en / etc / hosts, puede simplemente hacer

upstream upstream_name {
    server docker_link_alias;
}

Asumiendo que el comando de la ventana acoplable es algo docker run --link othercontainer:docker_link_alias nginx_container.


3
2018-03-17 05:16



Puede obtener el host utilizando este método pero no el puerto. Tienes que codificar el puerto o asumir que está usando el puerto 80. - Ben Whaley