我正在尝试在通过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;
}
下面是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;"]
以下是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;'"
似乎正在发生的事情是,当我在上游块中(在“服务器”之后)引用$ 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
当我尝试使用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
我很困,所以在此先感谢您的帮助。
答案 0 :(得分:7)
Since 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
我要从文档中的示例中删除一些脚本。请注意模板文件上的额外.conf
扩展名-这不是错字。在Nginx图片的文档中,建议命名文件,例如default.conf.template
。启动后,脚本将获取该文件,替换环境变量,然后使用原始文件名将文件输出到/etc/nginx/conf.d/,并删除后缀.template
。
默认情况下,后缀为.template
,但这会破坏语法高亮显示,除非您配置编辑器。相反,我指定了.conf
作为模板后缀。如果仅将文件命名为default.conf
,则结果将是名为/etc/nginx/conf.d/default的文件,并且不会按预期提供您的网站。
答案 1 :(得分:2)
通过定义自己的入口点,可以避免Compose解释环境变量带来的麻烦。看这个简单的例子:
#!/bin/sh
export NGINXPROXY
envsubst '${NGINXPROXY}' < /config.template > /etc/nginx/nginx.conf
exec "$@"
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;"]
我的config
文件与您的nginx.conf
的内容相同,除了我必须使用Perl模块对行进行注释之外。
请注意,我必须先envsubst
将配置文件挂载到另一个位置。我遇到了一些奇怪的行为,即替换后文件最终为空,这种方式可以避免这种情况。在您的特定情况下这应该不成问题,因为您已经在构建时将其嵌入到映像中。
编辑
为了完整起见,要尽可能少地更改设置,只需确保export
环境变量即可。像这样修改您的命令:
command: ["/bin/bash", "-c", "export NGINXPROXY && envsubst '$$NGINXPROXY' < /etc/nginx/nginx.conf > /etc/nginx/nginx.conf && nginx -g 'daemon off;'"]
...而且您应该很好。不过,我总是建议您使用“清洁”的方式定义自己的入口点。
答案 2 :(得分:1)
像 explained in Jody's answer 一样,现在官方的 Nginx Docker 镜像支持解析模板。这使用 envsubst
和 its handling 确保不会混淆 Nginx variables,例如 $host
和所有。好的。但是,在使用 envsubst
时,${MY_VAR:-My Default}
不支持像常规 shell 和 Docker Compose 那样支持的默认值。因此,即使使用默认值,这种内置模板也始终需要对所有变量进行完整设置。
要在图像本身中定义默认值,可以使用自定义入口点首先设置默认值,然后简单地委托给 the original entrypoint。像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 "$@"
还有一些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;
}
}
在 Dockerfile 中将模板复制到 /etc/nginx/templates/default.conf.template
中并设置自定义入口点:
FROM nginx:stable-alpine
...
# Each time Nginx is started it will perform variable substition in all template
# files found in `/etc/nginx/templates/*.template`, and copy the results (without
# the `.template` suffix) into `/etc/nginx/conf.d/`. Below, this will replace the
# original `/etc/nginx/conf.d/default.conf`; see https://hub.docker.com/_/nginx
COPY docker-nginx-default.conf /etc/nginx/templates/default.conf.template
COPY docker-defaults.sh /
# Just in case the file mode was not properly set in Git
RUN chmod +x /docker-defaults.sh
# This will delegate to the original Nginx `docker-entrypoint.sh`
ENTRYPOINT ["/docker-defaults.sh"]
# The default parameters to ENTRYPOINT (unless overruled on the command line)
CMD ["nginx", "-g", "daemon off;"]
现在使用,例如,docker run --env PROXY_API_DEST=https://example.com/api/ ...
将设置一个值,在此示例中,如果未设置,则默认为 http://host.docker.internal:8000/api/
(在本地机器上实际上是 http://localhost:8000/api/
)。>
答案 3 :(得分:0)
因此,在对此问题进行了一些努力之后,我设法使其工作与贝拉肯提供的答案类似。如果有人需要参考完整的解决方案,我将在此处发布确切的解决方案。
第一步:按照通常的方式编写您的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;
}
步骤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;
}
第3步:在docker-file中,将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;"]
第4步:使用“环境”部分标签在docker-compos.yml文件中设置环境变量。确保您的环境变量名称与您在nginx配置文件中选择的任何变量名称匹配。在泊坞窗容器中使用“ 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;'"
第5步:使用docker-compose up(使用所需的任何其他开关)运行堆栈,并且nginx服务器现在应该以docker-compose.yml的“ environment”部分中提供的任何值开头。 >
如上面的解决方案中所述,您也可以定义自己的入口点,但是事实证明该解决方案可以很好地工作,并将所有内容都包含在单个配置文件中,使我能够运行服务栈直接从git中获取,只有一个docker-compose.yml文件。
非常感谢所有花时间为这一问题做准备的人,并且贝拉肯花时间帮助我解决问题。