Docker-compose with nginx templates to pass global variables. Adding a command to my compose breaks this function

Viewed 557

(Similar to an unanswered post from yesterday but I've since zoomed in on the cause of my issue so re-posting here with less text and deleting yesterdays post)

With the nginx image one can pass global env variables. Documentation. On the link there's a section 'Using environment variables in nginx configuration (new in 1.19)'. When running this container the functionality described above about global variables does indeed work as expected.

If I exec into the running container I see a script at the root level of the directory system docker-entrypoint.sh. From research it sounds like the method nginx docker uses to pass global variables relies on this script being run when the container starts and that this is an automatic process.

The trouble is, my docker-compose has a command command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'". When I include this command and run, it breaks the functionality with global variables. From doing some searching, adding a command breaks any entry point scripts? It seems I can only make use of the global variable functionality if I don't add any commands to my docker-compose since it stops docker-entrypoint.sh from being run.

Is there a 'right' way around this?

Works - global variables are passed through to nginx:

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

Does not work, global variables are not passed through and the default.conf template is all that I get:

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
    command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
    networks:
      - collabora
1 Answers

Take a look at the entrypoint script inside the container, specifically the if statement that guards most of the code:

if [ "$1" = "nginx" -o "$1" = "nginx-debug" ]; then
   ...
fi

The templating and other entrypoint scripts will only run when $1 is nginx or nginx-debug. That's not true for your Dockefile, in which $1 would be /bin/sh.

The simplest option would be to replace the entrypoint script with a modified version that runs the entrypoint scripts unconditionally. There are a couple ways of doing that, but the easiest is probably:

  • Create a custom docker-entrypoint.sh script in your local directory (make sure it's executable).

  • Mount that on top of the stock version in your docker-compose.yml:

    version: "3.5"
    networks:
      collabora:
    
    services:
      nginx:
        image: nginx
        depends_on:
          - certbot
          - collabora
        volumes:
          # Here is where we orverride the entrypoint script.
          - ./data/docker-entrypoint.sh:/docker-entrypoint.sh
          - ./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
        command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
        networks:
          - collabora
    

Removing the guard if statement gives us:

#!/bin/sh
# vim:sw=4:ts=4:et

set -e

if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then
    exec 3>&1
else
    exec 3>/dev/null
fi

if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then
    echo >&3 "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration"

    echo >&3 "$0: Looking for shell scripts in /docker-entrypoint.d/"
    find "/docker-entrypoint.d/" -follow -type f -print | sort -V | while read -r f; do
        case "$f" in
            *.sh)
                if [ -x "$f" ]; then
                    echo >&3 "$0: Launching $f";
                    "$f"
                else
                    # warn on shell scripts without exec bit
                    echo >&3 "$0: Ignoring $f, not executable";
                fi
                ;;
            *) echo >&3 "$0: Ignoring $f";;
        esac
    done

    echo >&3 "$0: Configuration complete; ready for start up"
else
    echo >&3 "$0: No files found in /docker-entrypoint.d/, skipping configuration"
fi

exec "$@"
Related