Como posso usar variáveis de ambiente no Nginx.conf

167

[Cross-publicado e editado do link , já que foi considerado muito semelhante ao sysadmin para o StackOverflow.]

Eu tenho um contêiner do Docker executando o Nginx, que é vinculado a outro contêiner do Docker. O nome do host e o endereço IP do segundo contêiner são carregados no contêiner Nginx como variáveis de ambiente na inicialização, mas não são conhecidos antes (é dinâmico). Quero que meu nginx.conf use esses valores - por exemplo,

upstream gunicorn {
    server $APP_HOST_NAME:$APP_HOST_PORT;
}

Como posso obter variáveis de ambiente na configuração do Nginx na inicialização?

EDIT 1

Este é o arquivo inteiro, depois da resposta sugerida abaixo:

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

Recarregando nginx, em seguida, erros:

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

EDIT 2: mais detalhes

Variáveis de ambiente atuais

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

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

Configuração do nginx do site:

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;

Recarregar a configuração do nginx:

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

13 respostas

58

Se você estiver usando um link, o docker configura variáveis de ambiente e adiciona um alias para o contêiner vinculado em /etc/hosts . Se você é capaz de codificar a porta (ou se é apenas a porta 80), você pode simplesmente fazer:

upstream gunicorn {
    server linked-hostname:5000;
}

A porta está disponível apenas em uma variável de ambiente, que não pode ser usada no módulo upstream , nem em blocos de servidor ou local. Eles só podem ser referenciados na configuração principal, o que não ajuda você. Você poderia fazer isso com o pacote openresty que inclui Lua.

Se você não quiser usar openresty / Lua, outra opção é fazer alguma substituição na inicialização do contêiner. Seu comando docker run pode criar o link e executar um script de wrapper que realiza a substituição apropriada:

#!/bin/bash
/usr/bin/sed -i "s/server<gunicorn_server_placeholder>/${APP_WEB_1_PORT_5000_TCP_ADDR}/" default
start nginx
    
por 18.03.2014 / 07:14
88

a janela de encaixe Nginx oficial arquivo:

Using environment variables in nginx configuration:

Out-of-the-box, Nginx doesn't support using environment variables inside most configuration blocks.

But envsubst may be used as a workaround if you need to generate your nginx configuration dynamically before nginx starts.

Here is an example using 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;'" 

The mysite.template file may then contain variable references like this :

listen ${NGINX_PORT};

Atualização:

Mas você sabe disso causado a suas variáveis Nginx assim:

proxy_set_header        X-Forwarded-Host $host;

danificado para:

proxy_set_header        X-Forwarded-Host ;

Então, para evitar isso, eu uso esse truque:

Eu tenho um script para executar o Nginx, usado no arquivo docker-compose como opção de comando para o servidor Nginx, denominei run_nginx.sh :

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

E por causa da nova variável DOLLAR definida no script run_nginx.sh , agora o conteúdo do meu arquivo nginx.conf.template para a própria variável Nginx é assim:

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

E para minha variável definida é assim:

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

Também aqui , há o meu verdadeiro caso de uso para isso.

    
por 11.02.2016 / 13:39
29

Fazer isso com o Lua é substancialmente mais fácil do que parece:

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

Eu encontrei isso aqui:

link

Editar:

Aparentemente, isso requer a instalação do módulo lua: link

Editar 2:

Note que com essa abordagem você precisa definir a variável env no Nginx:

env ENVIRONMENT_VARIABLE_NAME

Você tem que fazer isso no contexto de primeiro nível em nginx.conf ou não vai funcionar! Não está no bloco do servidor ou na configuração de algum site em /etc/nginx/sites-available , porque está incluído no nginx.conf in http context (que não é o contexto de nível superior).

Observe também que, com essa abordagem, se você tentar redirecionar, por exemplo:

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

não funciona tão bem:

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

E se você der um nome de variável separado a ele:

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

O nginx não irá interpretá-lo e irá redirecioná-lo para https://%24server_name_from_env/ .

    
por 01.12.2015 / 17:26
14

Eu escrevi algo que pode ou não ser útil: link

Ele in-line edita arquivos de configuração com referências de $ {key} a variáveis de ambiente, opcionalmente criando backups / logs do que faz. Está escrito em Go e o binário estático resultante pode ser simplesmente baixado da aba de lançamento para Linux e MacOS.

Ele também pode executar processos (), substituir padrões, logs e semântica sensível de falhas.

    
por 15.11.2014 / 17:02
6

A imagem oficial do nginx recomenda o uso de envsubst , mas como apontado por outros ele substituirá também $host e outras variáveis, o que não é desejável . Mas, felizmente, envsubst pode tomar como parâmetro os nomes das variáveis para substituir .

Para evitar um parâmetro de comando muito complexo para o contêiner (como no exemplo vinculado), você pode escrever um script de ponto de entrada do Docker que preencherá as variáveis de ambiente antes de executar o comando. O script de ponto de entrada também é um bom lugar para validar os parâmetros e definir os valores padrão.

Aqui está um exemplo de um contêiner nginx que aceita os parâmetros API_HOST e API_PORT como variáveis de ambiente.

nginx-default.conf.template

resolver  127.0.0.11 valid=10s;  # recover from the backend's IP changing

server {
  listen  80;

  location / {
    root  /usr/share/nginx/html;
  }

  location /api {
    proxy_pass  http://${API_HOST}:${API_PORT};
    proxy_set_header  Host $http_host;
  }
}

docker-entrypoint.sh

#!/usr/bin/env sh
set -eu

envsubst '${API_HOST} ${API_PORT}' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf

exec "$@"

Dockerfile

FROM nginx:1.15-alpine

COPY nginx-default.conf.template /etc/nginx/conf.d/default.conf.template

COPY docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]
    
por 02.07.2018 / 19:28
5

O que eu fiz foi usar o erb !

cat nginx.conf  | grep -i error_log

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

- Depois de usar erb

export APP_ROOT=/tmp

erb nginx.conf  | grep -i error_log

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

Isso é usado no Cloudfoundry staticfile-buildpack

Exemplo de configuração do nginx: link

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

torne-se

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
}
    
por 20.02.2015 / 01:11
4

Referindo-se à resposta sobre o uso do erb, isso pode ser feito como abaixo.

Escreva o arquivo de configuração do NGINX como um arquivo erb contendo a variável de ambiente e avalie-o usando o comando erb para um arquivo de configuração normal.

erb nginx.conf.erb > nginx.conf

Dentro do bloco do servidor do arquivo nginx.conf.erb pode haver

listen <%= ENV["PORT"] %>;
    
por 01.08.2016 / 13:39
3

Eu sei que esta é uma questão antiga, mas apenas no caso de alguém se deparar com isso (como eu tenho agora), há uma maneira muito melhor de fazer isso. Como o docker insere o alias do contêiner vinculado em / etc / hosts, você pode apenas fazer

upstream upstream_name {
    server docker_link_alias;
}

assumindo que o seu comando docker é algo como docker run --link othercontainer:docker_link_alias nginx_container .

    
por 17.03.2016 / 06:16
2

Outra opção ... Acabei de encontrar esta ferramenta hoje: link ... Escrito em Go, pode ser instalado muito facilmente. Usá-lo é bem simples. Embora você precise colocar variáveis de modelo em seu nginx.conf.

Por exemplo, ${SOME_ENV_VAR} será substituído quando o comando ep do envplate for chamado no arquivo. Então, se o seu Dockerfile não conseguir esse binário ou se ele não for executado por algum motivo, isso tornará sua configuração inválida. Apenas uma pequena nota em comparação com outras soluções como o uso de extensões perl ou lua.

Eu realmente gosto de como você pode definir valores padrão também para quando a variável de ambiente não está definida. Ex. ${SOME_ENV_VAR:default-value} (e você pode escapar valores). Novamente, o envplate ainda deve ser executado com sucesso.

Uma vantagem de usar uma abordagem como essa é que você não acaba com uma imagem do Docker que é maior do que o necessário porque você instalou todos os tipos de módulos extras que você não precisa. Também pode ser mais fácil do que usar sed se as coisas começarem a ficar complexas e contiver essa funcionalidade de valor padrão.

    
por 20.07.2016 / 02:14
2

Eu faço isso usando um script de shell.

Aqui está o modelo 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;
    }

}

E o script para substituir as variáveis de ambiente está aqui:

echo sleep 3
sleep 3

echo build starting nginx config


echo replacing ___MY_DOMAIN_NAME___/$MY_DOMAIN_NAME
echo replacing ___PROXY_IP___/$LETSENCRYPT_IP
echo replacing ___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 "Need to set MY_DOMAIN_NAME"
    exit 1
fi  
if [ -z "$LETSENCRYPT_IP" ]; then
    echo "Need to set LETSENCRYPT_IP"
    exit 1
fi  
if [ -z "$LETSENCRYPT_PORT" ]; then
    echo "Need to set LETSENCRYPT_PORT"
    exit 1
fi
if [ -z "$LETSENCRYPT_HTTPS_IP" ]; then
    echo "Need to set LETSENCRYPT_HTTPS_IP"
    exit 1
fi 
if [ -z "$LETSENCRYPT_HTTPS_PORT" ]; then
    echo "Need to set LETSENCRYPT_HTTPS_PORT"
    exit 1
fi

nginx -g 'daemon off;'
    
por 20.01.2017 / 07:35
1

Outra possibilidade é usar o comando 'sed' com expressões regulares, então você não terá que mexer com seus arquivos de configuração! Dessa forma, você pode usar seus arquivos de configuração normalmente, mas quando você executar o docker, ele irá trocar os valores com as variáveis env. Nada disso "adiciona uma string de texto aos arquivos de configuração com os quais você pesquisa e substitui".

Você pode criar um arquivo run.sh com valores de substituição usando suas variáveis de ambiente.

Para alterar os "7s" nesta linha:

client_body_timeout 7s;         #Default 60s

Comando Sed usando client_body_timeout como linha de pesquisa e $ client_body_timeout como variável de env de substituição:

sed -i "s/\(client_body_timeout\).*\?\;/ $client_body_timeout;/" /usr/local/nginx/conf/nginx.conf

Copie / cole esta linha para cada parâmetro que você deseja definir e altere o client_body_timeout com a opção de configuração e $ client_body_timeout com a variável env que está associada. Use com o arquivo de configuração existente e ele só funcionará.

    
por 12.12.2017 / 21:53
0

Aqui está um exemplo do uso da abordagem sed , não necessariamente melhor, mas pode ser útil para alguns. Primeiro, adicione uma palavra-chave personalizada para ser substituída no arquivo conf. Segundo, crie um dockerfile que declare uma variável ENV e, em seguida, um CMD que use sed para editar a configuração antes de executar o nginx explicitamente.

Suponhamos que o default.conf contenha isso com a palavra-chave docker_host :

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

E escreva o seu Dockerfile como:

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

Em seguida, crie a imagem e execute o contêiner usando

docker run -d -p 80:80 -e "docker_host=${env:COMPUTERNAME}" imagename
    
por 23.09.2018 / 00:53
-1

Você deve poder fazer o que quiser com os modelos Dockerize .

    
por 20.05.2016 / 13:11

Tags