Рассмотрим пример файла 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
services: nginx-entrypoint: image: nginx hostname: nginx-entrypoint container_name: nginx-entrypoint restart: unless-stopped environment: TZ: "Europe/Moscow" ports: - 80:80 - 443:443 volumes: - ./conf/nginx.conf:/etc/nginx/nginx.conf - ./conf/conf.d:/etc/nginx/conf.d - ./conf/ssl:/etc/nginx/ssl - ./well-known:/usr/share/nginx/html - /opt/letsencrypt:/etc/letsencrypt networks: dnet: networks: dnet: name: dnet driver: bridge |
Описание сценария
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
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:
После завершения проверки можно удалить тестовый контейнер:
docker rm -f my_site_container
И уже работать со своими образами.
Настройка других docker-compose
Также рассмотрим небольшой пример куска сценария для других файлов docker-compose, где будут описаны сервисы, которые должны взаимодействовать с нашим nginx-entrypoint. Последний работает в созданной сети dnet — это значит, что для сервиса нужно указать такую настройку:
1 2 3 4 5 6 7 8 |
services: service_name: ... networks: - other_net - dnet ... |
* итого, чтобы все работало, среди перечня сетей должна быть перечислена та, в которой находится nginx-entrypoint (в нашем примере это dnet).
Получение сертификата
Ну и напоследок, рассмотрим процесс получения сертификата от Let's Encrypt
Для получения сертификата в docker мы будем использовать образ certbot/certbot
1 |
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@test.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.
Если все пройдет успешно, мы увидим:
1 2 3 4 5 |
... 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
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.