Skip to content

Динамические переменные внутри контейнера

Чтобы не хардкодить например имя домена в конфиге nginx(который добавляется в docker image) есть варианты:

server {
        listen 80;
        server_name ${DOMAIN_NAME};

        root /www/${DOMAIN_NAME}/site;

        location / {
                index index.html;
        }

        location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|pdf|ppt|txt|bmp|rtf|js|woff)$ {
                expires 30d;
        }
}

1. использовать встроенный функционал nginx

Например в nginx с версии 1.19 есть поддержка environment variables and templates

Entrypoint cкрипты заменяют все переменные, найденные в файлах /etc/nginx/templates/*.template, их соответствующими значениями с использованием envsubst.

Результаты этой подстановки записываются в /etc/nginx/conf.d (требуются права root в контейнере))

Убедитесь, что вы скопировали файл в папку templates и убедитесь, что его расширение - template.

например default.conf.template

FROM nginx:1.25-alpine

COPY default.conf.template /etc/nginx/templates/
docker build -t blog1 -f Dockerfile1 .

docker run -it --name blog1 --rm -e DOMAIN_NAME=test.ru blog1

2.1 свой entrypoint.sh (переназначает дефолтные entrypoint nginx)

#!/usr/bin/env sh
set -eu
envsubst '${DOMAIN_NAME}' < /etc/nginx/conf.d/custom.conf.template > /etc/nginx/conf.d/custom.conf
exec "$@"

FROM nginx:alpine
ENV DOMAIN_NAME=$DOMAIN_NAME
COPY custom.conf.template /etc/nginx/conf.d/
COPY ./entrypoint.sh /
RUN chmod +x ./entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]
Можем увидеть Running envsubst:
$ docker run -it --name blog1 --rm -e DOMAIN_NAME=test.ru blog1
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
20-envsubst-on-templates.sh: Running envsubst on /etc/nginx/templates/custom.conf.template to /etc/nginx/conf.d/custom.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2024/03/18 03:53:55 [notice] 1#1: using the "epoll" event method
2024/03/18 03:53:55 [notice] 1#1: nginx/1.25.4

2.2 cmd в dockerfile

С помощью envsubst мы можем заменить ${VARIABLE} соответствующими значениями переменных окружения.

Поскольку мы не хотим захардкодить значение DOMAIN_NAMe во время сборки, мы подставляем DOMAIN_NAME в момент запуска контейнера. Это может быть не самым простым для чтения, но это простой способ динамического назначения переменной окружения.

FROM nginx:alpine

COPY custom.conf.template /etc/nginx/conf.d/

CMD sh -c "envsubst \"`env | awk -F = '{printf \" \\\\$%s\", $1}'`\" < /etc/nginx/conf.d/custom.conf.template > /etc/nginx/conf.d/custom.conf && nginx -g 'daemon off;'"

3. передать через docker compose

...
environment:
      - NGINX_DOMAIN_NAME=${HOSTNAME}
      - VIRTUAL_HOST=${HOSTNAME}
      - LETSENCRYPT_HOST=${HOSTNAME}
      - LETSENCRYPT_EMAIL=${EMAIL}
command: bash -c "envsubst '$${DOMAIN_NAME}' < /etc/nginx/conf.d/custom.conf.template > /etc/nginx/conf.d/custom.conf && nginx -g 'daemon off;'"
...

4. через сборку образа, используя ARG с уже установленной переменной

удобно когда пользователь контейнера не имеет прав например создать файл в /etc/nginx/conf.d как в варианте #3

через ARG передаем значение переменной

docker build -t blog4 -f Dockerfile4 . --build-arg=DOMAIN_NAME="test.ru"
docker run -it --name blog4  blog4

FROM nginx:1.25-alpine

ARG DOMAIN_NAME='localhost'
ENV DOMAIN_NAME=$DOMAIN_NAME

# Configure nginx
COPY custom.conf /etc/nginx/conf.d/

RUN sed -i 's/${DOMAIN_NAME}/'"$DOMAIN_NAME"'/g' /etc/nginx/conf.d/custom.conf

# Setup document root
RUN mkdir -p /www

# Make sure files/folders needed by the processes are accessable when they run under the nobody user
RUN chown -R nobody.nobody /www && \
  chown -R nobody.nobody /run && \
  chown -R nobody.nobody /var/cache/nginx && \
  chown -R nobody.nobody /var/log/nginx

# Switch to use a non-root user from here on
USER nobody

# Add application
WORKDIR /www
# COPY --chown=nobody site/ /www/$DOMAIN_NAME

# Expose the port nginx is reachable on
EXPOSE 80

STOPSIGNAL SIGTERM

CMD ["nginx", "-g", "daemon off;"]