我有一个运行 Nginx 的 docker 容器,它链接到另一个 docker 容器。第二个容器的主机名和 IP 地址在启动时作为环境变量加载到 Nginx 容器中,但在此之前不知道(它是动态的)。我希望我nginx.conf使用这些值 - 例如
upstream gunicorn {
server $APP_HOST_NAME:$APP_HOST_PORT;
}
Run Code Online (Sandbox Code Playgroud)
如何在启动时将环境变量添加到 Nginx 配置中?
编辑 1
这是整个文件,在下面的建议答案之后:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
重新加载nginx然后错误:
$ nginx -s reload
nginx: [emerg] unknown directive "env" in /etc/nginx/sites-enabled/default:1
Run Code Online (Sandbox Code Playgroud)
编辑 2:更多细节
当前环境变量
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
Run Code Online (Sandbox Code Playgroud)
根 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;
Run Code Online (Sandbox Code Playgroud)
站点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;
Run Code Online (Sandbox Code Playgroud)
重新加载nginx配置:
root@87ede56e0b11:/# nginx -s reload
nginx: [emerg] directive "server" is not terminated by ";" in /etc/nginx/sites-enabled/default:3
Run Code Online (Sandbox Code Playgroud)
Omi*_*aha 160
来自官方 Nginx docker 文件:
在 nginx 配置中使用环境变量:
开箱即用,Nginx 不支持在大多数配置块中使用环境变量。
但是
envsubst如果您需要在 nginx 启动之前动态生成 nginx 配置,则可以用作解决方法。这是一个使用 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;'"
Run Code Online (Sandbox Code Playgroud)
然后 mysite.template 文件可能包含这样的变量引用:
listen ${NGINX_PORT};
Run Code Online (Sandbox Code Playgroud)
更新:
但是你知道这会导致它的 Nginx 变量是这样的:
proxy_set_header X-Forwarded-Host $host;
Run Code Online (Sandbox Code Playgroud)
损坏到:
proxy_set_header X-Forwarded-Host ;
Run Code Online (Sandbox Code Playgroud)
所以,为了防止这种情况,我使用这个技巧:
我有一个运行 Nginx 的脚本,它在docker-compose文件上用作 Nginx 服务器的命令选项,我将其命名为run_nginx.sh:
#!/usr/bin/env bash
export DOLLAR='$'
envsubst < nginx.conf.template > /etc/nginx/nginx.conf
nginx -g "daemon off;"
Run Code Online (Sandbox Code Playgroud)
并且由于DOLLAR在run_nginx.sh脚本上定义了新变量,现在我nginx.conf.template的 Nginx 自身变量文件的内容是这样的:
proxy_set_header X-Forwarded-Host ${DOLLAR}host;
Run Code Online (Sandbox Code Playgroud)
对于我定义的变量是这样的:
server_name ${WEB_DOMAIN} www.${WEB_DOMAIN};
Run Code Online (Sandbox Code Playgroud)
同样在这里,有我真正的用例。
Esk*_*ola 71
官方 nginx 镜像推荐使用envsubst,但正如其他人指出的那样,它会替换 also$host和其他变量,这是不可取的。不过还好envsubst可以把变量名作为参数来替换。
为了避免对容器使用非常复杂的命令参数(如链接示例中所示),您可以编写一个 Docker 入口点脚本,该脚本将在执行命令之前填充环境变量。入口点脚本也是验证参数和设置默认值的好地方。
这是一个 nginx 容器的示例,它接受API_HOST和API_PORT参数作为环境变量。
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;
}
}
Run Code Online (Sandbox Code Playgroud)
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 "$@"
Run Code Online (Sandbox Code Playgroud)
文件
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;"]
Run Code Online (Sandbox Code Playgroud)
小智 47
用 Lua 做这件事比听起来容易得多:
server {
set_by_lua $server_name 'return os.getenv("NGINX_SERVERNAME")';
}
Run Code Online (Sandbox Code Playgroud)
我在这里发现:
https://docs.apitools.com/blog/2014/07/02/using-environment-variables-in-nginx-conf.html
编辑:
显然这需要安装 lua 模块:https : //github.com/openresty/lua-nginx-module
编辑2:
请注意,使用这种方法,您必须env在 Nginx 中定义变量:
env ENVIRONMENT_VARIABLE_NAME
Run Code Online (Sandbox Code Playgroud)
您必须在顶级上下文中执行此操作,nginx.conf否则将无法正常工作!不在服务器块或某些站点的配置中/etc/nginx/sites-available,因为它包含nginx.conf在http上下文中(不是顶级上下文)。
另请注意,如果您尝试使用这种方法进行重定向,例如:
server {
listen 80;
server_name $server_name;
return 301 https://$server_name$request_uri;
}
Run Code Online (Sandbox Code Playgroud)
它也不会起作用:
2016/08/30 14:49:35 [emerg] 1#0: the duplicate "server_name" variable in /etc/nginx/sites-enabled/default:8
Run Code Online (Sandbox Code Playgroud)
如果你给它一个单独的变量名:
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;
}
Run Code Online (Sandbox Code Playgroud)
nginx 不会解释它并将您重定向到https://%24server_name_from_env/.
Mar*_*tin 31
envsubstrnginx现在由图像自动处理。从文档:
开箱即用的 nginx 不支持大多数配置块内的环境变量。但是这个镜像有一个功能,会在nginx启动前提取环境变量。
默认情况下,该函数读取模板文件
/etc/nginx/templates/*.template并将执行结果输出envsubst到/etc/nginx/conf.d.
小智 21
这是另一个带有 envsubst 的。
nginxdocker 镜像已经运行envsubst完毕/docker-entrypoint.d/20-envsubst-on-templates.sh。您只需将模板文件放置在正确的位置:/etc/nginx/templates/my-file.conf.template.
然后,您可以template仅为具有一个或多个map子句的变量创建一个专用文件,我们将使用这些子句作为自定义变量。您必须为该conf.d文件选择一个名称,以便它成为 nginx 采用的第一个名称。
这是用 docker-compose 和三个文件解释的基本概念:
docker-compose.yml:
version: "3.9"
services:
nginx:
image: nginx:1.23
volumes:
- ./template-variables:/etc/nginx/templates/10-variables.conf.template:ro
environment:
EXTERNAL_IP: "1.2.3.4"
Run Code Online (Sandbox Code Playgroud)
模板变量:
map $host $external_ip {
default "$EXTERNAL_IP";
}
Run Code Online (Sandbox Code Playgroud)
nginx.conf:
server {
location / {
proxy_set_header X-Real-IP $external_ip;
}
}
Run Code Online (Sandbox Code Playgroud)
小智 15
我写了一些可能有用也可能没用的东西:https : //github.com/yawn/envplate
它使用 ${key} 对环境变量的引用内联编辑配置文件,可选择创建备份/记录它所做的事情。它是用 Go 编写的,生成的静态二进制文件可以简单地从 Linux 和 MacOS 的发布选项卡下载。
它还可以 exec() 处理、替换默认值、记录并具有合理的故障语义。
小智 6
参考使用erb的答案,可以如下完成。
将 NGINX 配置文件编写为包含环境变量的 erb 文件,并使用 erb 命令将其评估为普通配置文件。
erb nginx.conf.erb > nginx.conf
Run Code Online (Sandbox Code Playgroud)
在 nginx.conf.erb 文件的 server 块内可能有
listen <%= ENV["PORT"] %>;
Run Code Online (Sandbox Code Playgroud)
小智 6
我使用 shell 脚本完成此任务。
这是 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;
}
}
Run Code Online (Sandbox Code Playgroud)
替换环境变量的脚本在这里:
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;'
Run Code Online (Sandbox Code Playgroud)
我所做的是使用erb!
cat nginx.conf | grep -i error_log
error_log <%= ENV["APP_ROOT"] %>/nginx/logs/error.log;
Run Code Online (Sandbox Code Playgroud)
--使用erb后
export APP_ROOT=/tmp
erb nginx.conf | grep -i error_log
error_log /tmp/nginx/logs/error.log;
Run Code Online (Sandbox Code Playgroud)
这在Cloudfoundry staticfile-buildpack 中使用
nginx 配置示例:https : //github.com/cloudfoundry/staticfile-buildpack/blob/master/conf/nginx.conf
在你的情况下
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;
}
Run Code Online (Sandbox Code Playgroud)
变得
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
}
Run Code Online (Sandbox Code Playgroud)
小智 5
有很多方法。有些已经在一些答案中概述了。
如果您使用ngx_http_js_module,还有一种方法可以使用 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;
}
Run Code Online (Sandbox Code Playgroud)
和
## /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;
}
}
Run Code Online (Sandbox Code Playgroud)
请确保您使用 njs 模块 0.33 或更高版本
| 归档时间: |
|
| 查看次数: |
322807 次 |
| 最近记录: |