numer 02 phile 01 z 01
Ping przechodzi. Nic poza nim.
Ping przechodzi. Nic poza nim.
31 lipca 2026. Lab, trzy maszyny wirtualne pod VMware, świeży klaster k3s z flannelem.
Instalacja przechodzi bez jednego błędu. Wszystkie trzy węzły Ready. I od tego momentu
przez sześć godzin nic nie działa tak, jak powinno.
Zacznę od końca, bo tego szukałeś w wyszukiwarce o drugiej w nocy:
ethtool -K flannel.1 tx-checksum-ip-generic off
Jedna linijka. Reszta tekstu jest o tym, dlaczego szedłem do niej sześć godzin przez cztery fałszywe tropy — i dlaczego każdy z nich wyglądał na właściwy.
Objaw, który kłamie
Pierwsze, co zobaczyłem, nie miało nic wspólnego z siecią:
longhorn-system longhorn-driver-deployer-58d6555f47-kl4bs 0/1 CrashLoopBackOff
A w logu poda zdanie, które wysyła człowieka w zupełnie złą stronę:
Error from server (NotFound): deployments.apps "csi-resizer" not found
Czyli: brakuje deploymentu. Więc szukasz, dlaczego go nie ma. Sprawdzasz wersję Longhorna,
czytasz changelog między 1.10 a 1.11, szukasz zmian w nazwach komponentów CSI, sprawdzasz
values.yaml, zastanawiasz się, czy ktoś nie wyciął czegoś z chartu.
Nie ma tam nic. Deployment nie powstał, bo proces, który miał go utworzyć, nie zdążył — poległ wcześniej, na czymś zupełnie innym. Komunikat opisuje skutek, nie przyczynę. Właściwy log był kilka linijek wyżej i mówił coś znacznie ciekawszego:
longhorn-backend:9500 context deadline exceeded
Deployer chciał pogadać z własnym backendem po HTTP i nie doczekał się odpowiedzi. Backend stał na innym węźle.
Trop pierwszy: brakujące pakiety
Longhorn wymaga open-iscsi i nfs-common. Klasyka gatunku — przy braku iscsid
wszystko wygląda dokładnie tak samo. Sprawdziłem:
● iscsid.service active (running)
○ multipathd.service inactive (dead)
iscsid chodzi. multipathd nie chodzi i tak ma być — Longhorn wręcz prosi,
żeby go wyłączyć albo dodać wykluczenie, bo multipath potrafi porwać jego urządzenia
blokowe. Czyli tu porządek. Trop odpada, dwadzieścia minut w plecy.
Trop drugi: firewall
Świeżo wygenerowane reguły ufw, a w statusie:
Default: deny (routed)
Wygląda jak wyrok. Ruch między podami jest routowany, a domyślna polityka go odrzuca —
przecież to musi być to. Dopisałem ufw default allow routed, przeładowałem, sprawdziłem.
Nic. Longhorn dalej się nie podnosił. Reguła była potrzebna i została, ale nie była przyczyną. Korelacja, nie związek. To najkosztowniejszy rodzaj tropu, bo poprawka jest sensowna i zostaje w konfiguracji, przez co masz poczucie postępu.
Trop trzeci: MTU
Tunel VXLAN dokłada 50 bajtów narzutu, więc flannel.1 chodzi z MTU 1450 zamiast 1500.
Jeśli gdzieś po drodze ktoś nie przepuszcza fragmentacji albo blokuje ICMP typu 3,
dostajesz dokładnie takie objawy: małe pakiety przechodzą, duże giną, połączenie wisi.
Klasyczny czarny dziura PMTUD.
$ ping -M do -s 1422 10.42.2.14
1430 bytes from 10.42.2.14: icmp_seq=1 ttl=64 time=0.41 ms
Przechodzi. Pełny pakiet, bez fragmentacji, zero strat. MTU jest w porządku. I to jest moment, w którym zaczyna być naprawdę dziwnie.
Moment, w którym wszystko się zmienia
Zestawmy dwie rzeczy obok siebie, bo w tym zestawieniu jest cała odpowiedź:
$ ping -c3 10.42.2.14
3 packets transmitted, 3 received, 0% packet loss
$ curl -sk https://10.42.2.14:9502/v1/healthz
(wisi. w nieskończoność.)
ICMP lata bez zarzutu. Każde połączenie TCP między węzłami wisi. Nie „jest wolne", nie „czasem się zrywa" — wisi, i to zawsze.
Jeśli kiedykolwiek zobaczysz taki układ, przestań sprawdzać routing, firewall i DNS. Warstwa trzecia działa. Coś zjada wyłącznie TCP.
tcpdump na drugim końcu tunelu domyka sprawę:
$ tcpdump -ni flannel.1 -v 'tcp port 9502'
IP (tos 0x0, ttl 64, id 41653, offset 0, flags [DF], proto TCP (6), length 60)
10.42.1.9.51234 > 10.42.2.14.9502: Flags [S], cksum 0x9a1f (incorrect -> 0x3d7c), seq 998...
cksum 0x9a1f (incorrect). Pakiet dociera. Ma poprawny adres, poprawny port,
poprawną flagę SYN. I ma zepsutą sumę kontrolną, więc jądro po drugiej stronie
wyrzuca go do kosza bez słowa. Nadawca nie dostaje odpowiedzi, więc retransmituje.
Odbiorca kasuje kolejny egzemplarz. I tak w kółko, aż do końca świata albo do timeoutu.
ICMP przechodzi, bo jego suma kontrolna liczona jest gdzie indziej i nikt jej nie dotyka.
Dlaczego suma jest zła
Współczesne karty sieciowe liczą sumy kontrolne same — to się nazywa checksum offload i oszczędza procesorowi roboty. Jądro nie liczy niczego, tylko zostawia w nagłówku placeholder i mówi karcie: „dolicz ty".
Przy VXLAN robi się z tego problem. Pakiet jest opakowany: prawdziwy nagłówek TCP ląduje w środku pakietu UDP, który dopiero leci przez fizyczną sieć. Karta musi zrozumieć, że wewnątrz UDP siedzi kolejny nagłówek, znaleźć go i policzyć sumę we właściwym miejscu.
Sterownik vmxnet3 tego nie robi poprawnie. Liczy sumę tak, jakby enkapsulacji nie było —
i wpisuje ją nie tam, gdzie trzeba. Efekt: pakiet wychodzi z hosta z sumą, która się nie zgadza,
i jest kasowany po drugiej stronie.
To nie jest błąd flannela. To nie jest błąd Longhorna. Longhorn był tylko pierwszą aplikacją, która potrzebowała TCP między węzłami — i dlatego to on się wysypał jako pierwszy. Zaraz za nim poszedł webhook MetalLB, potem External Secrets. Trzy różne komunikaty błędu, trzy różne namespace'y, jedna przyczyna cztery warstwy niżej.
Poprawka
ethtool -K flannel.1 tx-checksum-ip-generic off
Skutek natychmiastowy: pody wstają, webhooki odpowiadają, csi-resizer powstaje sam z siebie.
Tylko że to nie przeżywa restartu. Gorzej — flannel.1 w ogóle nie istnieje przed startem k3s,
bo to on tworzy ten interfejs. Więc nie da się tego wrzucić do przygotowania systemu,
przed instalacją klastra: skrypt nie znajdzie interfejsu i wyjdzie, nic nie robiąc.
Straciłem na tym godzinę, wpisując poprawkę w niewłaściwe miejsce i dziwiąc się,
że działa na jednym węźle, a na dwóch pozostałych nie.
Poprawka musi wejść po starcie k3s. Jednostka systemd z After=k3s.service
plus wywołanie skryptu zaraz po instalacji węzła.
Czego nie robić: wyłączać na ślepo
Tu jest druga część roboty, ważniejsza od samej linijki.
Kusi, żeby po prostu wywalić offload wszędzie i mieć spokój. Nie rób tego. Na fizycznym sprzęcie ten problem nie występuje, a offload realnie odciąża procesor — przy ruchu rzędu gigabitów mówimy o pojedynczych procentach CPU na węzeł, które oddajesz za darmo w zamian za naprawę czegoś, co u ciebie nie jest zepsute. Lab jedzie na wirtualkach, ale produkcja stoi na blasze i tam wyłączanie offloadu jest czystą stratą.
Więc poprawka sama sprawdza, czy jest potrzebna, i robi to dwutorowo. Najpierw po sterowniku uplinku i hipernadzorcy:
UPLINK=$(ip -o -4 route show to default | awk '{print $5}' | head -1)
DRIVER=$(ethtool -i "$UPLINK" | awk '/^driver:/{print $2}')
VIRT=$(systemd-detect-virt || echo none)
case "$DRIVER" in
vmxnet3|e1000|e1000e) NEED=1 ;;
esac
[ "$NEED" = "0" ] && [ "$VIRT" = "vmware" ] && NEED=1
A potem — i to jest część, która ratuje tyłek w setupach, których nikt nie przewidział — empirycznie, po tym, czy tunel faktycznie gubi pakiety:
tx_err() { ip -s link show flannel.1 | awk '/TX:/{getline; print $3}'; }
E1=$(tx_err); sleep 20; E2=$(tx_err)
[ "$E2" -gt "$E1" ] && NEED=1
Lista sterowników zawsze będzie niepełna. Rosnący licznik błędów TX nie kłamie i nie wymaga, żeby ktoś wcześniej wpisał twój sprzęt na listę.
Co z tego zostaje
Komunikat błędu opisuje warstwę, na której się przewróciło, a nie tę, na której leży przyczyna.
csi-resizer not found to była prawda — deployment faktycznie nie istniał.
Prawda kompletnie bezużyteczna, oddalona o cztery warstwy od tego, co się naprawdę stało.
ICMP nie jest testem sieci. „Ping chodzi, więc sieć działa" to zdanie, które kosztowało mnie
kilka godzin. Ping sprawdza, czy pakiet dojdzie. Nie sprawdza, czy dojdzie w stanie nadającym się do użycia.
Jak następnym razem usłyszysz „przecież się pinguje", zapytaj o curl.
Poprawka, która wymaga pamiętania, nie jest poprawką. Ta linijka działa natychmiast i znika po restarcie. Dopóki nie siedzi w automacie stawiającym klaster, jest tylko ładną anegdotą — a następna osoba (albo ty za pół roku) przejdzie tę samą drogę od nowa, przez te same cztery fałszywe tropy.
Poprawka warunkowa bije poprawkę uniwersalną. „Wyłącz wszędzie, bo raz zabolało" to jak leczenie bólu głowy gilotyną. Skoro maszyna potrafi sprawdzić, czy jest chora, niech sprawdza.
I na koniec to, co bolało najbardziej: cztery fałszywe tropy nie były głupie. Każdy z nich był sensowną hipotezą, każdy prowadził do prawdziwego wniosku o systemie, a dwa z nich zostawiły poprawki, które i tak były potrzebne. Problem polegał na tym, że żaden nie był tą przyczyną — a kolejność sprawdzania wynikała z tego, co było najłatwiejsze do sprawdzenia, a nie z tego, co najbardziej prawdopodobne.
Następnym razem zaczynam od tcpdump.