mod: проксирование через traefik
This commit is contained in:
parent
3bc414ca98
commit
e2c18fd572
@ -1,100 +1,216 @@
|
|||||||
# Проксирование внешнего хоста через Traefik (Ingress-контроллер)
|
# Проксирование внешнего хоста через Traefik (Ingress-контроллер)
|
||||||
|
|
||||||
У меня в домашней сети есть хост с сервисом (audiobookshelf), то удобно его прокинуть через Traefik, чтобы не открывать
|
У меня в домашней сети есть хост с web-сервисом (audiobookshelf), а стандартные web-порты (80 для HTTP и 443 для HTTPS)
|
||||||
на внешний IP лишних адресов, портов, использовать домен и включить SSL, и управлять всем этим через из единой
|
на домашнем роутере перенаправлены в кластер k3S (через keepalived). Таким образом, если прокинуть http-трафик этого
|
||||||
точки.
|
хоста через Traefik, то можно будет получить доступ к этому сервису через доменное имя и SSL-сертификат от
|
||||||
|
Let’s Encrypt.
|
||||||
|
|
||||||
|
Для удобства я поместил все манифесты в один файл (вы можете оформить из и как отдельные файлы). Так как хотелось бы
|
||||||
|
описать как делаются универсальные манифесты, которые можно использовать для проксирования любого сервиса, то
|
||||||
|
я заменил в нем конкретные значения на "заглушки. Можно взять этот манифест и просто заменить в нем значения на
|
||||||
|
свои:
|
||||||
|
|
||||||
В моем случае:
|
|
||||||
* `<PROXIED-HOST>` -- IP-адрес хоста, где работает сервис, который надо проксировать.
|
* `<PROXIED-HOST>` -- IP-адрес хоста, где работает сервис, который надо проксировать.
|
||||||
* `<PROXIED-PORT>` -- порт, с которого отвечает сервис.
|
* `<PROXIED-PORT>` -- порт, с которого отвечает сервис.
|
||||||
* `<YOU-DOMAIN-NAME>` -- доменное имя, на которое будет проксировать сервис.
|
* `<YOU-DOMAIN-NAME>` -- доменное имя, на которое будет проксировать сервис.
|
||||||
|
* `<NAME-SPACE>` -- пространство имен кластера, в котором будет создан сервис, маршруты, секреты и все необходимое
|
||||||
|
для проксирования. Пространство имен -- это логическая группа ресурсов в кластере Kubernetes, которая позволяет
|
||||||
|
организовать и изолировать ресурсы.
|
||||||
|
* `<SERVICE-NAME>` -- имя сервиса, который будет проксироваться. Это имя, для простоты, будем использоваться
|
||||||
|
* и в маршрутах, и сертификатах, и в секрете...
|
||||||
|
|
||||||
## Пространство имен
|
## Пространство имен
|
||||||
|
|
||||||
Чтобы все было аккуратно и серисы и поды не путались, создадим пространство имен для проксируемого сервиса.
|
Чтобы все было аккуратно и сервисы и поды не путались, создадим пространство имен для проксирования конкретного хоста.
|
||||||
Например, `ab-shelf`.
|
Мо хост относится к <SERVICE-NAME>, поэтому назову пространство имен `<NAME-SPACE>`
|
||||||
|
Например, `<NAME-SPACE>`.
|
||||||
```bash
|
```bash
|
||||||
sudo ubectl create namespace ab-shelf
|
sudo ubectl create namespace <NAME-SPACE>
|
||||||
```
|
```
|
||||||
|
|
||||||
Проверяем, что пространство создано:
|
Проверяем, что пространство создано:
|
||||||
```bash
|
```bash
|
||||||
sudo kubectl get namespace ab-shelf
|
sudo kubectl get namespace <NAME-SPACE>
|
||||||
```
|
```
|
||||||
|
|
||||||
Увидим, что пространство создано и активно:
|
Увидим, что пространство создано и активно:
|
||||||
```text
|
```text
|
||||||
NAME STATUS AGE
|
NAME STATUS AGE
|
||||||
ab-shelf Active 54s
|
<NAME-SPACE> Active 54s
|
||||||
```
|
```
|
||||||
|
|
||||||
## Конфигурация IngressRoute, Service и Endpoints
|
## Конфигурация всего
|
||||||
|
|
||||||
Для удобства я объединил манифесты в один файл (но можно и по отдельности). Создаем единый манифетст:
|
Для удобства я объединил манифесты в один файл (но можно и по отдельности). Создаем единый манифест:
|
||||||
```bash
|
```bash
|
||||||
sudo nano ~/k3s/audiobookshelf/audiobookshelf.yaml
|
sudo nano ~/k3s/<SERVICE-NAME>/<SERVICE-NAME>.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
И вставляем в него следующее содержимое (не забудь заменить `<PROXIED-HOST>`, `<PROXIED-PORT>` и `<YOU-DOMAIN-NAME>`
|
Он состоит из следующих частей:
|
||||||
на свои значения... пространство имен `ab-shelf` и имя сервиса `audiobookshelf` можно тоже поменять на свое, если
|
* `Endpoints` -- указывает на конечную точку, в которую будет проксироваться трафик. В данном случае это
|
||||||
у вас другой сервис):
|
IP-адрес и порт, на который будет проксироваться запрос.
|
||||||
|
* `Service` -- создает сервис, который будет использоваться для проксирования запросов к `Endpoints`.
|
||||||
|
* `Certificate` -- создает сертификат для домена `<YOU-DOMAIN-NAME>`, который будет использоваться для
|
||||||
|
шифрования трафика. Сертификат запрашивается через `cert-manager`, который автоматически обновляет его по мере
|
||||||
|
необходимости.
|
||||||
|
* `Middleware` -- создает промежуточное ПО, которое будет использоваться для обработки запросов. В данном случае
|
||||||
|
это редирект с HTTP на HTTPS и исключение редиректа для ACME challenge (механизма внешней проверки владения доменом
|
||||||
|
со стороны Let’s Encrypt).
|
||||||
|
* `IngressRoute` -- создает маршрут, который будет использоваться для проксирования запросов к сервису.
|
||||||
|
В данном случае это маршруты для HTTP и HTTPS, которые будут обрабатывать запросы на домен `<YOU-DOMAIN-NAME>`.
|
||||||
|
Также создается маршрут для ACME challenge, который позволяет cert-manager пройти проверку через порт 80.
|
||||||
|
|
||||||
|
Вставляем в манифест следующее содержимое (не забудьте заменить `<PROXIED-HOST>`, `<PROXIED-PORT>`, `<YOU-DOMAIN-NAME>`,
|
||||||
|
`<NAME-SPACE>` и `<SERVICE-NAME>` на свои значения):
|
||||||
```yaml
|
```yaml
|
||||||
# Endpoints для внешнего хоста
|
# Endpoints для внешнего хоста <SERVICE-NAME>
|
||||||
|
# Задаёт IP и порт внешнего сервера, так как <SERVICE-NAME> внешний хост для k3s
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Endpoints
|
kind: Endpoints
|
||||||
metadata:
|
metadata:
|
||||||
name: audiobookshelf
|
name: <SERVICE-NAME>
|
||||||
namespace: ab-shelf # пространство, например
|
namespace: <NAME-SPACE> # Namespace для <SERVICE-NAME>
|
||||||
subsets:
|
subsets: # Прямо в корне, без spec
|
||||||
- addresses:
|
- addresses:
|
||||||
- ip: <PROXIED-HOST>
|
- ip: <PROXIED-HOST> # IP Synology, где работает <SERVICE-NAME>
|
||||||
ports:
|
ports:
|
||||||
- port: <PROXIED-PORT>
|
- port: <PROXIED-PORT> # Порт Synology (HTTP)
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
---
|
|
||||||
|
|
||||||
# Service для проксируемого хоста (<PROXIED-HOST>:<PROXIED-PORT>)
|
---
|
||||||
|
# Service для маршрутизации трафика от Traefik к внешнему хосту
|
||||||
|
# Связывает IngressRoute с Endpoints
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: audiobookshelf
|
name: <SERVICE-NAME>
|
||||||
namespace: ab-shelf # пространство, например
|
namespace: <NAME-SPACE>
|
||||||
spec:
|
spec:
|
||||||
ports:
|
ports:
|
||||||
- port: <PROXIED-PORT>
|
- port: <PROXIED-PORT> # Порт сервиса, на который Traefik отправляет трафик
|
||||||
targetPort: <PROXIED-PORT>
|
targetPort: <PROXIED-PORT> # Порт на Synology
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
---
|
|
||||||
|
|
||||||
# IngressRoute
|
---
|
||||||
|
# Certificate для TLS-сертификата от Let’s Encrypt
|
||||||
|
# Запрашивает сертификат для <YOU-DOMAIN-NAME> через cert-manager
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: <SERVICE-NAME>-tls
|
||||||
|
namespace: <NAME-SPACE>
|
||||||
|
spec:
|
||||||
|
secretName: <SERVICE-NAME>-tls # Имя секрета для сертификата
|
||||||
|
dnsNames:
|
||||||
|
- <YOU-DOMAIN-NAME> # Домен для сертификата
|
||||||
|
issuerRef:
|
||||||
|
name: letsencrypt-prod # ClusterIssuer для Let’s Encrypt
|
||||||
|
kind: ClusterIssuer
|
||||||
|
|
||||||
|
---
|
||||||
|
# Middleware для редиректа HTTP → HTTPS
|
||||||
|
# Применяется к HTTP-запросам для перенаправления на HTTPS
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: Middleware
|
||||||
|
metadata:
|
||||||
|
name: https-redirect
|
||||||
|
namespace: <NAME-SPACE>
|
||||||
|
spec:
|
||||||
|
redirectScheme:
|
||||||
|
scheme: https # Перенаправлять на HTTPS
|
||||||
|
permanent: true # Код 301 (постоянный редирект)
|
||||||
|
|
||||||
|
---
|
||||||
|
# Middleware для исключения редиректа на ACME challenge
|
||||||
|
# Позволяет Let’s Encrypt проверять /.well-known/acme-challenge без HTTPS
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: Middleware
|
||||||
|
metadata:
|
||||||
|
name: no-https-redirect
|
||||||
|
namespace: <NAME-SPACE>
|
||||||
|
spec:
|
||||||
|
stripPrefix:
|
||||||
|
prefixes:
|
||||||
|
- /.well-known/acme-challenge # Убрать префикс для ACME
|
||||||
|
|
||||||
|
---
|
||||||
|
# IngressRoute для HTTP (порт 80) с редиректом на HTTPS
|
||||||
|
# Обрабатывает HTTP-запросы и перенаправляет их
|
||||||
apiVersion: traefik.containo.us/v1alpha1
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
metadata:
|
metadata:
|
||||||
name: audiobookshelf
|
name: <SERVICE-NAME>-http
|
||||||
namespace: ab-shelf # пространство, например
|
namespace: <NAME-SPACE>
|
||||||
spec:
|
spec:
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- web-custom # ендпоинт, который "слушает" порт 2055
|
- web # Порт 80 (стандартный HTTP)
|
||||||
|
routes:
|
||||||
|
- match: Host("<YOU-DOMAIN-NAME>") # Запросы к <YOU-DOMAIN-NAME>
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: <SERVICE-NAME> # Сервис <SERVICE-NAME>
|
||||||
|
port: <PROXIED-PORT> # Порт сервиса
|
||||||
|
middlewares:
|
||||||
|
- name: https-redirect # Редирект на HTTPS
|
||||||
|
|
||||||
|
---
|
||||||
|
# IngressRoute для HTTPS (порт 443)
|
||||||
|
# Обрабатывает HTTPS-запросы с TLS
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: <SERVICE-NAME>-https
|
||||||
|
namespace: <NAME-SPACE>
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure # Порт 443 (HTTPS)
|
||||||
routes:
|
routes:
|
||||||
- match: Host("<YOU-DOMAIN-NAME>")
|
- match: Host("<YOU-DOMAIN-NAME>")
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: audiobookshelf
|
- name: <SERVICE-NAME>
|
||||||
port: <PROXIED-PORT>
|
port: <PROXIED-PORT>
|
||||||
|
tls:
|
||||||
|
secretName: <SERVICE-NAME>-tls # Сертификат от cert-manager
|
||||||
|
|
||||||
|
---
|
||||||
|
# IngressRoute для HTTP-01 challenge (Let’s Encrypt)
|
||||||
|
# Позволяет cert-manager пройти проверку через порт 80
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: <SERVICE-NAME>-acme
|
||||||
|
namespace: <NAME-SPACE>
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- web # Порт 80
|
||||||
|
routes:
|
||||||
|
- match: Host("<YOU-DOMAIN-NAME>") && PathPrefix("/.well-known/acme-challenge")
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: <SERVICE-NAME>
|
||||||
|
port: <PROXIED-PORT>
|
||||||
|
middlewares:
|
||||||
|
- name: no-https-redirect # Не редиректить ACME
|
||||||
```
|
```
|
||||||
|
|
||||||
Что тут происходит:
|
ВАЖНО: В манифесте используется letsencrypt-prod для получения сертификата от Let’s Encrypt. Это нестандартный
|
||||||
* `Endpoints` -- указываем, что сервис будет проксировать запросы на внешний хост `<PROXIED-HOST>`
|
ClusterIssuer cert-manager, создание которого описано в [документации](https://cert-manager.io/docs/usage/ingress/#tls-termination)
|
||||||
и порт `<PROXIED-PORT>`. Ендпоинт -- это конечная точка, к которой будет проксироваться запрос. В данном случае
|
и [отдельной инструкции](k3s-custom-container-deployment.md#создание-clusterissuer)
|
||||||
это IP-адрес и порт, но обычно это имя пода, на который отправляются и который отвечает на запросы.
|
(возможно, вам нужно будет создать его отдельно). Если вы используете другой ClusterIssuer, то замените letsencrypt-prod
|
||||||
* `Service` -- создаем сервис, который будет использоваться для проксирования запросов к `Endpoints`. Сервис -- это
|
на имя вашего ClusterIssuer в секции `issuerRef` в манифесте.
|
||||||
абстракция, которая позволяет упрощать доступ к подам. Он может использоваться для балансировки нагрузки между
|
|
||||||
несколькими потоками, которые обрабатывают запросы. В данном случае мы создаем сервис, который будет проксировать
|
|
||||||
запросы к `Endpoints` (внешнему хосту).
|
|
||||||
* `IngressRoute` -- создаем маршрут, который будет проксировать запросы на домен `<YOU-DOMAIN-NAME>`
|
|
||||||
к сервису `audiobookshelf` в пространстве `ab-shelf`. Маршрут -- это правило, которое определяет, как обрабатывать
|
|
||||||
запросы, поступающие на определенный адрес. В данном случае мы создаем маршрут, который будет направлять запросы
|
|
||||||
на домен `<YOU-DOMAIN-NAME>` к сервису `audiobookshelf` в пространстве `ab-shelf`. Внутри маршрута мы указываем,
|
|
||||||
что запросы должны обрабатываться сервисом `audiobookshelf` на порту `<PROXIED-PORT>`.
|
|
||||||
В данном случае мы используем `web-custom` как точку входа, которая будет слушать порт 2055.
|
|
||||||
|
|
||||||
|
## Применяем манифест
|
||||||
|
```bash
|
||||||
|
sudo kubectl apply -f ~/k3s/<SERVICE-NAME>/<SERVICE-NAME>.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Проверяем, что все ресурсы создались:
|
||||||
|
```bash
|
||||||
|
sudo kubectl get all -n <NAME-SPACE>
|
||||||
|
```
|
||||||
|
|
||||||
|
Проверяем, что сертификат создан:
|
||||||
|
```bash
|
||||||
|
sudo kubectl describe certificate -n <NAME-SPACE> <SERVICE-NAME>-tls
|
||||||
|
```
|
Loading…
x
Reference in New Issue
Block a user