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

в 12:53, , рубрики: devops, kubernetes, linux

Оглавление:

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

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 (это может быть Dockercontainerd) отвечает за запуск контейнеров. Kubelet отправляет инструкции CNI, как присоединить сетевой интерфейс и настроить сеть для Пода.

CRI (это может быть Dockercontainerd) отвечает за запуск контейнеров. 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 можно проверить L4L7 соединение между Подами, порты и доступ в Интернет из кластера:

~$ 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://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js