跳转至

Nginx容器如何通过环境变量设置配置文件

使用Nginx容器时,一定会有个需求,那就是通过环境变量来设置配置文件,因为在容器中,对于一些易变且常用的配置,用环境变量会比修改配置文件更容易,比如代理的地址,端口等等。

但是我们知道Nginx并不支持在配置文件中使用环境变量,所以我们需要通过一些方式来实现这个需求,且不需要改Nginx的源码。经过思考发现可以用工具去替换配置文件中的环境变量,这样就可以实现了,以下是一个有效方案:

支持环境变量设置配置
支持环境变量设置配置
  • nginx.conf.tempalte:指的是配置文件模板,这个文件中会有一些环境变量,比如${SERVER_IP}${SERVER_PORT}等等

  • 转换工具:用于将模板文件中的环境变量替换成真实值。能实现该功能的方式很多,我这里只展示其中2种。

  • nginx.confNginx的配置文件,由nginx.conf.tempalteSubstitution Tool处理后生成的。

转换工具: envsubst(推荐)

envsubst是一个非常简单的工具,它可以将环境变量替换成真实值,比如:

envsubst '${SERVER_IP} ${SERVER_PORT}' < /path/to/nginx.conf.template > /path/to/nginx.conf

上述命令会将 /path/to/nginx.conf.template 中的 ${SERVER_IP}${SERVER_PORT} 替换成真实值,然后输出到 /path/to/nginx.conf 中。

假设nginx.conf.template的内容如下:

worker_processes  1;

events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;

    keepalive_timeout  65;

    server {
        listen       80;
        server_name  localhost;

        proxy_set_header Client-Port $remote_port;
        proxy_set_header Client-IP   $remote_addr;

        location / {
            proxy_pass http://${SERVER_IP}:${SERVER_PORT};
        }
    }
}

我们设置环境变量为:export SERVER_IP=192.168.8.10export SERVER_PORT=8080

经过替换工具后,它将产生下面的结果:

worker_processes  1;

events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;

    keepalive_timeout  65;

    server {
        listen       80;
        server_name  localhost;

        proxy_set_header Client-Port $remote_port;
        proxy_set_header Client-IP   $remote_addr;

        location / {
            proxy_pass http://192.168.8.10:8080;
        }
    }
}

大家应该注意到了,nginx.conf.template中还有别的变量,但是并没有被替换,这是因为我在envsubst种指定了要替代的变量名,这一点尤其重要:envsubst '${SERVER_IP} ${SERVER_PORT}'

但是只有上面还不够,我们需要跟容器结合,这里就分别给Dockerfile和docker-compose.yml给出示例。

docker-compose.yml示例如下:

version: '3.8'

services:
  proxy:
    image: homqyy/hengine
    command: bash -c "envsubst '${SERVER_IP} ${SERVER_PORT}' < /usr/local/hengine/conf/nginx.conf.template > /usr/local/hengine/conf/nginx.conf && /usr/local/hengine/sbin/nginx -g 'daemon off;'"
    environment:
      SERVER_IP: 192.168.8.10
      SERVER_PORT: 8080
    volumes:
      - ./conf/nginx.conf.template:/usr/local/hengine/conf/nginx.conf.template

Dockerfile示例如下:

  1. 编写 docker-entrypoint.sh 作为容器的启动文件:

    #!/usr/bin/env sh
    set -eu
    
    envsubst '${SERVER_IP} ${SERVER_PORT}' < /usr/local/hengine/conf/nginx.conf.template > /usr/local/hengine/conf/nginx.conf;
    
    exec "$@"
    
  2. 编写 Dockerfile

    FROM homqyy/hengine
    
    COPY nginx.conf.template /usr/local/hengine/conf/nginx.conf.template
    
    COPY docker-entrypoint.sh /
    
    ENTRYPOINT ["/docker-entrypoint.sh"]
    
    CMD ["/usr/local/hengine/sbin/nginx", "-g", "daemon off;"]
    

envsubst 的工具使用特别简单,因此强烈推荐。其安装方式可参考如下:

操作系统 安装方式
OS X brew install gettext
Debian apt-get install gettext-base
Ubuntu apt-get install gettext-base
Alpine apk add gettext
Arch Linux pacman -S gettext
Kali Linux apt-get install gettext-base
CentOS yum install gettext
Fedora dnf install gettext
Raspbian apt-get install gettext-base

转换工具: sed

如果使用别人的镜像,可能没有envsubst这个工具,那么我们可以使用sed来实现替换,比如:

  1. 复制模板文件到正式文件:

    copy /usr/local/hengine/conf/nginx.conf.template /usr/local/hengine/conf/nginx.conf
    
  2. 修改IP:

    sed -i 's/\${SERVER_IP}/${SERVER_IP}/' < /usr/local/hengine/conf/nginx.conf
    
  3. 修改端口:

    sed -i 's/\${SERVER_PORT}/${SERVER_PORT}/' < /usr/local/hengine/conf/nginx.conf
    

可以看出这种方法如果修改较多变量的话命令组合起来会比较长,但是它的优点是不需要安装额外的工具。

如果采用这种方法,最佳实践是写个docker-entrypoint.sh封装上述的替换命令,然后在Dockerfile中调用。

评论