Files
K3S/docs/networking.md
Sergey Antropoff 5079975d5e feat: добавить аддон ingress-add-domains — добавить домены к сервисам кластера
Helm chart + Ansible роль, создающие Ingress-only правила для уже существующих
K8s сервисов. Каждый Ingress создаётся в namespace целевого сервиса.

Поддерживает: TLS (cert-manager или готовый Secret), basic auth (автохэш пароля
через openssl passwd -apr1), WebSocket, несколько хостов, per-entry аннотации.
2026-04-26 12:02:41 +03:00

10 KiB
Raw Blame History

Сеть и доступ

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/.*"