14 - Hubble¶
K3s Homelab — Sesja 14 (Hubble debugging marathon)¶
Daty: 2026-03-14, 2026-03-15, 2026-03-16
Środowisko: 3x HP T630, k3s v1.34.4, Flux v2.8.1, Cilium v1.19.1 (VXLAN)
Co próbowaliśmy zrobić¶
Uruchomić Hubble UI — wbudowany w Cilium system observability sieci.
Czego NIE udało się zrobić¶
Hubble relay nadal nie działa. Klaster był kilkukrotnie destabilizowany.
Stan końcowy¶
Klaster stabilny, wszystko działa oprócz Hubble relay. Konfiguracja Cilium: VXLAN, kubeProxyReplacement: false, kube-proxy k3s włączony.
Root cause problemu z Hubble¶
Architektura Hubble¶
Cilium Agent (każdy node) → nasłuchuje na port 4244 (gRPC, node IP)
↑
Hubble Relay pod (IP z puli podów, np. 10.0.0.x)
↑
Hubble UI
Dlaczego relay nie działa z VXLAN¶
Relay pod ma IP z puli podów (10.0.0.x). Próbuje połączyć się z agentami na 192.168.55.x:4244 (node IP). W trybie VXLAN Cilium nie routuje ruchu pod→nodeIP — pakiety przepadają w BPF datapath zanim dotrą do fizycznego interfejsu.
Potwierdzono przez tcpdump: pakiety SYN widoczne na veth interfejsie poda, ale nigdy nie docierają do enp1s0 nodów docelowych.
relay pod (10.0.0.x) → SYN → 192.168.55.11:4244
Master widzi SYN na lxc interface ← ale nigdy nie wychodzi przez enp1s0
Dlaczego hostNetwork nie wchodzi w grę¶
Cilium Helm chart nie ma opcji hostNetwork dla relay — nie jest to wspierana konfiguracja. Próba przez postRenderers w HelmRelease byłaby obejściem niezgodnym z zamierzeniem projektu.
Co próbowaliśmy (chronologicznie)¶
1. Usunięcie i regeneracja certyfikatów TLS Hubble¶
Wynik: Certyfikaty się zregenerowały. Problem nie był w certach — TLS handshake działał poprawnie.
Lekcja: Zawsze sprawdź czy problem jest sieciowy czy TLS zanim zaczniesz grzebać w certach. openssl s_client z node→node pokazał że TLS działa.
2. Dodanie hubble.tls.auto.method: helm do HelmRelease¶
Wynik: Cilium operator zaczął regenerować certyfikaty automatycznie. Dobra zmiana, ale nie rozwiązała problemu z routingiem.
3. Reguły UFW dla portów 4240/4244¶
Wynik: UFW nie był problemem — już miał 10.0.0.0/8 ALLOW Anywhere które pokrywało te porty.
4. kubeProxyReplacement: true bez zmiany routing mode¶
Wynik: Klaster niestabilny. kubeProxyReplacement: true bez routingMode: native powoduje niespójny stan — Cilium próbuje przejąć obsługę serwisów ale nie ma pełnego native routing.
Lekcja: kubeProxyReplacement: true i routingMode: native muszą być włączone razem.
5. Próba przejścia na native routing na żywym klastrze (rolling update)¶
Wynik: Katastrofa. Podczas rolling update Cilium DaemonSet jeden node miał native routing a pozostałe VXLAN → ruch sieciowy się posypał → SSH przestało działać → klaster niedostępny.
Lekcja: Zmiana routing mode Cilium wymaga pełnego restartu klastra. Rolling update DaemonSet nie jest bezpieczny przy zmianie fundamentalnych parametrów CNI.
6. --disable-kube-proxy w k3s.service¶
Efekt: Dodane podczas próby przejścia na native routing. Po cofnięciu Cilium do VXLAN z kubeProxyReplacement: false — nikt nie obsługiwał ClusterIP ani NodePort. Klaster działał "od wewnątrz" ale żaden zewnętrzny ruch nie docierał (Traefik, Grafana, wszystkie Ingress przestały działać).
Lekcja: --disable-kube-proxy ma sens TYLKO gdy kubeProxyReplacement: true i Cilium jest w trybie native routing.
7. Próby naprawy ConfigMap ręcznie przez kubectl patch¶
Wynik: Działało jako rescue — pozwalało przywrócić VXLAN gdy klaster był niedostępny przez Flux.
Kluczowe wnioski techniczne¶
Cilium routing modes¶
| Tryb | Opis | Pod→NodeIP | KubeProxy needed |
|---|---|---|---|
| VXLAN (tunnel) | Enkapsulacja L3, działa wszędzie | ❌ | Tak (lub kubeProxyReplacement) |
| Native routing | Bezpośredni routing L2, wymaga tej samej podsieci | ✅ | Nie (kubeProxyReplacement) |
Dlaczego Prometheus działa z hostNetwork a relay nie może¶
Prometheus używa hostNetwork: true — działa na sieci hosta, ma bezpośredni dostęp do node IP. To jest udokumentowane obejście dla k3s. Cilium Helm chart nie przewiduje hostNetwork dla relay.
Prawidłowa konfiguracja dla native routing¶
# Cilium HelmRelease values
kubeProxyReplacement: true
routingMode: native
autoDirectNodeRoutes: true
ipv4NativeRoutingCIDR: "10.0.0.0/8"
Wymagania: wszystkie nody w tej samej podsieci L2 (spełnione — 192.168.55.0/24).
Bezpieczny sposób zmiany routing mode¶
- Zaktualizuj HelmRelease w Git
- Graceful shutdown klastra przez Ansible
- Włącz wszystkie nody jednocześnie (lub master + workery z małym opóźnieniem)
- Flux zaaplikuje nową konfigurację przy starcie
- NIE rób rolling update DaemonSet na żywym klastrze
Dlaczego "delete all Cilium pods at once" jest bezpieczniejsze niż rolling update¶
Przy jednoczesnym usunięciu wszystkich podów — wszystkie nody tracą CNI jednocześnie i odbudowują się z tą samą konfiguracją. Brak okna gdy jeden node ma native a drugi VXLAN.
Stan klastru po sesjach¶
Działa:
- Cilium VXLAN ✅
- kube-proxy k3s ✅ (przywrócony)
- Traefik + TLS ✅
- Grafana / Prometheus / Loki ✅
- AlertManager + ntfy ✅
- clients-api + CloudNativePG ✅
- Longhorn + S3 backup ✅
- metrics-server ✅ (z flagą
--authentication-tolerate-lookup-failure=true) - Sealed Secrets ✅
- Flux image automation ✅
Nie działa:
- Hubble relay ❌ — wymaga native routing
Konfiguracja Cilium (aktualna):
values:
k8sServiceHost: 192.168.55.10
k8sServicePort: 6443
operator:
replicas: 1
hubble:
enabled: true
tls:
auto:
enabled: true
method: helm
relay:
enabled: true
ui:
enabled: true
ingress:
enabled: true
ingressClassName: traefik
hosts:
- hubble.cluster.kcn333.com
tls:
- secretName: hubble-tls
hosts:
- hubble.cluster.kcn333.com
Plan na przyszłość — przejście na native routing¶
Zrobić w osobnej sesji, ze świeżą głową:
- Zaktualizuj HelmRelease Cilium z pełną konfiguracją native
- Graceful shutdown klastra
- Start klastra — Flux zaaplikuje nowe ustawienia
- Weryfikacja
Nie próbuj tego na żywym klastrze przez rolling update.
Przydatne komendy do debugowania Cilium¶
# Status Cilium
kubectl -n kube-system exec ds/cilium -- cilium status | grep -E "Routing|KubeProxy|Hubble|Cluster"
# Test TCP z agenta do innego agenta
kubectl -n kube-system exec ds/cilium -- \
openssl s_client -connect 192.168.55.11:4244 \
-CAfile /var/lib/cilium/tls/hubble/client-ca.crt \
-cert /var/lib/cilium/tls/hubble/server.crt \
-key /var/lib/cilium/tls/hubble/server.key \
2>&1 | head -10
# Sprawdź trasy w kernel routing table
ssh master "ip route | grep '10\.0'"
# tcpdump na veth poda relay
ssh master "sudo tcpdump -i any -n 'port 4244' -c 20"
# Monitor dropów Cilium
kubectl -n kube-system exec ds/cilium -- cilium monitor --type drop
# ConfigMap Cilium
kubectl get configmap -n kube-system cilium-config -o yaml | \
grep -E "routing-mode|kube-proxy|auto-direct|tunnel"
# Rescue — cofnij do VXLAN gdy klaster jest niedostępny
kubectl patch configmap cilium-config -n kube-system \
--type merge \
-p '{"data":{"routing-mode":"tunnel","kube-proxy-replacement":"false","auto-direct-node-routes":"false"}}'
kubectl delete pods -n kube-system -l k8s-app=cilium --force --grace-period=0