Docker-compose для создания nginx entrypoint

Обновлено и опубликовано Опубликовано:

На одном сервере с docker-контейнерами может размещаться несколько веб-приложений, которые необходимо публиковать по http и https. Самый оптимальный способ это сделать в среде Docker — использовать отдельный контейнер с http-прокси, который будет переводить веб-запросы на нужные контейнеры, ориентируясь по доменным именам.

Рассмотрим пример файла docker-compose для проксирования запросов на другие контейнеры и возможностью получения сертификатов от Let's Encrypt.

Подготовка

Выполним предварительные действия. Предполагается, что мы будем хранить наш файл docker-compose в каталоге /opt/nginx.

Создаем каталог:

mkdir /opt/nginx

Перейдем в него:

cd /opt/nginx

Создаем файл docker-compose.yml:

vi docker-compose.yml

Мы готовы к написанию сценария.

Docker-compose

Пример нашего файла compose:

  1. services:
  2.   nginx-entrypoint:
  3.     image: nginx
  4.     hostname: nginx-entrypoint
  5.     container_name: nginx-entrypoint
  6.     restart: unless-stopped
  7.     environment:
  8.       TZ: "Europe/Moscow"
  9.     ports:
  10.       - 80:80
  11.       - 443:443
  12.     volumes:
  13.       - ./conf/nginx.conf:/etc/nginx/nginx.conf
  14.       - ./conf/conf.d:/etc/nginx/conf.d
  15.       - ./conf/ssl:/etc/nginx/ssl
  16.       - ./well-known:/usr/share/nginx/html
  17.       - /opt/letsencrypt:/etc/letsencrypt
  18.     networks:
  19.       dnet:
  20.  
  21. networks:
  22.   dnet:
  23.     name: dnet
  24.     driver: bridge

Описание сценария

Кратко опишем, что выполнит наш сценарий. Подробнее про работу с docker-compose можно прочитать в инструкции Шпаргалка по работе с docker-compose.

1 - 19 Поднимаем контейнер с nginx прокси.
13 Основной конфигурационный файл nginx.
14 Дополнительные конфигурационные файлы, которые будут подгружаться к основному. В них мы будем хранить настройки для виртуальных доменов.
15 Хранение самоподписанных или платных сертификатов.
16 Каталог обмена контентом, который нужен для валидации домена. Используется при получении бесплатных сертификатов от Let's Encrypt.
17 Бесплатные сертификаты, полученные от Let's Encrypt.
21 - 24 Общая сеть. Ее мы будем добавлять к другим службам других контейнеров для обеспечения сетевой доступности между данным контейнерами и нашим entrypoint.

Запуск

Прежде чем запустить контейнер с entrypoint, создаем базовый конфигурационный файл для nginx:

mkdir conf

vi conf/nginx.conf

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    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;

    resolver        127.0.0.11 valid=10s;
    sendfile        on;

    keepalive_timeout  65;

    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }

    include /etc/nginx/conf.d/*.conf;
}

* это, более или менее, стандартный конфигурационный файл nginx. Но при желании, вы можете его переделать под себя.
** для нас особую важность имеет директива include со значением /etc/nginx/conf.d/*.conf — это наш каталог для подгружаемых конфигов.

Продолжая находиться в каталоге с файлом docker-compose, выполним команду:

docker-compose up -d

При первом запуске система загрузит образ с nginx и запустит контейнер. Посмотреть его состояние можно командой:

docker ps

Пример конфигурации виртуального домена

Рассмотрим простой пример создания конфигурационного файла для проксирования http запросов.

Убедимся, что мы находимся в рабочем каталоге:

cd /opt/nginx

Создаем конфигурационный файл:

vi conf/conf.d/test.domain.ru.conf

* обязательно, чтобы название файла заканчивалось на .conf.

server {
    listen       80;
    #listen       443 ssl http2;
    server_name  test.domain.ru;

    location ~ /.well-known {
        root /usr/share/nginx/html;
        allow all;
    }

    #ssl_certificate     /etc/letsencrypt/live/test.domain.ru/fullchain.pem;
    #ssl_certificate_key /etc/letsencrypt/live/test.domain.ru/privkey.pem;

    #if ($scheme = 'http') {
        #return 301 https://$host$request_uri;
    #}

    location / {
        proxy_pass         http://my_site_container;
        proxy_redirect     off;
        proxy_set_header   Host             $host;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
    }
}

* nginx с данной конфигурацией будет переводить запросы на контейнер my_site_container для запросов к сайту test.domain.ru.
** обратите внимание, что мы предусмотрели в будущем возможность использовать https, но чтобы нам опции не мешали, пока оставили их закомментированными.

Чтобы наш конфигурационный файл работал, контейнер nginx-entrypoint должен видеть сервис my_site_container (из нашего примера). Создадим его для теста:

docker run --rm -d --name my_site_container --network dnet nginx

* наш контейнер будет с именем my_site_container, работать в сети dnet.

Теперь можно применить конфигурацию nginx, но для начала, проверим корректность конфига:

docker exec nginx-entrypoint nginx -t

Если видим:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

... перечитываем конфигурацию:

docker exec nginx-entrypoint nginx -s reload

Можно проверять — при обращении к нашему домену в браузере мы должны получить страницу приветствия nginx:

Страница приветствия в nginx

После завершения проверки можно удалить тестовый контейнер:

docker rm -f my_site_container

И уже работать со своими образами.

Настройка других docker-compose

Также рассмотрим небольшой пример куска сценария для других файлов docker-compose, где будут описаны сервисы, которые должны взаимодействовать с нашим nginx-entrypoint. Последний работает в созданной сети dnet — это значит, что для сервиса нужно указать такую настройку:

services:

  service_name:
    ...
    networks:
      - other_net
      - dnet
    ...

* итого, чтобы все работало, среди перечня сетей должна быть перечислена та, в которой находится nginx-entrypoint (в нашем примере это dnet).

Получение сертификата

Ну и напоследок, рассмотрим процесс получения сертификата от Let's Encrypt. Подробнее процесс описан в инструкции Получение бесплатного SSL сертификата Let's Encrypt.

Для получения сертификата в docker мы будем использовать образ certbot/certbot

docker run -it --rm --name certbot -v "/opt/letsencrypt:/etc/letsencrypt" -v "/opt/nginx/well-known:/usr/share/nginx/html" certbot/certbot certonly --webroot --agree-tos --email postmaster@dmosk.ru --webroot-path /usr/share/nginx/html/ -d test.domain.ru -d www.test.domain.ru

* в данном примере мы задействуем пути, которые описали выше в сценарии — каталог /opt/letsencrypt, куда будут сохранены полученные сертификаты и /opt/nginx/well-known для размещения временных файлов, необходимых при проверке домена.
** Мы получим сертификаты для хостов test.domain.ru и www.test.domain.ru. Важно, чтобы данные имена вели на наш сервер с nginx.

Если все пройдет успешно, мы увидим:

...
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/test.domain.ru/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/test.domain.ru/privkey.pem
...

Теперь нужно вернуться к конфигурационному файлу для виртуального домена и разрешить использование ssl (снять комментарии):

vi /opt/nginx/conf/conf.d/test.domain.ru.conf

server {
    listen       80;
    listen       443 ssl http2;
    server_name  test.domain.ru;

    location ~ /.well-known {
        root /usr/share/nginx/html;
        allow all;
    }

    ssl_certificate     /etc/letsencrypt/live/test.domain.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/test.domain.ru/privkey.pem;

    if ($scheme = 'http') {
        return 301 https://$host$request_uri;
    }

    location / {
        proxy_pass         http://my_site_container;
        proxy_redirect     off;
        proxy_set_header   Host             $host;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
    }
}

* желтым отмечены строки, с которых мы сняли комментарии.

Проверяем конфигурацию и перечитываем ее:

docker exec nginx-entrypoint nginx -t

docker exec nginx-entrypoint nginx -s reload

Снова открываем в браузере наш сайт — запрос должен быть переброшен на https.

# Linux # Интернет # Серверы # DevOps
Дмитрий Моск — частный мастер
Был ли вам полезен этот скрипт?

Да            Нет