需求背景:
集群中,每一台服务器都有自己的Nginx, 转发请求到本机的应用. 应用与Nginx都通过Docker部署.随之而来的一个问题是,应用是无状态的,可以通过一个镜像在所有的机器上运行,而Nginx需要转发到本机的应用,在每台服务器的Nginx配置文件中不可避免地需要写上本机的内网IP,也就是镜像似乎不能通用.
在此,我想到的一种方法是,启动Nginx Docker容器时, 通过 –env 参数,传入一个自定义的环境变量到容器中,比如变量叫 HOST_IP, 通过 $ ifconfig eth0|grep inet|awk '{print $2}'获取本机内网IP赋值给HOST_IP,那么容器中的nginx.conf又如何才能读取到这个环境变量呢?
于是我查看了一些方法,其中有一种方法可供参考 -

查看Nginx的官方镜像,可以找到下面这段话

Using environment variables in nginx configuration
Out-of-the-box, nginx doesn’t support 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:

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

Nginx官方提供了一种用docker compose启动的方法,启动时传入两个环境变量到容器中,并挂载了一个mysite.template 的文件.在这里,这个文件是default.conf文件的复制,在这个文件中需要将被替换的值用变量表示,比如在正宗的nginx.conf中 proxy_pass http://本机ip:端口, 那么在mysite.template中则相应地表示为proxy_pass http://${NGINX_HOST}:${NGINX_PORT}, 通过 envsubst 命令以及输出输入重定向, nginx容器启动之后,相应的default.comf中的两个值就会被容器中的环境变量替换.
实际上这样仍然是不够的,命令envsubst < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf执行时,会将mysite.template 文件中所有带$ 符的字符视为变量读取出来, 然后找相应的环境变量做替换,再将最后的结果输出到default.conf中,然而nginx本身有许多的自定义变量如$host $remote_addr等,这些都会被envsubst命令做替换,而环境变量中并没有这些值,实际会造成这些都被替换成空值,导致最终的nginx.conf不合法而无法启动,所以要指定只替换我们需要的那两个变量.将上面的最后一行的命令修改为envsubst '$NGINX_HOST $NGINX_PORT' < /etc/nginx/mysite.template > /etc/nginx/default.conf即可
如果是在制作镜像时,想要加上这些,只需要修改nginx的Dockfile,比如增加如下内容:

COPY mysite.template /etc/nginx

CMD envsubst ‘$HOST_IP’ < /etc/nginx/mysite.template > /etc/nginx/nginx.conf && nginx -g ‘daemon off;’

制作镜像之后,相应的docker run命令为docker run --name nginx -p 80:80 -v /logs/nginx:/var/log/nginx --env HOST_IP=$(ifconfig eth0|grep inet|awk '{print $2}') --restart always -d nginx:image_tag,由此引申,任何文件需要读取环境变量都可以采用这种方法

在我需要使用上述方法时,其实还有一个原因,我们的应用容器名称是带有版本号的,也就是容器名不是固定的,假如应用的容器名是固定,在nginx.conf中转发应用通过指定的容器名,启动时让nginx link相应的容器即可,也就不用这么大费周折了.