Doug Fir
Doug Fir

Reputation: 21302

Add a file to `/docker-entrypoint.d/` as part of a app.conf.template file to swap global variables into nginx set up

I would like to pass global variables to my nginx app.conf via a app.conf.template file using docker and docker-compose.

When using an app.conf.template file with no commands in docker-compose.yaml my variables translate successfully and my redirects via nginx work as expected. But when I use a command in docker-compose my nginx and redirects fail.

My set up is per the instructions on the documentation, under section 'Using environment variables in nginx configuration (new in 1.19)':

Out-of-the-box, nginx doesn't support environment variables inside most configuration blocks. But this image has a function, which will extract environment variables before nginx starts.

Here is an example using docker-compose.yml:

web: image: nginx volumes:

  • ./templates:/etc/nginx/templates ports:
  • "8080:80" environment:
  • NGINX_HOST=foobar.com
  • NGINX_PORT=80

By default, this function reads template files in /etc/nginx/templates/*.template and outputs the result of executing envsubst to /etc/nginx/conf.d ... more ...

My docker-compose.yaml works when it looks like this:

version: "3.5"
networks:
  collabora:
  
services:
  nginx:
    image: nginx
    depends_on:
      - certbot   
      - collabora 
    volumes:
      - ./data/nginx/templates:/etc/nginx/templates
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
    ports:
      - "80:80"
      - "443:443"
    env_file: .env
    networks:
      - collabora

On host I have a conf file ./data/nginx/templates/app.conf.template which contains a conf file with global variables throughout in the form ${variable_name}.

With this set up I'm able to run the container and my redirects work as expected. When I exec into the container I can cat /etc/nginx/conf.d/app.conf and see the file with the correct variables swapped in from the .env file.

But I need to add a command to my docker-compose.yaml:

command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"

When I add that command the set up fails and the global variables are not swapped into the app.conf file within the container.

On another forum it was suggested I move the command into it's own file in the container. I then gave this a try and created a shell script test.sh:

#/bin/sh 

while :; 
    do sleep 6h & wait $${!}; 
    nginx -s reload; 
done;

My new docker-compose:

version: "3.5"
networks:
  collabora:
  
services:
  nginx:
    image: nginx
    depends_on:
      - certbot   
      - collabora 
    volumes:
      - ./data/nginx/templates:/etc/nginx/templates
      - ./test.sh:/docker-entrypoint.d/test.sh # new - added test.sh into the container here
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
    ports:
      - "80:80"
      - "443:443"
    env_file: .env
    networks:
      - collabora

This fails. Although when I exec into the container and cat /etc/nginx/conf.d/app.conf I DO see the correct config, it just does not seem to be working in that my redirects, which otherwise do work when I don't include this test.sh script within /docker-entrypoint.d/.

I asked nearly same question yesterday and was given a working solution. However, it 'feels more correct' to add a shell script to the container at /docker-entrypoint.d/ and go that route instead like I've attempted in this post.

Upvotes: 0

Views: 894

Answers (1)

larsks
larsks

Reputation: 312500

For what you're trying to do, I think the best solution is to create a sidecar container, like this:

version: "3.5"

networks:
  collabora:

volumes:
  shared_run:

services:
  nginx:
    image: nginx:1.19
    volumes:
      - "shared_run:/run"
      - ./data/nginx/templates:/etc/nginx/templates
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
    ports:
      - "80:80"
      - "443:443"
    env_file: .env
    networks:
      - collabora

  nginx_reloader:
    image: nginx:1.19
    pid: service:nginx
    volumes:
      - "shared_run:/run"
    entrypoint:
      - /bin/bash
      - -c
    command:
      - |
        while :; do
          sleep 60
          echo reloading
          nginx -s reload
        done

This lets you use the upstream nginx image without needing to muck about with its mechanics. The key here is that (a) we run the nginx_reloader container in the same PID namespace as the nginx container itself, and (b) we arrange for the two containers to share a /run directory so that the nginx -s reload command can find the pid of the nginx process in the expected location.

Upvotes: 4

Related Questions