Helm chart + Ansible роль, создающие Ingress-only правила для уже существующих K8s сервисов. Каждый Ingress создаётся в namespace целевого сервиса. Поддерживает: TLS (cert-manager или готовый Secret), basic auth (автохэш пароля через openssl passwd -apr1), WebSocket, несколько хостов, per-entry аннотации.
10 KiB
Сеть и доступ
ingress-nginx
HTTP/S Ingress controller, точка входа для всех веб-приложений кластера. Подробнее: addons/ingress-nginx/README.md.
addon_ingress_nginx: true
ingress_nginx_load_balancer_ip: "" # авто от kube-vip
Базовый Ingress:
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.
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.
addon_istio: true
istio_mtls_mode: "STRICT"
kiali_enabled: true
Включить sidecar injection
kubectl label namespace my-app istio-injection=enabled
VirtualService routing
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.
Быстрый старт
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)
Подключение клиентов
netbird up --management-url grpc://netbird.example.com:80
ingress-add-domains — добавить домены к сервисам кластера
Позволяет быстро открыть дополнительные домены для уже существующих K8s сервисов без изменения их шаблонов. Создаёт только Ingress в namespace целевого сервиса. Подробнее: addons/ingress-add-domains/README.md.
# 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 }}"
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.
# 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 }}" # хэш генерируется автоматически
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.
# 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
# Режим 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.
# inventory/hosts.ini
[hysteria2_server]
myvps ansible_host=1.2.3.4 ansible_user=root
# group_vars/all/vault.yml
vault_hysteria2_server_password: "мойпароль"
# По 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 из подсети кластера.
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".
# Запретить весь трафик в 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 — дополнительные возможности
k3s_cni: "cilium"
cilium_hubble_enabled: true # observability
cilium_hubble_ui_enabled: false # Hubble UI
L7 Network Policy (только Cilium):
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/.*"