Substitute environment variables in NGINX config from docker-compose

后端 未结 3 703
感情败类
感情败类 2020-12-11 23:13

I am trying to start an NGINX server within a docker container configured through docker-compose. The catch is, however, that I would like to substitute an environment varia

相关标签:
3条回答
  • 2020-12-11 23:29

    You can avoid some of the hassles with Compose interpreting environment variables by defining your own entrypoint. See this simple example:

    • entrypoint.sh (make sure this file is executable)
    #!/bin/sh
    
    export NGINXPROXY
    
    envsubst '${NGINXPROXY}' < /config.template > /etc/nginx/nginx.conf
    
    exec "$@"
    
    • docker-compose.yml
    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;"]
    

    My config file has the same content as your nginx.conf, aside from the fact that I had to comment the lines using the Perl module.

    Note that I had to mount my config file to another location before I could envsubst it. I encountered some strange behaviour in the form that the file ends up empty after the substitution, which can be avoided by this approach. It shouldn't be a problem in your specific case, because you already embed it in your image on build time.


    EDIT

    For completeness, to change your setup as little as possible, you just have to make sure that you export your environment variable. Adapt your command like this:

    command: ["/bin/bash", "-c", "export NGINXPROXY && envsubst '$$NGINXPROXY' < /etc/nginx/nginx.conf > /etc/nginx/nginx.conf && nginx -g 'daemon off;'"]
    

    ...and you should be good to go. I would always recommend the "cleaner" way with defining your own entrypoint, though.

    0 讨论(0)
  • 2020-12-11 23:34

    So after some wrestling with this issue, I managed to get it working similarly to the answer provided by bellackn. I am going to post my exact solution here, in case anybody else needs to reference a complete solution.

    Step1: Write your nginx.conf or default.conf how you would normally write it. Save the file as "nginx.conf.template", or "default.conf.template" depending on which you are trying to substitute variables into.

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

    Step2: Substitute a variable in the format ${VARNAME} for whatever value(s) you want to replace with an environment variable:

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

    Step 3: In your docker-file, copy your nginx configuration files (your nginx.conf.template or default.conf.template) into your container at the appropriate location:

    # 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;"]
    

    Step 4: Set your environment variable in your docker-compos.yml file using the "environment" section label. Make sure your environment variable name matches whatever variable name you chose within your nginx config file. Use the "envsubt" command within your docker container to substitute your variable values in for your variables within your nginx.conf.template, and write the output to a file named nginx.conf in the correct location. This can be done within the docker-compose.yml file by using the "command" section label:

    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;'"
    

    Step 5: Run your stack with docker-compose up (with whatever additional switches you need) and your nginx server should now start with whatever value you supplied in the "environment" section of your docker-compose.yml

    As mentioned in the solution above, you can also define your own entry point, however this solution has also proven to work pretty well, and keeps everything contained into a single configuration file, giving me the ability to run a stack of services directly from git with nothing but a docker-compose.yml file.

    A big thank you to everybody who took the time to ready through this, and bellackn for taking the time to help me solve the issue.

    0 讨论(0)
  • 2020-12-11 23:38

    Since nginx 1.19 you can now use environment variables in your configuration with docker-compose. I used the following setup:

    # 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
            
    

    I'm going off script a little from the example in the documentation. Note the extra .conf extension on the template file - this is not a typo. In the docs for the nginx image it is suggested to name the file, for example, default.conf.template. Upon startup, a script will take that file, substitute the environment variables, and then output the file to /etc/nginx/conf.d/ with the original file name, dropping the .template suffix.

    By default that suffix is .template, but this breaks syntax highlighting unless you configure your editor. Instead, I specified .conf as the template suffix. If you only name your file default.conf the result will be a file named /etc/nginx/conf.d/default and your site won't be served as expected.

    0 讨论(0)
提交回复
热议问题