Кубернетес для сетевых инженеров

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Оглавление:

Сетевая связность и пропускная способность

CNI и CRI

DNS, L4/L7

Захват трафика

Сетевая связность и пропускная способность

Кубернетес использует стандартное сетевое оборудование и примитивы ОС Linux в качестве фундамента для построения различных типов SND (Software-defined networking). Способы отладки сетей в Кубернетес, принципиально не отличается, от привычных методов.

iperf

https://iperf.fr

iperf – это хорошо известный для сетевых инженеров и системных администраторов инструмент,
предназначенный для тестирования сетевого оборудования пропускной способности сетевых каналов.
Также как и обычными хостами Linux, его можно использовать для тестирования сетей в кластере Кубернетес.
Для того, чтобы развернуть iperf в Кубернетес необходимо создать манифест развертывания использующий нужный образ:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: iperf3-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: iperf3
  template:
    metadata:
      labels:
        app: iperf3
    spec:
      containers:
      - name: iperf3
        image: leodotcloud/swiss-army-knife
        ports:
        - containerPort: 5201

Для того, чтобы развернуть созданный манифест в кластере:

kubectl apply -f iperf3-deployment.yaml

Планируемый результат:

~$ kubectl get pods -o wide
NAME                                 READY   STATUS    RESTARTS   AGE     IP            NODE       NOMINATED NODE   READINESS GATES
iperf3-deployment-64c767596d-9r4jm   1/1     Running   0          3h36m   10.244.0.13   minikube   <none>           <none>
iperf3-deployment-64c767596d-jgqx9   1/1     Running   0          3h36m   10.244.0.14   minikube   <none>           <none>
iperf3-deployment-64c767596d-l5tg8   1/1     Running   0          3h36m   10.244.0.15   minikube   <none>           <none>

Сначала нужно запустить iperf в одном из подов, в режиме сервера:

kubectl exec -it <pod-name> -- iperf3 -s -p 12345

В данном случае необходимо поменять [pod-name] на имя одного из подов в развертывании:
kubectl exec -it [pod-name] -- iperf3 -s -p 12345

Планируемый результат:

~$ kubectl exec -it pod/iperf3-deployment-64c767596d-l5tg8 -- iperf3 -s -p 12345
-----------------------------------------------------------
Server listening on 12345
-----------------------------------------------------------

В другой сессии терминала нужно запустить Iperf в режиме клиента, и подключится из этого пода к серверу:

~$ kubectl exec -it iperf3-deployment-64c767596d-9r4jm -- iperf3 -c 10.244.0.15 -p 12345
Connecting to host 10.244.0.15, port 12345
[  4] local 10.244.0.13 port 43842 connected to 10.244.0.15 port 12345
[ ID] Interval           Transfer     Bandwidth       Retr  Cwnd
[  4]   0.00-1.00   sec  2.78 GBytes  23.9 Gbits/sec  1296506932   0.00 Bytes
[  4]   1.00-2.00   sec  2.56 GBytes  22.0 Gbits/sec    0   0.00 Bytes
[  4]   2.00-3.00   sec  3.02 GBytes  25.9 Gbits/sec    0   0.00 Bytes
[  4]   3.00-4.00   sec  3.17 GBytes  27.2 Gbits/sec    0   0.00 Bytes
[  4]   4.00-5.00   sec  2.91 GBytes  25.0 Gbits/sec    0   0.00 Bytes
[  4]   5.00-6.00   sec  2.76 GBytes  23.7 Gbits/sec    0   0.00 Bytes
[  4]   6.00-7.00   sec  2.47 GBytes  21.2 Gbits/sec    0   0.00 Bytes
[  4]   7.00-8.00   sec  2.43 GBytes  20.9 Gbits/sec    0   0.00 Bytes
[  4]   8.00-9.00   sec  2.43 GBytes  20.9 Gbits/sec    0   0.00 Bytes
[  4]   9.00-10.00  sec  2.82 GBytes  24.2 Gbits/sec  2998460368   0.00 Bytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth       Retr
[  4]   0.00-10.00  sec  27.3 GBytes  23.5 Gbits/sec    4             sender
[  4]   0.00-10.00  sec  27.3 GBytes  23.5 Gbits/sec                  receiver

Основное предназначение iperf - это анализ пропускной способности сети: между географически удаленными узлами в одном кластере Кубернетес
или между хостом внутри кластера и машиной которая находится за его пределами.

Iperf может тестировать не только TCP но и UDP:

~$ kubectl exec -it iperf3-deployment-64c767596d-9r4jm -- iperf3 -c 10.244.0.15 -u -p 12345
Connecting to host 10.244.0.15, port 12345
warning: Unable to set socket pacing, using application pacing instead
[  4] local 10.244.0.13 port 51612 connected to 10.244.0.15 port 12345
[ ID] Interval           Transfer     Bandwidth       Total Datagrams
[  4]   0.00-1.00   sec   120 KBytes   983 Kbits/sec  15
[  4]   1.00-2.00   sec   128 KBytes  1.05 Mbits/sec  16
[  4]   2.00-3.00   sec   128 KBytes  1.05 Mbits/sec  16
[  4]   3.00-4.00   sec   128 KBytes  1.05 Mbits/sec  16
[  4]   4.00-5.00   sec   128 KBytes  1.05 Mbits/sec  16
[  4]   5.00-6.00   sec   128 KBytes  1.05 Mbits/sec  16
[  4]   6.00-7.00   sec   128 KBytes  1.05 Mbits/sec  16
[  4]   7.00-8.00   sec   128 KBytes  1.05 Mbits/sec  16
[  4]   8.00-9.00   sec   128 KBytes  1.05 Mbits/sec  16
[  4]   9.00-10.00  sec   128 KBytes  1.05 Mbits/sec  16
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth       Jitter    Lost/Total Datagrams
[  4]   0.00-10.00  sec  1.24 MBytes  1.04 Mbits/sec  0.207 ms  0/159 (0%)
[  4] Sent 159 datagrams

В случаи если при тестировании наблюдаются потери пакетов, то это может говорить о:

  • Неисправности "железа" (CRC ошибки NIC проблемы с коммутаторами)

  • Не правильно настроенный межсетевой экран

  • Не правильно настроенный протокол (например MTU)

  • Link congestion

CNI и CRI

Кубернетес построен на принципах UNIX: Делайте что-то одно, но делайте это хорошо. Каждый компонент Кубернетес – это отдельная программа, которая выполняет определенный набор операций и не имеет жесткой привязки (decoupling) к другим компонентам.

CRI

Кубернетес занимается оркестрацией контейнеров, но за работу непостредственно связаной с запуском и остановкой контейнеров на узлах кластера отвечает другой компонент – CRI (Container Runtime Interface). CRI использует примитивы Linux (cgroups и пространства имен) для работы с образами контейнеров. Kubelet – это компонент Кубернтес, который управляет Container Runtime.

CRI (это может быть Docker\containerd) отвечает за запуск контейнеров. Kubelet отправляет инструкции CNI, как присоединить сетевой интерфейс и настроить сеть для Пода.
CRI (это может быть Docker\containerd) отвечает за запуск контейнеров. Kubelet отправляет инструкции CNI, как присоединить сетевой интерфейс и настроить сеть для Пода.

Для того, чтобы быстро посмотреть какие с какими параметрами был запущен сервис kubelet можно использовать команду strings /proc/$(pgrep kubelet)/cmdline:

$ strings /proc/$(pgrep kubelet)/cmdline
/usr/bin/kubelet
--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf
--kubeconfig=/etc/kubernetes/kubelet.conf
--config=/var/lib/kubelet/config.yaml
--container-runtime=remote
--container-runtime-endpoint=/run/containerd/containerd.sock
--node-ip=192.168.61.11
--pod-infra-container-image=k8s.gcr.io/pause:3.4.1

Для отладки проблем связанных с сетевым доступом на узлах Кубернетес, можно использовать бинарные файлы CRI (Container Runtime Interface).
crio:
https://github.com/cri-o/cri-o/blob/main/docs/crio.8.md

$ crictl pull docker.io/library/busybox:latest

containerd:
https://github.com/projectatomic/containerd/blob/master/docs/cli.md

$ ctr images pull docker.io/library/busybox:latest

crictl inspect выводит информацию о контейнере в формате JSON. Можно использовать утилиту jq для того, чтобы отфильтровать PID:

crictl ps
crictl inspect $CONTAINER_ID
PID=$(crictl inspect $CONTAINER_ID | jq '.info.pid')
ps -ef | grep $PID | grep -v grep

CNI

У CNI плагина есть две главные обязанности: аллоцировать и назаначять уникальные IP адреса для Подов и добавлять маршруты в кластере Кубернетес для каждого IP адреса Пода.
Это означает, что сеть в которой находится узлы кластера, диктует поведение CNI плагина. Существует два категории в сетевой модели CNI: flat networks и overlay networks. flat networks использует IP из сети кластера, для чего обычно требуется большое количество свободных адресов. В сетях overlay, драйвер CNI создает свою сеть в Кубернетес, и затем использует кластерную сеть (которая называется ]underlay network]) для передачи пакетов.

Пример вывода команды ip route на узле кластера использующего CNI плагин Calico:

$ ip route
default via 10.6.16.1 dev eth0 
10.6.16.0/21 dev eth0 proto kernel scope link src 10.6.22.111 
111.97.95.0/26 via 10.6.145.224 dev tunl0 proto bird onlink 
111.98.108.64/26 via 10.6.144.128 dev tunl0 proto bird onlink 
111.98.163.0/26 via 10.6.147.100 dev tunl0 proto bird onlink 
111.101.172.128/26 via 10.6.86.141 dev tunl0 proto bird onlink 
111.103.57.192/26 via 10.6.17.44 dev eth0 proto bird 
111.103.80.128/26 via 10.6.85.178 dev tunl0 proto bird onlink 
111.105.231.0/26 via 10.6.23.120 dev eth0 proto bird 
111.115.208.128/26 via 10.6.80.11 dev tunl0 proto bird onlink 
blackhole 111.126.117.128/26 proto bird 
111.126.117.129 dev cali8934275ty scope link 
111.126.117.132 dev cali983hfsdf4 scope link 
111.126.117.140 dev cali443gfby45 scope link

kubelet подключает Поды к CNI. Сетевой трафик CNI предстваляет из себя стандартный TCP/IP (здесь могут быть особенности реализации конкертного плагина CNI). Шифрованием трафика занимается CNI, приложение или service mesh. Если трафик передается в незашифрованном виде, то его можно прослушивать из скомпрометированного Пода или непостредственно на узле Кубернетес.

По-умолчанию kubelet читает конифиг CNI из директории /etc/cni/net.d/ и ожидает найти бинарный файл CNI в директории /opt/cni/bin/.
Эти параметры может использовать в командной строки с помощью фалгов --cni-config-dir=[directory] и --cni-bin-dir=[directory].

Cilium

Cilium - это одна из реализаций CNI. Это первый плагин использующий Berkeley Packet Filter (eBPF). Это означает, что обработка сетевых пакетов происходит в ядре (Linux kernel space). При использовании вместе с технологией Xpress Data Path (XDP), это позволяет маршрутизировать трафик сразу после передачи сетевых пакетов. Cilium имеет ряд преимуществ по сравнению с другими плагинами. При этом выбор CNI это одно из ключевых решений, которое должно приниматься на этапе планирования кластера администраторами, сетевыми инженерами и разработчиками.

NetworkPolicy

По-умолчанию Кубернетес открывает доступ для любого трафика между Подами в кластерной сети.
NetworkPolicy Это ресурс Кубернетес, который позволяет настраивать правила доступа аналогичные правилам для межсетевого экрана.
Ресурсы NetworkPolicy используется используются для конфигурации плагинов CNI – это компонент который отвечает за сетевую связность между Подами.

Iptables

Большинство имплементаций CNI используют kube-proxy и iptables для фильтрации сетевых пакетов. Исключением является Cilium и другие плагины использующие eBPF.

Некоторые компоненты Кубернетес (kube-proxy) создают правила iptables для выполнения определенных операций. Пример таких правил можно увидеть, выполнив команду на узле в кластере Кубернетес:

$ sudo iptables -t nat -L KUBE-SERVICES

Эти правила предназначены для внутреннего использования в Кубернетес. Они создаются автоматически и не предназначены для редактирования пользователями.

DNS, L4/L7

По-умолчанию Кубернетес автоматически настраивает DNS сервис, который используется для обнаружения сервисов в кластере. Кубернетес это динамическая инфраструктура: Поды и контейнеры создаются, удаляются и перемещаются между узлами кластера в автоматическом режиме. Встроенное обнаружение сервисов необходимо для коммуникации между приложениями в условиях динамической инфраструктуры: кубернетес постоянно создает, удаляет и перемещает Поды и контейнеры между узлами кластера в автоматическом режиме.

CoreDNS

https://kubernetes.io/docs/tasks/administer-cluster/dns-debugging-resolution

Кубернетес использует CoreDNS в качестве внутрикластерного DNS сервера для Подов.

CoreDNS отслеживает состояние ресурсов API Сервера. Для каждого Сервиса Кубернетес CoreDNS создает запись следующего формата: [service-name].[namespace-name].svc.cluster.local.
К примеру Сервис, который называется nginx в пространстве имен default, получит запись - nginx.default.svc.cluster.local.

Во время выполнения процедуры запуска Подов, kubelet сохраняет в контейнере файл /etc/resolv.conf. Если изучить содержимое этого файла, то в качестве nameserver там будет указан CoreDNS. Каждый раз когда Под запрашивает Сервис Кубернетес по имени - этот запрос отправляется в CoreDNS:

cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5

Сервис kube-dns подключается к развертыванию (Deployment) CoreDNS:

kubectl -n kube-system get services
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   2d3h

Сервис kube-dns не имеет отношения к легковесной реализации DNS сервера, которая устанавливалась по-умолчанию в предыдущих версиях Кубернетес. Сервис kube-dns является частью CoreDNS и устанавливается на этапе установки кластера.

  • CoreDNS настраивается с помощью плагинов.

  • CoreDNS использует так называемый Corefile для того, чтобы конфигурировать поведение DNS сервера.

  • Конфиг CoreDNS нужно читать сверху вниз - каждая новая строчка это один из используемых плагинов.

  • Для того, чтобы изучить конфигурацию CoreDNS можно воспользоваться следующей командой:

kubectl get configmaps coredns -n kube-system -o yaml

dnstools

Для отладки сетей в Кубернетес, зачастую не хватает привычных для сетевых инженеров и системных администраторов инструментов: dig, nslookup, curl, ping, nc и так далее. Для того, чтобы получить доступ к этим необходимым инструментам, можно собрать служебный образ контейнера с набором предустановленных программ, или использовать один из существующих публично доступных образов Docker, например - dnstools:
dnstools.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: dnstools
spec:
  containers:
  - name: dnstools
    image: infoblox/dnstools
    command: ['sh', '-c', 'while true; do sleep 1; done']

Для того, чтобы развернуть созданный манифест в кластере:

kubectl apply -f dnstools.yaml

Планируемый результат:

kubectl get pods dnstools
NAME       READY   STATUS    RESTARTS   AGE
dnsutils   1/1     Running   0          36s

С помощью dnstools можно проверить L4\L7 соединение между Подами, порты и доступ в Интернет из кластера:

~$ kubectl exec -i -t dnstools -- nc -z -vv 10.244.0.6 80
nc: 10.244.0.6 (10.244.0.6:80): Connection refused
sent 0, rcvd 0
command terminated with exit code 1

~$ kubectl exec -i -t dnstools -- nc -z -vv 10.244.0.6 8080
10.244.0.6 (10.244.0.6:8080) open
sent 0, rcvd 0

~$ kubectl exec -i -t dnstools -- ping google.com -c 4
PING google.com (64.233.165.100): 56 data bytes
64 bytes from 64.233.165.100: seq=0 ttl=36 time=200.956 ms
64 bytes from 64.233.165.100: seq=1 ttl=36 time=18.517 ms
64 bytes from 64.233.165.100: seq=2 ttl=36 time=31.825 ms
64 bytes from 64.233.165.100: seq=3 ttl=36 time=16.783 ms

layer 7 HTTP API:

~$ kubectl exec -i -t dnstools -- wget -qO- 10.244.0.6:8080
Hello, world!

Проверить разрешение доменных имен в кластере:

$ kubectl exec -i -t dnstools -- nslookup kubernetes.default
Server:		10.96.0.10
Address:	10.96.0.10#53

Name:	kubernetes.default.svc.cluster.local
Address: 10.96.0.1

$ kubectl exec -i -t dnstools -- dig hello-world.default.svc.cluster.example.com

Для того, чтобы быстро получить доступ к контейнеру с dnstools:

kubectl run --restart=Never -it --image infoblox/dnstools dnstools dnstools#

Сделать снимок сетевого трафика DNS (UDP 53) в контейнере dnstools:

kubectl exec -it dnstools sh
dnstools# tcpdump -ni eth0 udp and port 53

В случае проблем с DNS в кластере Кубернетес, сначала следует проверить содержимое /etc/resolv.conf:

dnstools# cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

https://linux.die.net/man/5/resolv.conf

Захват трафика

Wireshark и tcpdump – являются де-факто стандартными инструментами в арсенале сетевого инженера и хотя контейнеры значительно меняют подход к проектированию и отладки сетей, эти две не заменимые программы можно использовать для анализа сетевого трафика в Кубернетес.

tcpdump собирает данные между интерфейсом драйвера сетевой карты (NIC) и вторым уровнем (layer 2) OSI
tcpdump собирает данные между интерфейсом драйвера сетевой карты (NIC) и вторым уровнем (layer 2) OSI

ksniff

https://github.com/eldadru/ksniff

ksniff - это плагин kubectl, который использует tcpdump для захвата сетевого трафика.
Трафик в формате PCAP можно затем импортировать в Wireshark для последующего анализа.

Для установки ksniff лучше использовать krew - менеджер плагинов для kubectl:

kubectl krew install sniff

Инструкции по установке krew для разных ОС:
https://krew.sigs.k8s.io/docs/user-guide/setup/install

Ksniff устанавливается на пользовательской машине с настроенным kubectl.
При запуске ksniff использует эфемерный контейнер с tcpdump для подключения к нужному Поду. Для работы с PCAP файлами, на машине должен быть установлен Wireshark.

Интерфейс кsniff достаточно прост:

kubectl sniff <POD_NAME> [-n <NAMESPACE_NAME>] [-c <CONTAINER_NAME>] [-i <INTERFACE_NAME>] [-f <CAPTURE_FILTER>] [-o OUTPUT_FILE] [-l LOCAL_TCPDUMP_FILE] [-r REMOTE_TCPDUMP_FILE]

Следующая команда сохранит перехваченные tcpdump сететвые пакеты в файл out.pcap:

kubectl sniff -n <NAMESPACE> <POD_NAME> -p -f "port 80" -o out.pcap

В данном случае мы отправляем tcpdump инструкции - отслеживать только запросы POST протокола HTTP на порту 8080:

kubectl sniff -p <POD_NAME> -n <NAMESPACE> -f 'tcp dst port 8080 and (tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504f5354)' -o - | tshark -r -

С помощью флагов --image и --tcpdump-image можно указывать кастомизированные образы Docker. Эта функция может быть использована для работы в закрытом контуре.

Kubeshark

https://docs.kubeshark.co

Инструкции по установке:
https://docs.kubeshark.co/en/install

Это развитие идей, которые были апробированы в ksniff. Принцип работы похож на ksniff – для захвата трафика используется контейнер с tcpdump.
Кроме этого Kubeshark добавляет графический веб-интерфейс и ряд возможностей, которые доступены лишь в системах для анализа трафика класса enterprise.

kubeshark позволяет:

  • добавлять кастомизированные пользовательские функции и триггеры написанные на Javascript. Это необходимо для отслеживания и реагирования на инциденты и подозрительное поведение в сети Кубернетес.

  • cохранять снимок сетевого трафика в формате PCAP для последующего импорта в Wireshark.

С kubeshark можно в режиме реального времени отслеживать перемещение трафика (REST, gRPC, Kafka, AMQP и Redis) в кластере,
и визуализировать связи между Сервисами Кубернетес - https://docs.kubeshark.co/en/service_map

Источник: https://habr.com/ru/articles/741246/


Интересные статьи

Интересные статьи

9 мая 2023 года компания Microsoft выпустила обновление KB5026372, предназначенное для Windows 11. В результате установки данного пакета у большого количества пользователей наблюдаются проблемы в ра...
На связи Саша Хрущев, технический директор IT-компании WINFOX. Недавно мы сделали кроссплатформенное приложение для прикладных инженеров крупной компании на самом современном фреймворке от Google. Поч...
Это первая из трех частей, описывающих развитие процесса обучения инженеров АСУТП. Целью всех трех статей является попытка осмыслить подготовку инженеров АСУТП в ВУЗе (какая была, и какая есть сейчас)...
В связи со сложившейся мировой обстановкой, иностранные производители межсетевых экранов ушли с российского рынка, а использование уже эксплуатируемых остается под вопросом. Если вы тот самый специали...
Продолжение подборки историй из интернета о том, как у багов иногда бывают совершенно невероятные проявления. Первая часть тут. Читать дальше →