[DOCKER] Think about how to follow container operation best practices with Nginx containers

Introduction

Nginx is a convenient HTTP server that makes it super easy to launch in a container and serve web services. On the other hand, there are some quirks in following best practices for container operations.

What is addictive

The best practices for container operations are:

--Containers do not change the image in each environment (development, production, etc.) --It is the environment variables that change, and the environment variables control the behavior inside the container.

On the other hand, Nginx is difficult to pass environment variables. You have to do some tricks like the article below.

[Qiita] General-purpose pattern for embedding environment variables in configuration files with Docker using envsubst

But with modern Nginx containers, you don't have to do this!

Introducing docker-entrypoint.sh

When you start the Nginx container, docker-entrypoint.sh is executed by default.

The contents of this script are as follows (image when `` `FROM nginx: 1.18``` is done)

docker-entrypoint.sh


#!/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 [ "$1" = "nginx" -o "$1" = "nginx-debug" ]; then
    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 -n | 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
fi

exec "$@"

In short, it will execute .sh under /docker-entrypoint.d/ in sequence (other than .sh will be ignored).

In addition, /docker-entrypoint.d/ includes the following scripts by default.

20-envsubst-on-templates.sh


#!/bin/sh

set -e

ME=$(basename $0)

auto_envsubst() {
  local template_dir="${NGINX_ENVSUBST_TEMPLATE_DIR:-/etc/nginx/templates}"
  local suffix="${NGINX_ENVSUBST_TEMPLATE_SUFFIX:-.template}"
  local output_dir="${NGINX_ENVSUBST_OUTPUT_DIR:-/etc/nginx/conf.d}"

  local template defined_envs relative_path output_path subdir
  defined_envs=$(printf '${%s} ' $(env | cut -d= -f1))
  [ -d "$template_dir" ] || return 0
  if [ ! -w "$output_dir" ]; then
    echo >&3 "$ME: ERROR: $template_dir exists, but $output_dir is not writable"
    return 0
  fi
  find "$template_dir" -follow -type f -name "*$suffix" -print | while read -r template; do
    relative_path="${template#$template_dir/}"
    output_path="$output_dir/${relative_path%$suffix}"
    subdir=$(dirname "$relative_path")
    # create a subdirectory where the template file exists
    mkdir -p "$output_dir/$subdir"
    echo >&3 "$ME: Running envsubst on $template to $output_path"
    envsubst "$defined_envs" < "$template" > "$output_path"
  done
}

auto_envsubst

exit 0

This means that all environment variables will replace the environment variable definitions (strings enclosed in $ {}) in the * .template file under/etc/nginx/templates.

Does this solve the environment variable problem?

Not solved.

As you can see by reading the script above, it replaces all the set environment variables. If the environment variable and the variable of nginx.conf are duplicated in log output etc., there is a possibility of accidental explosion.

If you want to avoid accidental explosions, you have to prepare your own script using envsubst.

Also, if you add the above script under /docker-entrypoint.d/, it will be executed at startup, but docker-entrypoint.sh will continue processing even if the called script causes an error. Therefore, for example, "If this environment variable is not defined, it will not start" cannot be done.

After all, I had no choice but to execute the above script with CMD, and it seemed difficult to complete with docker-entrypoint.sh ...

Recommended Posts

Think about how to follow container operation best practices with Nginx containers
How to monitor nginx with docker-compose with datadog
How to think when you suddenly understand about generics
How to develop in a container with --privileged and / sbin / init passed in VSCode Remote Containers
Think about how to divide MVC into M and V
How to set Docker nginx
How to number (number) with html.erb
How to update with activerecord-import
[Note] How to restart the Windows container set up with docker-compose
How to think about class design (division) in a business system (1)