Mik*_*ike 11 nginx environment-variables docker docker-compose
我正在尝试在通过 docker-compose 配置的 docker 容器中启动 NGINX 服务器。然而,问题是我想替换 http 部分内的环境变量,特别是在“上游”块内。
让它工作会很棒,因为我还有其他几个容器都是通过环境变量配置的,并且我有大约 5 个环境需要在任何给定时间运行。我曾尝试使用“envsubst”(如官方 NGINX 文档所建议的)、perl_set 和 set_by_lua,但是它们似乎都不起作用。
下面是 NGINX 配置,因为它是在我最近的试用之后
user nginx;
worker_processes 1;
env NGINXPROXY;
load_module modules/ngx_http_perl_module.so;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
perl_set $nginxproxy 'sub { return $ENV{"NGINXPROXY"}; }';
upstream api-upstream {
server ${nginxproxy};
}
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile off;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
Run Code Online (Sandbox Code Playgroud)
下面是 NGINX dockerfile
# build stage
FROM node:latest
WORKDIR /app
COPY ./ /app
RUN npm install
RUN npm run build
# production stage
FROM nginx:1.17.0-perl
COPY --from=0 /app/dist /usr/share/nginx/html
RUN apt-get update && apt-get install -y gettext-base
RUN rm /etc/nginx/conf.d/default.conf
RUN rm /etc/nginx/nginx.conf
COPY default.conf /etc/nginx/conf.d
COPY nginx.conf /etc/nginx
RUN mkdir /certs
EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]
Run Code Online (Sandbox Code Playgroud)
下面是 NGINX 服务器的 docker-compose.yml 部分(名称和 IP 已更改)。在我的故障排除中, envsubst 命令在这一点上被有意注释掉。
front-end:
environment:
- NGINXPROXY=172.31.67.100:9300
build: http://gitaccount:password@gitserver.com/group/front-end.git#develop
container_name: qa_front_end
image: qa-front-end
restart: always
networks:
qa_network:
ipv4_address: 172.28.0.215
ports:
- "9080:80"
# command: /bin/bash -c "envsubst '$$NGINXPROXY' < /etc/nginx/nginx.conf > /etc/nginx/nginx.conf && nginx -g 'daemon off;'"
Run Code Online (Sandbox Code Playgroud)
似乎正在发生的事情是,当我在上游块中引用 $nginxproxy 变量时(就在“服务器”之后),我得到的输出使它看起来像是在引用字符串文字“$nginxproxy”而不是替换变量的值.
qa3_front_end | 2019/06/18 12:35:36 [emerg] 1#1: host not found in upstream "${nginx_upstream}" in /etc/nginx/nginx.conf:19
qa3_front_end | nginx: [emerg] host not found in upstream "${nginx_upstream}" in /etc/nginx/nginx.conf:19
qa3_front_end exited with code 1
Run Code Online (Sandbox Code Playgroud)
当我尝试使用 envsubst 时,我收到一个错误,它听起来像是命令与 nginx.conf 文件的格式混淆
qa3_front_end | 2019/06/18 12:49:02 [emerg] 1#1: no "events" section in configuration
qa3_front_end | nginx: [emerg] no "events" section in configuration
qa3_front_end exited with code 1
Run Code Online (Sandbox Code Playgroud)
我很困惑,所以提前感谢您的帮助。
Jod*_*ody 19
从 nginx 1.19 开始,您现在可以使用 docker-compose 在您的配置中使用环境变量。我使用了以下设置:
# file: docker/nginx/templates/default.conf.conf
upstream api-upstream {
server ${API_HOST};
}
# file: docker-compose.yml
services:
nginx:
image: nginx:1.19-alpine
volumes:
- "./docker/nginx/templates:/etc/nginx/templates/"
environment:
NGINX_ENVSUBST_TEMPLATE_SUFFIX: ".conf"
API_HOST: api.example.com
Run Code Online (Sandbox Code Playgroud)
我将从文档中的示例中稍微偏离脚本。请注意.conf模板文件上的额外扩展名 - 这不是拼写错误。在 nginx 映像的文档中,建议将文件命名为default.conf.template. 启动时,脚本将获取该文件,替换环境变量,然后使用原始文件名将文件输出到 /etc/nginx/conf.d/,去掉.template后缀。
默认情况下,后缀是.template,但这会破坏语法突出显示,除非您配置编辑器。相反,我指定.conf为模板后缀。如果你只命名你的文件default.conf,结果将是一个名为 /etc/nginx/conf.d/default 的文件,你的站点将不会按预期提供服务。
您可以通过定义自己的入口点来避免 Compose 解释环境变量的一些麻烦。看这个简单的例子:
#!/bin/sh
export NGINXPROXY
envsubst '${NGINXPROXY}' < /config.template > /etc/nginx/nginx.conf
exec "$@"
Run Code Online (Sandbox Code Playgroud)
version: "3.7"
services:
front-end:
image: nginx
environment:
- NGINXPROXY=172.31.67.100:9300
ports:
- 80:80
volumes:
- ./config:/config.template
- ./entrypoint.sh:/entrypoint.sh
entrypoint: ["/entrypoint.sh"]
command: ["nginx", "-g", "daemon off;"]
Run Code Online (Sandbox Code Playgroud)
除了我必须使用 Perl 模块对行进行注释这一事实之外,我的config文件与您的nginx.conf.
请注意,我必须先将配置文件挂载到另一个位置,然后才能安装envsubst。我遇到了一些奇怪的行为,即替换后文件最终为空,这种情况可以通过这种方法来避免。在您的特定情况下,这应该不是问题,因为您已经在构建时将其嵌入到您的图像中。
编辑
为了完整起见,要尽可能少地更改您的设置,您只需要确保您export的环境变量。像这样调整你的命令:
command: ["/bin/bash", "-c", "export NGINXPROXY && envsubst '$$NGINXPROXY' < /etc/nginx/nginx.conf > /etc/nginx/nginx.conf && nginx -g 'daemon off;'"]
Run Code Online (Sandbox Code Playgroud)
......你应该很高兴去。不过,我总是建议使用“更干净”的方式来定义您自己的入口点。
就像Jody 的回答中已经解释的那样,现在官方的 Nginx Docker 镜像支持解析模板。这种使用envsubst及其处理确保不会弄乱诸如此类的Nginx 变量$host。好的。但是,envsubst它不支持像常规 shell 和 Docker Compose 在使用${MY_VAR:-My Default}. 因此,这个内置模板始终需要所有变量的完整设置,即使使用默认值也是如此。
要在图像本身中定义默认值,可以使用自定义入口点首先设置默认值,然后简单地委托给原始入口点。像一个docker-defaults.sh:
#!/usr/bin/env sh
set -eu
# As of version 1.19, the official Nginx Docker image supports templates with
# variable substitution. But that uses `envsubst`, which does not allow for
# defaults for missing variables. Here, first use the regular command shell
# to set the defaults:
export PROXY_API_DEST=${PROXY_API_DEST:-http://host.docker.internal:8000/api/}
# Due to `set -u` this would fail if not defined and no default was set above
echo "Will proxy requests for /api/* to ${PROXY_API_DEST}*"
# Finally, let the original Nginx entry point do its work, passing whatever is
# set for CMD. Use `exec` to replace the current process, to trap any signals
# (like Ctrl+C) that Docker may send it:
exec /docker-entrypoint.sh "$@"
Run Code Online (Sandbox Code Playgroud)
比如说,一些docker-nginx-default.conf:
# After variable substitution, this will replace /etc/nginx/conf.d/default.conf
server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location /api/ {
# Proxy API calls to another destination; the default for the variable is
# set in docker-defaults.sh
proxy_pass $PROXY_API_DEST;
}
}
Run Code Online (Sandbox Code Playgroud)
在 Dockerfile 中将模板复制到/etc/nginx/templates/default.conf.template并设置自定义入口点:
# After variable substitution, this will replace /etc/nginx/conf.d/default.conf
server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location /api/ {
# Proxy API calls to another destination; the default for the variable is
# set in docker-defaults.sh
proxy_pass $PROXY_API_DEST;
}
}
Run Code Online (Sandbox Code Playgroud)
现在使用,例如,docker run --env PROXY_API_DEST=https://example.com/api/ ...将设置一个值,在本例中,如果未设置,则默认为该值http://host.docker.internal:8000/api/(实际上 http://localhost:8000/api/在本地计算机上)。
因此,在解决了这个问题之后,我设法使其与 bellackn 提供的答案类似。我将在这里发布我的确切解决方案,以防其他人需要参考完整的解决方案。
步骤 1:按照通常的方式编写 nginx.conf 或 default.conf。将文件另存为“nginx.conf.template”或“default.conf.template”,具体取决于您尝试将变量替换为哪个。
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
upstream api-upstream {
server 192.168.25.254;
}
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile off;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
Run Code Online (Sandbox Code Playgroud)
步骤 2:将 ${VARNAME} 格式的变量替换为要替换为环境变量的任何值:
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
upstream api-upstream {
server ${SERVER_NAME};
}
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile off;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
Run Code Online (Sandbox Code Playgroud)
第 3 步:在您的 docker 文件中,将您的 nginx 配置文件(您的 nginx.conf.template 或 default.conf.template)复制到您的容器中的适当位置:
# build stage
FROM node:latest
WORKDIR /app
COPY ./ /app
RUN npm install
RUN npm run build
# production stage
FROM nginx:1.17.0-perl
COPY --from=0 /app/dist /usr/share/nginx/html
RUN apt-get update && apt-get install -y gettext-base
RUN rm /etc/nginx/conf.d/default.conf
RUN rm /etc/nginx/nginx.conf
#-----------------------------------#
|COPY default.conf /etc/nginx/conf.d|
|COPY nginx.conf.template /etc/nginx|
#-----------------------------------#
RUN mkdir /certs
EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]
Run Code Online (Sandbox Code Playgroud)
第 4 步:使用“环境”部分标签在 docker-compos.yml 文件中设置环境变量。确保您的环境变量名称与您在 nginx 配置文件中选择的任何变量名称相匹配。使用 docker 容器中的“envsubt”命令将变量值替换为 nginx.conf.template 中的变量,并将输出写入正确位置的名为 nginx.conf 的文件。这可以通过使用“命令”部分标签在 docker-compose.yml 文件中完成:
version: '2.0'
services:
front-end:
environment:
- SERVER_NAME=172.31.67.100:9100
build: http://git-account:git-password@git-server.com/project-group/repository-name.git#branch-ame
container_name: qa_front_end
image: qa-front-end-vue
restart: always
networks:
qa_network:
ipv4_address: 172.28.0.215
ports:
- "9080:80"
command: >
/bin/sh -c
"envsubst '
$${SERVER_NAME}
'< /etc/nginx/nginx.conf.template
> /etc/nginx/nginx.conf
&& nginx -g 'daemon off;'"
Run Code Online (Sandbox Code Playgroud)
第 5 步:使用 docker-compose up 运行您的堆栈(使用您需要的任何其他开关),您的 nginx 服务器现在应该以您在 docker-compose.yml 的“环境”部分中提供的任何值开始
正如上面的解决方案中提到的,你也可以定义你自己的入口点,但是这个解决方案也被证明工作得很好,并将所有内容保存在一个配置文件中,让我能够直接从 git 运行一堆服务只有一个 docker-compose.yml 文件。
非常感谢所有花时间准备完成这件事的人,并感谢您花时间帮助我解决问题。
| 归档时间: |
|
| 查看次数: |
24625 次 |
| 最近记录: |