Немного о Traefik

В прошлой заметке — вот тут — я рассказывал как, используя Docker compose развернуть простое веб-окружение LAMP.
Конечно же, для полноценной работы веб-проектов такого простого окружения недостаточно, почти сразу же возникнет проблема — как разместить несколько сайтов на одном сервере? Казалось бы, какая же это проблема — просто по тому же принципу развернуть еще несколько контейнеров? Вот только 80 порт уже занят. И сертификаты для https тоже нужны — без них тебя уже браузер на сайт может не пустить.

Сегодня попытаемся исправить эти недочеты и запустим в контейнере прокси-сервер Traefik, который к тому же еще и сертификаты на наш домен автоматически подтянет.
Давайте разбираться. Основная задача прокси-сервера при работе с веб-серверами заключается в принятии всех запросов на любой из ваших сайтов «на себя», обработку этих запросов и направление их на нужный ресурс. Суть в том, что в интернет вы выставляется только прокси-сервер, он в свою очередь будет принимать все запросы и распределять их по контейнерам. Таким образом у вас может быть хоть 2, хоть 10 контейнеров с сайтами или веб-приложениями, и каждому можно будет обратиться по доменному имени.

Подобный подход имеет очевидные преимущества, однако имеет один совсем не очевидный недостаток — подключение к каждому контейнеру будет осуществляться из контейнера прокси-сервера, а значит в логах веб-сервера вы не увидите реальных адресов посетителей — только адрес прокси-сервера. Данную особенность стоит учитывать.

Почему будем использовать именно Traefik? Он поставляется в виде крошечного образа, обеспечивает, при необходимости, балансировку нагрузки, позволяет обновлять конфигурацию без перезагрузки и автоматически получает сертификаты для всех доменных имен. В директории нашего проекта, который мы создавали в прошлой заметке, необходимо создать еще одну директорию — traefik

mkdir traefik

В этой директории необходимо создать два файла — один конфигурационный файл и один json, в котором будут храниться наши сертификаты.

touch acme.json
touch traefik.toml

В файле acme.json хранятся файлы сертификатов, поэтому для Traefik обязательно нужно заблокировать этот файл — чтобы только root мог читать или изменять его

chmod 600 acme.json

Прежде чем перейти к редактированию конфигурации прокси-сервера, необходимо создать логин и зашифрованный пароль, которые будут использоваться для входа на панель мониторинга. Для этого будем использовать утилиту из пакета apache2-utils.

sudo apt install apache2-utils

Генерируем пароль:

htpasswd -nb traefik-admin traefik-pass

Замените traefik-pass на ваш пароль и запомните вывод утилиты. Выглядеть он будет примерно так:

traefik-admin:$apr1$pBYiHQTS$7EsgAVDRzWQD6.8gG8OZI.

Теперь открываем конфигурационный файл Traefik:

nano traefik.toml

И пишем в него следующее:

#Отключаем дебаг
debug = false
#Проверка новых версий
checkNewVersion = true
#Задаем уровень логирования
logLevel = "ERROR"

#Задаем две точки входа для HTTP и HTTPS
defaultEntryPoints = ["https","http"]

#Включаем панель мониторинга Traefik на порту 8080
#используя базовую аутентификацию
[web]
address = ":8080"
[web.auth.basic]
users = ["СГЕНЕРИРОВАНЫЕ РАНЕЕ ЛОГИН И ПАРОЛЬ"]

#Определяем 80 как точку входа HTTP и
#порт 443 для HTTPS 
#Включаем автоматический редирект с HTTP на HTTPS
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]

#Повторять попытку отправки запроса при ошибке в сети
[retry]

#Определение серверной части конфигурации

[docker]
endpoint = "unix:///var/run/docker.sock"
domain = "ВАШ ДОМЕН"
watch = true
exposedbydefault = false

#Регистрация Letsencrypt
#Получение сертификатор используя ACME

[acme]
email = "ВАШ EMAIL"
storage = "acme.json"
entryPoint = "https"
OnHostRule = true
[acme.httpChallenge]
entryPoint = "http"

Здесь необходимо внести изменения, согласно вашим данным, сохранить изменения в файле и закрыть редактор. Теперь осталось отредактировать файл docker-compose.yml, и привести его к следующему виду:

version: '3'

services:

  traefik:
image: traefik:latest
command: --docker --docker.domain=ВАШ_ДОМЕН
ports:
  - 80:80
  - 443:443
networks:
  - traefik-proxy
volumes:
  - /var/run/docker.sock:/var/run/docker.sock
  - ./traefik/traefik.toml:/traefik.toml
  - ./traefik/acme.json:/acme.json
labels:
  - traefik.frontend.rule=Host:ПОДДОМЕН_ДЛЯ_DASHBOARD
  - traefik.port=8080
container_name: traefik
restart: always
links:
  - apache_php

  apache_php:
build: ./httpd
labels:
  - traefik.backend=apache_php
  - traefik.frontend.rule=Host:ВАШ_ДОМЕН
  - traefik.docker.network=traefik-proxy
  - traefik.port=80
volumes:
  - ./src:/var/www/html
 links:
  - mariadb
networks:
  - traefik-proxy
  - wp-apache-bd
container_name: apache_php
depends_on:
  - mariadb

  mariadb:
image: mariadb:10.3
restart: always
volumes:
  - ./mariadb:/var/lib/mysql
environment:
  MYSQL_ROOT_PASSWORD: ПАРОЛЬ_ROOT
  MYSQL_DATABASE: ИМЯ_БД
  MYSQL_USER: ИМЯ_ПОЛЬЗОВАТЕЛЯ_БД
  MYSQL_PASSWORD: ПАРОЛЬ_ПОЛЬЗОВАТЕЛЯ_БД
labels:
  - traefik.enable=false
container_name: mariadb
networks:
  - wp-apache-bd

networks:
traefik-proxy:
external: true
wp-apache-bd:
external: false

Разберем все по порядку

В предыдущей статье мы рассмотрели часть конфигурации, поэтому сейчас опишу только изменения.

services:
 traefik:
   image: traefik:latest

Здесь мы описываем создание сервиса Traefik, образ которого берем напрямую с DockerHub.

command: --docker --docker.domain=ВАШ_ДОМЕН

Выполняем команду внутри docker контейнера, указывая домен, с которым работаем

networks:
     - traefik-proxy

Для контейнера Traefik используем отдельную сеть, чтобы прокси-сервер не мог получить доступ к контейнеру с базой данных.

volumes:
     - /var/run/docker.sock:/var/run/docker.sock
     - ./traefik/traefik.toml:/traefik.toml
     - ./traefik/acme.json:/acme.json

Пробрасываем в контейнер сокет Docker и файлы конфигураций.

labels:
     - traefik.frontend.rule=Host:ПОДДОМЕН_ДЛЯ_DASHBOARD
     - traefik.port=8080

Поле labels не хранит переменных окружения, в отличие от environment, но Traefik способен прочитать labels и взять от туда данные, в которых мы указываем поддомен для доступа на панель мониторинга и порт, на котором эта панель должна работать

container_name: traefik

Задаем контейнеру уникальное имя, чтобы не полагаться на генератор имен Docker Compose

 links:
     - apache_php

Прилинковываем Traefik к контейнеру с Apache

 apache_php:

  ...

   labels:
     - traefik.backend=apache_php
     - traefik.frontend.rule=Host:ВАШ_ДОМЕН
     - traefik.docker.network=traefik-proxy
     - traefik.port=80

 ...

   networks:
     - traefik-proxy
     - wp-apache-bd
   container_name: apache_php

Назначаем labels для контейнера с Apache, где указываем имя сервиса, к которому будет обращаться Traefik, домен, при обращении к которому, Traefik будет направлять запросы на этот контейнер и сеть, по которой эти запросы будут направляться, а также порт, на котором работает сервис с Apache.

Также указываем сети, с которыми работает Apache — по одной он соединяется с Traefik, по второй с базой данных.

mariadb:

  ...

   labels:
     - traefik.enable=false

   ...

Указываем labels сервиса mariadb (базы данных) для Traefik, чтобы он не пытался связываться с контейнером.

networks:
       traefik-proxy:
       external: true
       wp-apache-bd:
       external: false

Создаем сети для связи контейнеров.

На этом все. Сохраняем файл docker-compose.yml и собираем проект:

docker-compose up -d

и получаем полностью готовый к работе веб-сервер, с сертификатами Letsencrypt и автоматическим перенаправлением с http на https.