Helm chart + Ansible роль, создающие Ingress-only правила для уже существующих K8s сервисов. Каждый Ingress создаётся в namespace целевого сервиса. Поддерживает: TLS (cert-manager или готовый Secret), basic auth (автохэш пароля через openssl passwd -apr1), WebSocket, несколько хостов, per-entry аннотации.
394 lines
10 KiB
Markdown
394 lines
10 KiB
Markdown
# Сеть и доступ
|
||
|
||
## ingress-nginx
|
||
|
||
HTTP/S Ingress controller, точка входа для всех веб-приложений кластера. Подробнее: [addons/ingress-nginx/README.md](../addons/ingress-nginx/README.md).
|
||
|
||
```yaml
|
||
addon_ingress_nginx: true
|
||
ingress_nginx_load_balancer_ip: "" # авто от kube-vip
|
||
```
|
||
|
||
Базовый Ingress:
|
||
```yaml
|
||
apiVersion: networking.k8s.io/v1
|
||
kind: Ingress
|
||
metadata:
|
||
name: my-app
|
||
annotations:
|
||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||
spec:
|
||
ingressClassName: nginx
|
||
tls:
|
||
- hosts: [myapp.example.com]
|
||
secretName: myapp-tls
|
||
rules:
|
||
- host: myapp.example.com
|
||
http:
|
||
paths:
|
||
- path: /
|
||
pathType: Prefix
|
||
backend:
|
||
service:
|
||
name: my-app
|
||
port:
|
||
number: 80
|
||
```
|
||
|
||
---
|
||
|
||
## cert-manager — TLS сертификаты
|
||
|
||
Автоматические TLS сертификаты от Let's Encrypt или самоподписанного CA. Подробнее: [addons/cert-manager/README.md](../addons/cert-manager/README.md).
|
||
|
||
```yaml
|
||
addon_cert_manager: true
|
||
cert_manager_issuer: "letsencrypt"
|
||
cert_manager_acme_email: "admin@example.com"
|
||
```
|
||
|
||
---
|
||
|
||
## Istio — Service Mesh
|
||
|
||
mTLS между сервисами, traffic management, observability. Подробнее: [addons/istio/README.md](../addons/istio/README.md).
|
||
|
||
```yaml
|
||
addon_istio: true
|
||
istio_mtls_mode: "STRICT"
|
||
kiali_enabled: true
|
||
```
|
||
|
||
### Включить sidecar injection
|
||
|
||
```bash
|
||
kubectl label namespace my-app istio-injection=enabled
|
||
```
|
||
|
||
### VirtualService routing
|
||
|
||
```yaml
|
||
apiVersion: networking.istio.io/v1alpha3
|
||
kind: VirtualService
|
||
metadata:
|
||
name: my-app
|
||
spec:
|
||
hosts: ["myapp.local"]
|
||
gateways: ["istio-system/istio-ingressgateway"]
|
||
http:
|
||
- route:
|
||
- destination:
|
||
host: my-app
|
||
port:
|
||
number: 80
|
||
```
|
||
|
||
---
|
||
|
||
## NetBird VPN
|
||
|
||
Self-hosted WireGuard VPN с управляемым сервером. Клиенты из любой точки мира получают доступ к подсетям кластера. Подробнее: [addons/netbird/README.md](../addons/netbird/README.md).
|
||
|
||
### Быстрый старт
|
||
|
||
```yaml
|
||
addon_netbird: true
|
||
netbird_domain: "netbird.example.com"
|
||
|
||
# Subnet Router — доступ к локальной сети из VPN
|
||
netbird_subnet_router_enabled: true
|
||
netbird_subnet_routes:
|
||
- "192.168.1.0/24" # локальная сеть
|
||
- "10.42.0.0/16" # pod CIDR
|
||
- "10.43.0.0/16" # service CIDR
|
||
|
||
# Exit Node — интернет через кластер
|
||
netbird_exit_node_enabled: false
|
||
```
|
||
|
||
### Архитектура
|
||
|
||
```
|
||
VPN Client
|
||
│ WireGuard
|
||
├──→ Management (gRPC LoadBalancer IP)
|
||
├──→ Signal (WebRTC signaling)
|
||
└──→ Coturn (STUN/TURN для NAT traversal)
|
||
│
|
||
└──→ Subnet Router Pod ──→ 192.168.1.0/24
|
||
└──→ 10.42.0.0/16 (pods)
|
||
```
|
||
|
||
### Подключение клиентов
|
||
|
||
```bash
|
||
netbird up --management-url grpc://netbird.example.com:80
|
||
```
|
||
|
||
---
|
||
|
||
## ingress-add-domains — добавить домены к сервисам кластера
|
||
|
||
Позволяет быстро открыть дополнительные домены для уже существующих K8s сервисов без изменения их шаблонов. Создаёт **только Ingress** в namespace целевого сервиса. Подробнее: [addons/ingress-add-domains/README.md](../addons/ingress-add-domains/README.md).
|
||
|
||
```yaml
|
||
# group_vars/all/addons.yml
|
||
addon_ingress_add_domains: true
|
||
|
||
ingress_add_domains_entries:
|
||
# Внутренний домен без TLS
|
||
- name: gitea-local
|
||
hosts: [gitea.local]
|
||
service:
|
||
name: gitea-http
|
||
namespace: gitea
|
||
port: 3000
|
||
|
||
# Внешний домен с TLS + basic auth
|
||
- name: grafana-home
|
||
hosts: [grafana.home.ru]
|
||
service:
|
||
name: prometheus-stack-grafana
|
||
namespace: monitoring
|
||
port: 80
|
||
tls:
|
||
enabled: true
|
||
certManager:
|
||
enabled: true
|
||
issuer: letsencrypt-prod
|
||
auth:
|
||
enabled: true
|
||
username: admin
|
||
password: "{{ vault_grafana_proxy_password }}"
|
||
```
|
||
|
||
```bash
|
||
make addon-ingress-add-domains
|
||
```
|
||
|
||
| Сценарий | Инструмент |
|
||
|---|---|
|
||
| Открыть K8s-сервис по новому домену | **ingress-add-domains** |
|
||
| Проксировать сервис вне кластера (по IP) | ingress-proxypass |
|
||
|
||
---
|
||
|
||
## ingress-proxypass — проксировать внешние сервисы
|
||
|
||
Позволяет открыть по домену любой сервис, работающий **вне кластера** (роутер, NAS, Plex на отдельной машине и т.д.), через тот же ingress-nginx VIP. Для каждой записи создаётся: `Service (ClusterIP, без selector)` + `Endpoints` + `Ingress`. Подробнее: [addons/ingress-proxypass/README.md](../addons/ingress-proxypass/README.md).
|
||
|
||
```yaml
|
||
# group_vars/all/addons.yml
|
||
addon_ingress_proxypass: true
|
||
|
||
ingress_proxypass_proxies:
|
||
- name: router
|
||
hosts: [router.home.ru]
|
||
ips: [192.168.1.1]
|
||
port: 8080
|
||
|
||
- name: nas
|
||
hosts: [nas.home.ru]
|
||
ips: [192.168.1.20]
|
||
port: 5000
|
||
tls:
|
||
enabled: true
|
||
secretName: wildcard-tls
|
||
|
||
- name: grafana-ext
|
||
hosts: [grafana.home.ru]
|
||
ips: [192.168.1.60]
|
||
port: 3000
|
||
auth:
|
||
enabled: true
|
||
username: admin
|
||
password: "{{ vault_proxy_password }}" # хэш генерируется автоматически
|
||
```
|
||
|
||
```bash
|
||
make addon-ingress-proxypass
|
||
```
|
||
|
||
Маршрут трафика: `kube-vip VIP → ingress-nginx → Service → Endpoints → внешний IP:PORT`
|
||
|
||
---
|
||
|
||
## splitgw — прозрачный split-tunnel gateway
|
||
|
||
Устанавливает `sing-box` с TPROXY-перехватом на хосте или K3S DaemonSet. Трафик с указанных устройств (Smart TV и т.п.) маршрутизируется по правилам: YouTube/Google → Hysteria2 VPN, RU-сервисы и частные сети → прямой маршрут. Подробнее: [addons/splitgw/README.md](../addons/splitgw/README.md).
|
||
|
||
```yaml
|
||
# group_vars/all/addons.yml (+ group [splitgw] в inventory)
|
||
addon_splitgw: true
|
||
|
||
splitgw_tv_sources:
|
||
- "192.168.1.100/32" # Smart TV
|
||
|
||
splitgw_router_ip: "192.168.1.1"
|
||
# vault_hysteria2_url задаётся в vault.yml
|
||
```
|
||
|
||
```bash
|
||
# Режим systemd на хосте (по умолчанию):
|
||
make addon-splitgw
|
||
|
||
# Режим K8s DaemonSet:
|
||
make addon-splitgw ARGS="-e splitgw_deploy_mode=k8s"
|
||
```
|
||
|
||
Маршрут: `Smart TV → шлюз splitgw (TPROXY:7893) → sing-box → YouTube/Google: Hysteria2 VPN | остальное: прямой`
|
||
|
||
---
|
||
|
||
## hysteria2-server — VPN-сервер на удалённом VPS
|
||
|
||
Устанавливает Hysteria2-сервер на внешний VPS (не часть кластера). Сервер нужен для `splitgw` и `mediaserver` (Prowlarr sidecar). Подробнее: [addons/hysteria2-server/README.md](../addons/hysteria2-server/README.md).
|
||
|
||
```yaml
|
||
# inventory/hosts.ini
|
||
[hysteria2_server]
|
||
myvps ansible_host=1.2.3.4 ansible_user=root
|
||
|
||
# group_vars/all/vault.yml
|
||
vault_hysteria2_server_password: "мойпароль"
|
||
```
|
||
|
||
```bash
|
||
# По SSH-ключу:
|
||
make addon-hysteria2-server
|
||
|
||
# По SSH-паролю (интерактивный ввод):
|
||
make addon-hysteria2-server ARGS="-k"
|
||
```
|
||
|
||
После установки выводится готовая URL-строка для Shadowrocket / NekoBox / Hiddify:
|
||
|
||
```
|
||
hysteria2://пароль@1.2.3.4:443?insecure=1#MyVPS
|
||
```
|
||
|
||
---
|
||
|
||
## kube-vip LoadBalancer
|
||
|
||
kube-vip обрабатывает все `LoadBalancer` сервисы — каждый сервис с `type: LoadBalancer` автоматически получает IP из подсети кластера.
|
||
|
||
```yaml
|
||
apiVersion: v1
|
||
kind: Service
|
||
metadata:
|
||
name: my-tcp-service
|
||
annotations:
|
||
kube-vip.io/loadbalancerIPs: "192.168.1.150" # статический IP (опционально)
|
||
spec:
|
||
type: LoadBalancer
|
||
ports:
|
||
- port: 8080
|
||
targetPort: 8080
|
||
selector:
|
||
app: my-app
|
||
```
|
||
|
||
---
|
||
|
||
## DNS внутри кластера
|
||
|
||
Паттерны DNS для сервисов:
|
||
|
||
```
|
||
<service>.<namespace>.svc.cluster.local
|
||
|
||
# Примеры:
|
||
postgresql.postgresql.svc.cluster.local:5432
|
||
minio.minio.svc.cluster.local:9000
|
||
vault.vault.svc.cluster.local:8200
|
||
loki.loki.svc.cluster.local:3100
|
||
smtp-relay.smtp-relay.svc.cluster.local:25
|
||
tempo.tempo.svc.cluster.local:4317
|
||
```
|
||
|
||
---
|
||
|
||
## Network Policies (Calico/Cilium)
|
||
|
||
Требует `k3s_cni: "calico"` или `k3s_cni: "cilium"`.
|
||
|
||
```yaml
|
||
# Запретить весь трафик в namespace:
|
||
apiVersion: networking.k8s.io/v1
|
||
kind: NetworkPolicy
|
||
metadata:
|
||
name: default-deny-all
|
||
namespace: my-app
|
||
spec:
|
||
podSelector: {}
|
||
policyTypes: [Ingress, Egress]
|
||
---
|
||
# Разрешить только из ingress-nginx:
|
||
apiVersion: networking.k8s.io/v1
|
||
kind: NetworkPolicy
|
||
metadata:
|
||
name: allow-ingress
|
||
namespace: my-app
|
||
spec:
|
||
podSelector:
|
||
matchLabels:
|
||
app: my-app
|
||
ingress:
|
||
- from:
|
||
- namespaceSelector:
|
||
matchLabels:
|
||
kubernetes.io/metadata.name: ingress-nginx
|
||
ports:
|
||
- port: 8080
|
||
---
|
||
# Разрешить DNS (CoreDNS):
|
||
apiVersion: networking.k8s.io/v1
|
||
kind: NetworkPolicy
|
||
metadata:
|
||
name: allow-dns
|
||
namespace: my-app
|
||
spec:
|
||
podSelector: {}
|
||
egress:
|
||
- ports:
|
||
- port: 53
|
||
protocol: UDP
|
||
- port: 53
|
||
protocol: TCP
|
||
```
|
||
|
||
---
|
||
|
||
## Cilium — дополнительные возможности
|
||
|
||
```yaml
|
||
k3s_cni: "cilium"
|
||
cilium_hubble_enabled: true # observability
|
||
cilium_hubble_ui_enabled: false # Hubble UI
|
||
```
|
||
|
||
L7 Network Policy (только Cilium):
|
||
```yaml
|
||
apiVersion: cilium.io/v2
|
||
kind: CiliumNetworkPolicy
|
||
metadata:
|
||
name: allow-http-get
|
||
spec:
|
||
endpointSelector:
|
||
matchLabels:
|
||
app: my-api
|
||
ingress:
|
||
- fromEndpoints:
|
||
- matchLabels:
|
||
app: frontend
|
||
toPorts:
|
||
- ports:
|
||
- port: "8080"
|
||
protocol: TCP
|
||
rules:
|
||
http:
|
||
- method: GET
|
||
path: "/api/.*"
|
||
```
|