Traefik как обратный прокси для Docker контейнеров
Использование Traefik в качестве обратного прокси для Docker контейнеров
Traefik - это обратный прокси сервер. Его основными преимуществами является наличие собственной панели мониторинга, а так же поддержка Docker “из коробки”. В этой статье я попытаюсь осветить аспект использования Traefik в качестве реверс-прокси.
Иногда нужно, чтобы Ваше приложение было доступно из мира. Это может быть какой-то концепт на начальной стадии, который нужно показать заказчику. Оригинальная идея, чтобы ‘прощупать’ потенциального потребителя или даже внутренний корпоративный сервис с небольшой нагрузкой. В такой ситуации настраивать полноценное продуктивное окружения может быть излишним. Идеальным же решением, как мне видится, будет запуск группы сервисов в Docker контейнерах, перед которыми предварительно будет развернут Traefik. Он же и будет осуществлять ретрансляцию запросов из внешней сети, что так же позволит скрыть структуру внутренней.
Конфигурирование Traefik
Запускать Traefik будем в докере, поэтому он должен быть заранее установлен и настроен. Как это сделать я описывал в данной статье. Для запуска будем использовать официальный Docker образ, но прежде чем запустить наш контейнер, необходимо создать конфигурационный файл и настроить парольный доступ к панели мониторинга.
Пусть вся информация о конфигурации нашего реверс-прокси будет хранится в директории traefik/config. Там же создадим наш файл конфигурации traefik.yml:
# mkdir traefik && mkdir traefik/config
# cd traefik/config
# mcedit traefik.yml
Первым делом добавим две точки входа в наш прокси. Таким образом из вне будут доступны порты 80 и 443 для протоколов HTTP и HTTPS соответственно. Причем traefik автоматически будет производи редирект на защищенное соединение.
entryPoints:
http:
address: :80
http:
redirections:
entryPoint:
to: https
scheme: https
https:
address: :443
Чтобы использовать шифрованный протокол HTTPS, необходимо где-то взять SSL сертификаты. Traefik позволяет автоматически получать бесплатные сертификаты Let’s Encrypt. Для этого добавим в файл конфигурации следующий блок:
certificatesResolvers:
letsEncrypt:
acme:
email: your_email@your_domain
storage: acme.json
caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"
httpChallenge:
entryPoint: http
Здесь cтоит обратить внимание на два момента:
- storage -
acme.json
файл, куда будут сохранятся данные о полученных сертификатах; - caServer -
https://acme-staging-v02.api.letsencrypt.org/directory
ACME URL тестового сервера Let’s Encrypt. После того как получение сертификатов будет отлажено, данную строку можно закомментировать или удалить;
Ключевым достоинством Traefik является возможность изменения его конфигурации без приостановки работы. Это достигается путем использования так называемых провайдеров. Следующий блок позволит отслеживать метки (labels) в запускаемых контейнерах и конфигурировать наш прокси “на лету”:
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
В заключение разрешим доступ к интерфейсу информационной панели:
api:
dashboard: true
Запуск Traefik
Traefik и контейнеры, в которые проксируется трафик, должны находиться в одной сети. Поэтому создадим ее:
# docker network create traefik_net
Далее создадим файл acme.json и дадим права записи и чтения. В этом файле будет хранится информация о сертификатах, выданных Let’s Encrypt.
# touch acme.json && chmod 600 acme.json
Теперь сгенерируем пароль для панели мониторинга с помощью утилиты htpasswd. Если она отсутствует, то необходимо ее установить:
# dnf install httpd-tools
Создаем шифрованный пароль для пользователя admin:
# htpasswd -nb admin my_password
admin:$apr1$Z6j6uukd$0BZKFwmZV0bhEgiHA7uP/0
Теперь можно приступать к запуску самого Traefik. Для этого создадим файл docker-compose.yml следующего содержания:
version: '3'
services:
traefik:
image: traefik:v2.3.2
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
ports:
- 80:80
- 443:443
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./config/traefik.yml:/traefik.yml:ro
- ./config/acme.json:/acme.json
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.entrypoints=https"
- "traefik.http.routers.traefik.rule=Host(`your_subdomain.your_domain`)"
- "traefik.http.routers.traefik.tls=true"
- "traefik.http.routers.traefik.tls.certresolver=letsEncrypt"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.services.traefik-traefik.loadbalancer.server.port=888"
- "traefik.http.middlewares.traefik-auth.basicauth.users=your_secret_password"
- "traefik.http.routers.traefik.middlewares=traefik-auth"
networks:
default:
external:
name: traefik_net
Имейте ввиду, что символы $ из полученной строки шифрованного пароля нужно будет продублировать (заменить символ $ на $$).
Теперь запустим контейнер Traefik с помощью следующей команды:
# docker-compose up -d
И проверим поднялся ли контейнер:
# docker ps
CONTAINER ID IMAGE COMMAND CREATED
STATUS PORTS NAMES
431a99940fc0 traefik:v2.3.2 "/entrypoint.sh trae…" 36 seconds ago
Up 34 seconds 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp traefik
После запуска контейнера будет доступна информационная панель, попасть в нее, можно будет, введя в браузер адрес https://your_subdomain.your_domain. Этот хост, который был указан в docker-compose.yml:
- "traefik.http.routers.traefik.rule=Host(`your_subdomain.your_domain`)"
Теперь попытаемся с помощью Traefik запроксировать трафик на другой контейнер. Пусть это будет nginx. Для его запуска воспользуемся следующим docker-compose.yml:
version: '3'
services:
test:
image: nginx:latest
restart: unless-stopped
security_opt:
- no-new-privileges:true
volumes:
- nginx_data:/etc/nginx
labels:
- "traefik.enable=true"
- "traefik.http.routers.test.entrypoints=https, http"
- "traefik.http.routers.test.rule=Host(`test.your_domain`)"
- "traefik.http.routers.test.tls=true"
- "traefik.http.routers.test.tls.certresolver=letsEncrypt"
networks:
default:
external:
name: traefik_net
volumes:
nginx_data:
Аналогичным образом, так же как мы запускали сам traifk запустим наш контейнер nginx:
# docker-compose up -d
И проверим все ли хорошо:
# docker ps
CONTAINER ID IMAGE COMMAND CREATED
STATUS PORTS NAMES
b69590bfe9b2 nginx:latest "/docker-entrypoint.…" 4 minutes ago
Up About a minute 80/tcp test
431a99940fc0 traefik:v2.3.2 "/entrypoint.sh trae…" 9 minutes ago
Up 9 minutes 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp traefik
С контейнером все хорошо, и пройдя в браузере по ссылке https://test.your_domain, мы должны увидеть приветственную информацию nginx.
Traefik в качестве Load Balancer
Одной из замечательных возможностей traefik, является осуществление балансировки нагрузки между экземплярами одного и того же сервиса. Чтобы продемонстрировать данный функционала, запустим два экземпляра нашего тестового nginx-контейнера, выполнив следующую команду:
# docker-compose up --scale test=2 -d
После зайдем в раздел HTTP Services панели мониторинга traefik и убедимся, что балансировщик видит оба экземпляра тестового сервиса. Действительно в разделе Servers их два:
Если же посмотреть логи docker-compose, то можно увидеть, что traefik балансирует входящие запросы на оба экземпляра:
test_2 | 192.168.144.2 - - [23/Oct/2020:20:43:02 +0000] "GET / HTTP/1.1" 200 612 "-"
"Mozilla/5.0 ..." "xxx.xxx.xxx.xxx"
test_1 | 192.168.144.2 - - [23/Oct/2020:20:43:36 +0000] "GET / HTTP/1.1" 200 612 "-"
"Mozilla/5.0 ..." "xxx.xxx.xxx.xxx"
test_2 | 192.168.144.2 - - [23/Oct/2020:20:44:31 +0000] "GET / HTTP/1.1" 200 612 "-"
"Mozilla/5.0 ..." "xxx.xxx.xxx.xxx"
test_1 | 192.168.144.2 - - [23/Oct/2020:20:44:35 +0000] "GET / HTTP/1.1" 200 612 "-"
"Mozilla/5.0 ..." "xxx.xxx.xxx.xxx"