@ -7,7 +7,6 @@ category: DevOps
|
||||
|
||||
# Traefik - роутинг просто
|
||||
|
||||
|
||||
Сегодня я бы хотел рассказать о такой клёвой штуке, как [Traefik](https://traefik.io/traefik/). Не так давно я перевёл все сервисы своего сервера на traefik и это буквально сделало жизнь проще. Сегодня я расскажу вам зачем он нужен, как его настроить, и покажу на примере, как именно он помогает. По факту, это nginx на стероидах, в плане конфигурации, потому что в traefik за тебя сделано гораздо больше.
|
||||
|
||||
# Что такое traefik
|
||||
@ -33,6 +32,7 @@ Traefik - это система, которая позволяет настро
|
||||
</div>
|
||||
|
||||
## Архитектура
|
||||
|
||||
В официальной документации зарисована следующая схема работы traefik:
|
||||
|
||||
<div align="center">
|
||||
@ -43,21 +43,24 @@ Traefik - это система, которая позволяет настро
|
||||
|
||||
Как можно видеть по данному изображению, есть 5 основных составляющих traefik, а именно:
|
||||
|
||||
* entrypoints
|
||||
* routers
|
||||
* rules (часть routers)
|
||||
* middlewares (чать routers)
|
||||
* services
|
||||
- entrypoints
|
||||
- routers
|
||||
- rules (часть routers)
|
||||
- middlewares (чать routers)
|
||||
- services
|
||||
|
||||
### Entrypoint
|
||||
|
||||
Являются основными слушателями входящих соединений. Через них проходит весь трафик. Если попробовать объяснить в двух словах: "Порт, на который должно прийти входящее соединение", - вполне себе неплохое объяснение. В данном туториале я создам 2 `entrypoint`, которые будут слушать на http и https.
|
||||
|
||||
### Routers, Rules и Middlewares
|
||||
Роутер - связующее звено между `entrypoint` и сервисом, куда нужно направить трафик. Роутер хранит в себе информацию, куда направить входящий трафик, и
|
||||
### Routers, Rules и Middlewares
|
||||
|
||||
Роутер - связующее звено между `entrypoint` и сервисом, куда нужно направить трафик. Роутер хранит в себе информацию, куда направить входящий трафик, и
|
||||
правила, по которым можно определить, пускать ли трафик дальше.
|
||||
|
||||
Rules - это и есть те самые правила, которые определяют, через какой роутер пустить трафик.
|
||||
Допустим, у вас в конфиге есть следующие правила:
|
||||
|
||||
```
|
||||
Host(`myapp.com`) && (PathPrefix(`/api`) || PathPrefix(`/memes`))
|
||||
```
|
||||
@ -75,7 +78,6 @@ Host(`myapp.com`) && (PathPrefix(`/api`) || PathPrefix(`/memes`))
|
||||
Вы, конечно же, можете использовать локально установленную версию, всё будет работать, как часы.
|
||||
</b-message>
|
||||
|
||||
|
||||
Для нашего основного traefik на сервере мы создадим небольшой docker-compose.yml, файл конфига и папочку с сертификатами.
|
||||
Структура будет следующая:
|
||||
|
||||
@ -100,13 +102,20 @@ services:
|
||||
# The official v2.0 Traefik docker image
|
||||
image: traefik:v2.4.8
|
||||
container_name: traefik_main
|
||||
command:
|
||||
command:
|
||||
# Включает прослушивание докера на новые события и следит за лейблами контейнеров.
|
||||
- --providers.docker=true
|
||||
# Отключает автоматическое создание роутеров ко всем контейнерам на сервере.
|
||||
- --providers.docker.exposedbydefault=false
|
||||
# Сеть докера, по которой будет выполнятся подключение к контейнерам.
|
||||
- --providers.docker.network=traefik-shared
|
||||
# Папка с конфигурационным файлом.
|
||||
- --providers.file.directory=/etc/traefik/dynamic
|
||||
# Включает отслеживание изменений файла конфигурации.
|
||||
- --providers.file.watch=true
|
||||
# Создаёт entrypoint с названием http и слушает 80 порт.
|
||||
- --entrypoints.http.address=:80
|
||||
# Создаёт entrypoint с названием https и слушает 443 порт.
|
||||
- --entrypoints.https.address=:443
|
||||
ports:
|
||||
# The HTTP port
|
||||
@ -119,12 +128,16 @@ services:
|
||||
environment:
|
||||
MAIN_HOST: 192.168.1.89
|
||||
volumes:
|
||||
# So that Traefik can listen to the Docker events
|
||||
# Обязательный вольюм. Так траефик может слушать
|
||||
# события происходящие в демоне докера.
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
# Вольюм с файлом конфигурации.
|
||||
- ./config.toml:/etc/traefik/dynamic/traefik.toml
|
||||
# Папка сертификатов.
|
||||
- ./certs:/etc/certs/
|
||||
|
||||
networks:
|
||||
# Сетка, внутри которой будут находится приложения.
|
||||
traefik-shared:
|
||||
name: traefik-shared
|
||||
|
||||
@ -132,16 +145,6 @@ networks:
|
||||
|
||||
Вот какие параметры я передаю в `traefik-cli`.
|
||||
|
||||
| Параметр | Что делает |
|
||||
|-------------------------------------------------|----------------------------------------------------------------------------------|
|
||||
| `providers.docker=true` | Включает прослушивание докера на новые события и следит за лейблами контейнеров. |
|
||||
| `providers.docker.exposedbydefault=false` | Отключает автоматическое создание роутеров ко всем контейнерам на сервере. |
|
||||
| `providers.docker.network=traefik-shared` | Сеть докера, по которой будет выполнятся подключение к контейнерам. |
|
||||
| `providers.file.directory=/etc/traefik/dynamic` | Папка с конфигурационным файлом. |
|
||||
| `providers.file.watch=true` | Включает отслеживание изменений файла конфигурации. |
|
||||
| `entrypoints.http.address=:80` | Создаёт entrypoint с названием http и слушает 80 порт. |
|
||||
| `entrypoints.https.address=:443` | Создаёт entrypoint с названием https и слушает 443 порт. |
|
||||
|
||||
Конечно, вы всегда можете глянуть `traefik --help` и подобрать себе желаемые параметры.
|
||||
|
||||
Также из docker-compose файла видно, что я создал докер сеть `traefik-shared`, которую в дальнейшем буду использовать на всех контейнерах, которым требуется свой домен.
|
||||
@ -153,16 +156,19 @@ networks:
|
||||
Для генерации локальных сертификатов я использую тулу [mkcert](https://github.com/FiloSottile/mkcert).
|
||||
|
||||
Для любого локального домена я делаю что-то типа:
|
||||
|
||||
```bash
|
||||
mkcert "*.local"
|
||||
mv _wildcard.local-key.pem local.key
|
||||
mv _wildcard.local.pem local.pem
|
||||
```
|
||||
|
||||
И помещаю это в папочку `certs` рядом с `docker-compose.yml`.
|
||||
|
||||
После того как я создал все нужные сертефикаты для всех доменов, их надо указать в файле `config.toml` в папочке traefik.
|
||||
|
||||
Вот пример:
|
||||
|
||||
```toml{}[config.toml]
|
||||
[tls.options]
|
||||
[tls.options.default]
|
||||
@ -173,7 +179,7 @@ mv _wildcard.local.pem local.pem
|
||||
[[tls.certificates]]
|
||||
# Я тут указываю /etc/certs, потому что в docker-compose
|
||||
# у нас volume на эту папку.
|
||||
certFile = "/etc/certs/local.pem"
|
||||
certFile = "/etc/certs/local.pem"
|
||||
keyFile = "/etc/certs/local.key"
|
||||
```
|
||||
|
||||
@ -183,16 +189,18 @@ mv _wildcard.local.pem local.pem
|
||||
|
||||
```toml
|
||||
[[tls.certificates]]
|
||||
certFile = "/etc/certs/<certFile>"
|
||||
certFile = "/etc/certs/<certFile>"
|
||||
keyFile = "/etc/certs/<keyFile>"
|
||||
```
|
||||
|
||||
После этого вы можете запускать traefik и наслаждаться доменами для ваших контейнеров.
|
||||
|
||||
# Запуск приложений
|
||||
|
||||
Теперь сконфигурируем приложение таким образом, чтобы к нему можно было обращаться через доменное имя.
|
||||
|
||||
Для примера возьмем мелкое приложение на nodejs со следующей структурой проекта:
|
||||
|
||||
```
|
||||
.
|
||||
├── docker-compose.yml
|
||||
@ -223,18 +231,18 @@ app.listen(PORT, () => {
|
||||
```
|
||||
|
||||
```json{}[package.json]
|
||||
{
|
||||
"name": "express-test",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"author": "s3rius",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"runserver": "node index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "^4.17.1"
|
||||
}
|
||||
{
|
||||
"name": "express-test",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"author": "s3rius",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"runserver": "node index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "^4.17.1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -260,10 +268,15 @@ services:
|
||||
server:
|
||||
build: .
|
||||
labels:
|
||||
# Включить поддержку роутинга через traefik.
|
||||
- traefik.enable=true
|
||||
# Поставить правило роутинга, если Host запроса равен test_node.local.
|
||||
- traefik.http.routers.test_node.rule=Host(`test_node.local`)
|
||||
# Слушать на entrypoint http (80 порт, это было объявлено в параметрах запуска traefik).
|
||||
- traefik.http.routers.test_node.entrypoints=http
|
||||
# Сервис, связанный с роутером test_node.
|
||||
- traefik.http.routers.test_node.service=node_test
|
||||
# Порт, куда направлять запросы в сервис node_test.
|
||||
- traefik.http.services.node_test.loadbalancer.server.port=3000
|
||||
command: runserver
|
||||
networks:
|
||||
@ -271,6 +284,7 @@ services:
|
||||
|
||||
|
||||
networks:
|
||||
# Докер сеть, в которой находится traefik.
|
||||
traefik-shared:
|
||||
name: traefik-shared
|
||||
external: true
|
||||
@ -282,14 +296,6 @@ networks:
|
||||
|
||||
Как вы видите, приложение слушает на порт `3000` и отвечает свим hostname и количеством обработанных запросов. А в docker-compose.yml, в отличие от обычного проекта, появились labels.
|
||||
|
||||
| Лейбл | Что делает |
|
||||
|---------------------------------------------------------------|---------------------------------------------------------------------------------------|
|
||||
| ``traefik.enable=true`` | Включить поддержку роутинга через traefik |
|
||||
| ``traefik.http.routers.<router>.rule=Host(`test_node.local`)`` | Поставить правило роутинга, если Host запроса равен test_node.local |
|
||||
| ``traefik.http.routers.<router>.entrypoints=http`` | Слушать на entrypoint http (80 порт, это было объявлено в параметрах запуска traefik) |
|
||||
| ``traefik.http.routers.<router>.service=<service>`` | Сервис, связанный с роутером test_node |
|
||||
| ``traefik.http.services.<service>.loadbalancer.server.port=3000`` | Порт, куда направлять запросы в сервис node_test |
|
||||
|
||||
<hr/>
|
||||
<b-message type="is-danger" has-icon>
|
||||
|
||||
@ -300,14 +306,15 @@ networks:
|
||||
|
||||
Обратите внимание на косые кавычки при указании хоста! Это обязательно.
|
||||
|
||||
В объявлении labels могут быть использованы переменные среды. Например:
|
||||
``traefik.http.routers.test_node.rule=Host(`${APP_HOST}`)``
|
||||
В объявлении labels могут быть использованы переменные среды. Например:
|
||||
`` traefik.http.routers.test_node.rule=Host(`${APP_HOST}`) ``
|
||||
|
||||
</b-message>
|
||||
|
||||
Также можно видеть, что я подключил контейнер к сети, которую мы указывали в контейнере traefik. Здесь она помечена как external.
|
||||
|
||||
Теперь мы можем спокойно запустить наш сервис. Для этого воспользуемся следующей командой:
|
||||
|
||||
```bash
|
||||
docker-compose up --build --scale server=3
|
||||
```
|
||||
@ -328,6 +335,7 @@ $ curl -H "Host: test_node.local" "http://localhost"
|
||||
Как вы видите, traefik балансирует между контейнерами за нас. И я считаю, что это - победа.
|
||||
|
||||
## Подключение TLS и сертификатов
|
||||
|
||||
Тут всё не намного сложнее. Давайте немного поменяем лейблы нашего контейнера.
|
||||
|
||||
```yaml
|
||||
@ -347,11 +355,12 @@ services:
|
||||
На данном этапе вам потребуется добавить свой хост в `/etc/hosts`, если вы используете нормальную систему. Но если вы всё же на windows, то вам потребуется добавить правило в `C:\Windows\System32\drivers\etc\hosts`.
|
||||
|
||||
И добавляем в конец файла запись:
|
||||
|
||||
```
|
||||
127.0.0.1 test_node.local
|
||||
```
|
||||
|
||||
И также вам потребуется cертификат на этот домен.
|
||||
И также вам потребуется cертификат на этот домен.
|
||||
Для этого:
|
||||
|
||||
1. Создадим сертификат через `mkcert`, как упоминалось ранее;
|
||||
@ -365,12 +374,12 @@ $ curl --insecure https://test_node.local
|
||||
{"request_num":0,"host":"7417ac8fda92"}
|
||||
```
|
||||
|
||||
|
||||
## Добавление локальных сервисов не из докера
|
||||
|
||||
Все те флаги, которые мы указываем в labels, вы также можете указать в файле конфигурации рядом с docker-compose.yml, указав конкретный ip адрес.
|
||||
|
||||
Например:
|
||||
|
||||
```toml
|
||||
[http.routers]
|
||||
# Define a connection between requests and services
|
||||
@ -387,9 +396,9 @@ $ curl --insecure https://test_node.local
|
||||
url = "http://192.168.1.89:8100"
|
||||
```
|
||||
|
||||
|
||||
# Создание локального DNS
|
||||
В данном пункте я бы хотел рассказать, как настроить свой DNS-сервер, чтобы ваши домены были доступны всем устройствам в локальной сети. Для этого я буду использовать dnsmasq. Пользователям винды он недоступен, поэтому советую развернуть маленький домашний сервер на линуксе.
|
||||
|
||||
В данном пункте я бы хотел рассказать, как настроить свой DNS-сервер, чтобы ваши домены были доступны всем устройствам в локальной сети. Для этого я буду использовать dnsmasq. Пользователям винды он недоступен, поэтому советую развернуть маленький домашний сервер на линуксе.
|
||||
|
||||
Для этого установите `dnsmasq` и найдите и раскомментируйте, либо добавьте следующие строчки в файл `/etc/dnsmasq.conf`:
|
||||
|
||||
@ -406,6 +415,7 @@ address=/.<other_domain>/<your_local_ip>
|
||||
Чтобы это узнать, посмотрите свой ip через роутер или выполните `ip addr`.
|
||||
|
||||
Вообще, `dnsmasq` парсит файл `/etc/hosts` и вы можете туда добавлять записи, типа:
|
||||
|
||||
```
|
||||
192.168.1.1 mydomain.local
|
||||
```
|
||||
@ -413,6 +423,7 @@ address=/.<other_domain>/<your_local_ip>
|
||||
Но так как я указал `address`, то это необязательно. `dnsmasq` и без явного указания поддоменов должен будет работать отлично.
|
||||
|
||||
Запустите `dnsmasq` в режиме сревиса:
|
||||
|
||||
```bash
|
||||
sudo systemctl enable dnsmasq.service
|
||||
sudo systemctl start dnsmasq.service
|
||||
@ -445,7 +456,7 @@ services:
|
||||
- traefik.http.routers.traefik_router.entrypoints=https
|
||||
- traefik.http.routers.traefik_router.tls=true
|
||||
|
||||
command:
|
||||
command:
|
||||
- --api.dashboard=true
|
||||
...
|
||||
```
|
||||
@ -457,5 +468,4 @@ services:
|
||||
|
||||
[](/images/traefik_imgs/traefik_web.png)
|
||||
|
||||
|
||||
Разве это не круто?
|
||||
|
Reference in New Issue
Block a user