K8s Metal LB Service Trafic Flow

Материал из noname.com.ua
Версия от 09:34, 26 сентября 2025; Sirmax (обсуждение | вклад)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к навигацииПерейти к поиску


K8s Metal LB Service Trafic Flow

Заметка о пути трафика с MetalLB
Заметка появилась в процессе расследования почему на сервис можно ходить с некоторых адресов, а с других нельзя.
Для определнности "проблемный" сервис iam-proxy-alertmanager
"Проблемный" взят в кавычки так как не ясно в сервисе ли дело или в чем-то другом

Найти с какой ноды анонсируется адрес

Если повезло

Если события логгируются то можно достать из логов
OpenSearch MetalLB 250925155617.png
К сожалению этот простой путь доступен не всегда

Описание сервиса

kubectl -n stacklight get svc  iam-proxy-alertmanager
NAME                     TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)         AGE
iam-proxy-alertmanager   LoadBalancer   10.232.100.189   10.80.8.102   443:30358/TCP   42d

Тут виден внешний адрес сервиса - 10.80.8.102

Поиск адреса в логах

Посмотреть все логи по всем подам можно например так:

kubectl -n metallb-system  logs daemonset/mcc-metallb-speaker --prefix

Icon-caution.gif

Обращать внимание на сообщения вроде

Found 3 pods, using pod/mcc-metallb-speaker-8k5wl

Если такое есть - то логи не полные и нужно смотреть по метке

Icon-caution.gif

Можно и нужно искать и по метке, а не только по принадлежности к daemonset

kubectl -n metallb-system  logs   -l "app.kubernetes.io/component"="speaker" --prefix

Icon-caution.gif

Не забывать что логи могут выводится не все
Правильно, что б найти то что нужно не забывать про

  • --prefix что бы видеть имя пода и контейнера
  • --since=24h время, что бы не выгребать вообще все логи, когда они не нужны
  • --tail=-1 показать все логи. Это важно так как часто k8s решает показать только часть, я не исследовал причин и настроек этого поведения
  • --timestamps обычно хочется меток времени (их может и не быть в логах приложения и по ним можно сортировать)
  • LC_ALL=C sort -k2,2 если хоется сортировку по времени а не по подам (обычно хочется)

Финальный запрос

kubectl childctl -n metallb-system  logs -l app.kubernetes.io/component=speaker  --prefix --since=5h --tail=-1 --timestamps  | LC_ALL=C sort -k2,2 | grep '10.80.8.102'
[pod/mcc-metallb-speaker-8k5wl/speaker] 2025-09-25T10:24:15.767871702Z {"caller":"main.go:409","event":"serviceAnnounced","ips":["10.80.8.102"],"level":"info","msg":"service has IP, announcing","pool":"default","protocol":"layer2","ts":"2025-09-25T10:24:15Z"}
[pod/mcc-metallb-speaker-8k5wl/speaker] 2025-09-25T10:26:10.381353840Z {"caller":"main.go:453","event":"serviceWithdrawn","ip":["10.80.8.102"],"ips":["10.80.8.102"],"level":"info","msg":"withdrawing service announcement","pool":"default","protocol":"layer2","reason":"notOwner","ts":"2025-09-25T10:26:10Z"}
[pod/mcc-metallb-speaker-hgksn/speaker] 2025-09-25T10:26:10.458269685Z {"caller":"main.go:409","event":"serviceAnnounced","ips":["10.80.8.102"],"level":"info","msg":"service has IP, announcing","pool":"default","protocol":"layer2","ts":"2025-09-25T10:26:10Z"}
[pod/mcc-metallb-speaker-hgksn/speaker] 2025-09-25T10:26:10.535686056Z {"caller":"main.go:409","event":"serviceAnnounced","ips":["10.80.8.102"],"level":"info","msg":"service has IP, announcing","pool":"default","protocol":"layer2","ts":"2025-09-25T10:26:10Z"}
root@nest:~/MOSK/CURRENT/003-K8S-Control-Machines-Objects#

Из этого лога можно понять какой POD анонсировал адрес

  • Сначала это был pod/mcc-metallb-speaker-8k5wl/speaker
  • Потом он прекратил обслуживание этого сервиса serviceWithdrawn notOwner
  • Сервис теперь анонсируется с mcc-metallb-speaker-hgksn


Получение адреса ноды


Зная имя POD можно получить ноду (k8s-control-3):

kubectl -n metallb-system get pod/mcc-metallb-speaker-hgksn -o wide
NAME                        READY   STATUS    RESTARTS   AGE    IP           NODE            NOMINATED NODE   READINESS GATES
mcc-metallb-speaker-hgksn   1/1     Running   0          102m   10.80.3.13   k8s-control-3   <none>           <none>

Путь прохождени трафика

Трафик на ноде

Тут мы уже знаем на какую ноду (k8s-control-3) прийдет запрос и можем на ней запустить tcpdump и для теста "дернуть" сервис curl https://10.80.8.102 -I -k

root@k8s-control-3:~# tcpdump  -n -i any  host 10.80.8.102
...
12:12:44.576113 mlb   In  IP 192.168.22.253.52582 > 10.80.8.102.443: Flags [S], seq 3953098481, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1301733900 ecr 0,sackOK,eol], length 0
12:12:44.577625 mlb   Out IP 10.80.8.102.443 > 192.168.22.253.52582: Flags [S.], seq 1124290493, ack 3953098482, win 64308, options [mss 1410,sackOK,TS val 3194506911 ecr 1301733900,nop,wscale 7], length 0
12:12:44.579051 mlb   In  IP 192.168.22.253.52582 > 10.80.8.102.443: Flags [.], ack 1, win 2053, options [nop,nop,TS val 1301733903 ecr 3194506911], length 0
12:12:44.579593 mlb   In  IP 192.168.22.253.52582 > 10.80.8.102.443: Flags [P.], seq 1:302, ack 1, win 2053, options [nop,nop,TS val 1301733903 ecr 3194506911], length 301
...

192.168.22.253 адрес хоста откуда запускался curl https://10.80.8.102 -I -k 10.80.8.102 адрес сервиса

Разбор сервиса

Для того что бы проследить дальнейший путь трафика нужно подробно разобрать сервис

kubectl  -n stacklight get svc iam-proxy-alertmanager  -o yaml

selector

Селектор определяет на какие поды будет направлен трафик

 selector:
    app.kubernetes.io/instance: iam-proxy-alertmanager
    app.kubernetes.io/name: iam-proxy

Их можно найти командой

kubectl get pod -A -l app.kubernetes.io/name=iam-proxy,app.kubernetes.io/instance=iam-proxy-alertmanager -o wide
NAMESPACE    NAME                                     READY   STATUS    RESTARTS   AGE   IP                NODE           NOMINATED NODE   READINESS GATES
stacklight   iam-proxy-alertmanager-76997d95b-d9czm   1/1     Running   0          42d   192.168.105.143   stacklight-1   <none>           <none>
stacklight   iam-proxy-alertmanager-76997d95b-mqd2f   1/1     Running   0          42d   192.168.104.66    stacklight-3   <none>           <none>

Icon-caution.gif

  • ключ -A оставлен намеренно что б показать что поиск по меткам работает сразу во всех namespace

Тут видно что трафик будет направлен на 2 пода с адресами

  • 192.168.105.143
  • 192.168.104.66

Что можно проверить используя tcpdump

tcpdump  -n -i any  host 192.168.105.143 or host 192.168.104.66

Вывод сокращен, до нескольких пакетов что бы показать что трафик идет поочередно на один или второй POD

12:26:50.893669 vxlan.calico Out IP 192.168.106.0.36057 > 192.168.105.143.4180: Flags [S], seq 2888292147, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 976299430 ecr 0,sackOK,eol], length 0
12:26:50.894698 vxlan.calico In  IP 192.168.105.143.4180 > 192.168.106.0.36057: Flags [S.], seq 1236287622, ack 2888292148, win 64308, options [mss 1410,sackOK,TS val 3195353228 ecr 976299430,nop,wscale 7], length 0
12:26:50.896305 vxlan.calico Out IP 192.168.106.0.36057 > 192.168.105.143.4180: Flags [.], ack 1, win 2053, options [nop,nop,TS val 976299433 ecr 3195353228], length 0
12:26:50.896972 vxlan.calico Out IP 192.168.106.0.36057 > 192.168.105.143.4180: Flags [P.], seq 1:302, ack 1, win 2053, options [nop,nop,TS val 976299433 ecr 3195353228], length 301
...
12:27:00.868844 vxlan.calico In  IP 192.168.104.66.4180 > 192.168.106.0.22319: Flags [S.], seq 2502063474, ack 1294456302, win 64308, options [mss 1410,sackOK,TS val 931778658 ecr 3753725410,nop,wscale 7], length 0
12:27:00.881856 vxlan.calico Out IP 192.168.106.0.22319 > 192.168.104.66.4180: Flags [.], ack 1, win 2053, options [nop,nop,TS val 3753725424 ecr 931778658], length 0
12:27:00.882748 vxlan.calico Out IP 192.168.106.0.22319 > 192.168.104.66.4180: Flags [P.], seq 1:302, ack 1, win 2053, options [nop,nop,TS val 3753725424 ecr 931778658], length 301
...

Вопросом доставки трафика до пода далее занимается Calico и обзор прохождения трафика через VxLAN сейчас не важен (что то есть тут: Calico_Kubernetes_the_hard_way_v2_How_packet_goes_from_pod)
В данный момент важно то что видны запросы и ответы

sessionAffinity: None

sessionAffinity: None

Такая настройка означает RoundRobin

ports

  - name: https
    nodePort: 30358
    port: 443
    protocol: TCP
    targetPort: https

тут кажется что трафик должен идти на 443 порт (но дамп выше это не подтверждает - там порт 4180)

На самом деле https тут это ИМЯ порта в поде

targetPort: https

Что можно проверить:

kubectl get pod -A -l app.kubernetes.io/name=iam-proxy,app.kubernetes.io/instance=iam-proxy-alertmanager -o yaml \
    | yq '.items[].spec.containers[].ports'
- containerPort: 4180
  name: https
  protocol: TCP
- containerPort: 4180
  name: https
  protocol: TCP
  • name: https соответвует containerPort: 4180 и совпадает с тем что видно в tcpdump:
192.168.106.0.36057 > 192.168.105.143.4180

Трафик в POD

Для этого для обоих подов действия (пример 192.168.104.66 на ноде stacklight-3)
Для начала определить контейнер - но сделать это может быть сложно
по тому заходим в под и запускаем там top (процессов /bin/oauth2-proxy может быть несколько а top скорее всего - один, но метод косвенный)

kubectl  -n stacklight  exec -ti iam-proxy-alertmanager-76997d95b-mqd2f  -- sh

top

Дальше найти PID процесса top

ps auxfw | grep top
root        8244  0.0  0.0   2788  1712 ?        S<   Aug14  38:36 /usr/sbin/atopacctd
root     1921049  0.0  0.0   7008  2200 pts/1    S+   16:10   0:00                              \_ grep --color=auto top
nobody   1920805  0.0  0.0   1596   968 pts/0    S+   16:10   0:00      \_ top
root      796509  0.8  0.0  19616 19452 ?        S<Ls 01:00   7:54 /usr/bin/atop -R -w /var/log/atop/atop_20250924 60

Интересует 1920805

nobody   1920805  0.0  0.0   1596   968 pts/0    S+   16:10   0:00      \_ top

Далее по PID провалиться в network namespace

nsenter -t 1886583 -n

Проверить что находимся внутри network namespace

ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet 192.168.104.66  netmask 255.255.255.255  broadcast 0.0.0.0
        ether fe:cd:df:e1:24:d3  txqueuelen 1000  (Ethernet)
        RX packets 12212837  bytes 1400942826 (1.4 GB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 10131352  bytes 3843343988 (3.8 GB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
  • Адрес 192.168.104.66 совпадает с тем что было в описании POD: iam-proxy-alertmanager-76997d95b-mqd2f 1/1 Running 0 41d 192.168.104.66

Далее в PODзапускать tcpdump

tcpdump  -n -i eth0
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
16:12:45.747433 IP 192.168.107.192.64528 > 192.168.104.66.4180: Flags [S], seq 1723519164, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 3632424568 ecr 0,sackOK,eol], length 0
16:12:45.747474 IP 192.168.104.66.4180 > 192.168.107.192.64528: Flags [S.], seq 3246211835, ack 1723519165, win 64308, options [mss 1410,sackOK,TS val 1325901618 ecr 3632424568,nop,wscale 7], length 0
16:12:45.749724 IP 192.168.107.192.64528 > 192.168.104.66.4180: Flags [.], ack 1, win 2053, options [nop,nop,TS val 3632424571 ecr 1325901618], length 0
16:12:45.751215 IP 192.168.107.192.64528 > 192.168.104.66.4180: Flags [P.], seq 1:302, ack 1, win 2053, options [nop,nop,TS val 3632424571 ecr 1325901618], length 301