OpenVPN клиент в подах Kubernetes

Вопрос или проблема

Я относительно нов в сетях и Kubernetes, но мне нужно провести нагрузочное тестирование сервера OpenVPN.

Вот что я сделал до сих пор:

Я создал образ Docker, который включает клиент OpenVPN.

Я настроил кластер Kubernetes с помощью Minikube, чтобы запустить Job, который выполняет Pods, содержащие мой образ Docker с OpenVPN.

Я использую Calico в режиме IPinIP.

Я настроил Service с NodePort.

Когда я запускаю свои Pods, я успешно устанавливаю VPN туннель. Я могу это подтвердить, потому что:

Интерфейс tun смонтирован в каждом из моих Pods.

Логи сервера и статусный файл показывают, что туннели открыты.

Однако я сталкиваюсь с проблемой: интерфейс tun0 в моих Pods фактически бесполезен. Насколько я понимаю, он неправильно маршрутизируется за пределами моего узла. Я в тупике и не могу понять, как заставить интерфейс tun0 в моих Pods подключаться внешне через Calico.

Ниже представлены некоторые команды, которые я использовал, чтобы понять свою проблему в моем поде.

Ping с использованием интерфейса tun0

module-update-job-0:/home/root# ping 8.8.8.8 -I tun0
PING 8.8.8.8 (8.8.8.8): 56 data bytes
^C
--- 8.8.8.8 ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss

Ping с использованием интерфейса eth0

module-update-job-0:/home/root# ping 8.8.8.8 -I eth0
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=113 time=10.461 ms
64 bytes from 8.8.8.8: seq=1 ttl=113 time=10.380 ms
64 bytes from 8.8.8.8: seq=2 ttl=113 time=13.003 ms
^C
--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 10.380/11.281/13.003 ms

Интерфейсы, смонтированные в моем поде

module-update-job-0:/home/root# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo       valid_lft forever preferred_lft forever    inet6 ::1/128 scope host proto kernel_lo        valid_lft forever preferred_lft forever
2: tunl0@NONE: <NOARP> mtu 1480 qdisc tbf state DOWN group default qlen 1000    link/ipip 0.0.0.0 brd 0.0.0.0
4: eth0@if42: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc tbf state UP group default qlen 1000
    link/ether 9e:39:6c:ed:65:38 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.100.81/32 scope global eth0       valid_lft forever preferred_lft forever
    inet6 fe80::9c39:6cff:feed:6538/64 scope link proto kernel_ll 
       valid_lft forever preferred_lft forever
5: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1380 qdisc tbf state UNKNOWN group default qlen 500
    link/none 
    inet 192.168.X.X peer 192.168.X.X/32 scope global tun0
       valid_lft forever preferred_lft forever
    inet6 fe80::bcc5:57a:f07e:b61a/64 scope link stable-privacy proto kernel_ll 
       valid_lft forever preferred_lft forever

Маршруты в моих подах после выполнения VPN клиента

module-update-job-0:/home/root# routes
bash: routes: command not found
module-update-job-0:/home/root# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         192.168.16.5    128.0.0.0       UG    0      0        0 tun0
default         169.254.1.1     0.0.0.0         UG    0      0        0 eth0
128.0.0.0       192.168.16.5    128.0.0.0       UG    0      0        0 tun0
169.254.1.1     *               255.255.255.255 UH    0      0        0 eth0
172.17.16.79    169.254.1.1     255.255.255.255 UGH   0      0        0 eth0
192.168.16.0    192.168.16.5    255.255.240.0   UG    0      0        0 tun0
192.168.16.5    *               255.255.255.255 UH    0      0        0 tun0

Traceroute через eth0

traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 46 byte packets
 1  192.168.49.2 (192.168.49.2)  0.006 ms  0.040 ms  0.034 ms
 2  192.168.49.1 (192.168.49.1)  0.008 ms  0.010 ms  0.007 ms
 3  192.168.200.254 (192.168.200.254)  0.528 ms  0.571 ms  0.436 ms
 4  X.X.X.X (X.X.X.X)  1.083 ms  1.115 ms  1.052 ms
 5  X.X.X.X (X.X.X.X)  2.156 ms  2.117 ms  2.109 ms
 6  X.X.X.X (X.X.X.X)  12.101 ms  11.581 ms  13.382 ms
 7  X.X.X.X (X.X.X.X)  10.640 ms  12.218 ms  12.060 ms
 8  X.X.X.X (X.X.X.X)  11.569 ms  14.146 ms  12.000 ms
 9  X.X.X.X (X.X.X.X)  10.433 ms  10.512 ms  10.330 ms
10  X.X.X.X (X.X.X.X)  10.355 ms  94.228.177.30 (94.228.177.30)  10.937 ms  11.495 ms
11  *  *  *
12  8.8.8.8 (8.8.8.8)  10.430 ms  10.304 ms  142.250.234.41 (142.250.234.41)  10.975 ms

Traceroute через tun0

module-update-job-0:/home/root# traceroute 8.8.8.8 -i tun0
traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 46 byte packets
 1  192.168.16.1 (192.168.16.1)  11.639 ms  11.637 ms  11.398 ms
 2  *  *  *
 3  *  *  *

Ниже приведено определение моей задачи Kubernetes,

Конфигурация Job

Символы ‘%’ заполняются с помощью sed в Bash-скрипте.

apiVersion: batch/v1
kind: Job
metadata:
  name: module-update-job
spec:
  completions: %COMPLETION%
  parallelism: %PARALLELISM%
  completionMode: Indexed
  template:
    metadata:
      labels:
        app: module-update-pod
      annotations:
        #k8s.v1.cni.cncf.io/networks: "direct-host-network"
        #cni.projectcalico.org/ipv4pools: "[\"192.168.100.0/24\"]"
    spec:
      containers:
      - name: module-update-conn
        image: module-update:latest
        imagePullPolicy: Never
        securityContext:
          privileged: true
          capabilities:
            add:
              - NET_ADMIN
              - NET_RAW
        tty: dev
        stdin: true
        env:
        - name: POD_ID
          valueFrom:
            fieldRef:
              fieldPath: metadata.name  # Уникальное имя пода как BOARD_ID
        - name: JOB_COMPLETION_INDEX
          valueFrom:
            fieldRef:
              fieldPath: metadata.annotations['batch.kubernetes.io/job-completion-index']
        - name: GATEWAY_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        ports:
        - containerPort: 5686
          protocol: UDP
        - containerPort: 21
          protocol: TCP  # FTP контрольный канал
        volumeMounts:
        # Индивидуальные сопоставления файлов
        - name: client-crt
          mountPath: /media/edenv/openvpn/client.crt
        - name: client-key
          mountPath: /media/edenv/openvpn/client.key
        - name: ca-crt
          mountPath: /media/edenv/openvpn/ca.crt
        - name: conf
          mountPath: /etc/openvpn/client.conf
        - name: script-down
          mountPath: /etc/openvpn/script_down.sh
        - name: scripts
          mountPath: /home/root/.
        - name: tun-device
          mountPath: /dev/net/tun
        command: [./integration_test.sh, "k8s", "%VPN_IP%", "%VPN_PORT%"]
      restartPolicy: Never
      volumes:
      # Определите пути хоста
      - name: client-crt
        hostPath:
          path: %HOME%/ed-load-testing-tools/k8s-integration-test/secret/client.crt
          type: File
      - name: client-key
        hostPath:
          path: %HOME%/ed-load-testing-tools/k8s-integration-test/secret/client.key
          type: File
      - name: ca-crt
        hostPath:
          path: %HOME%/ed-load-testing-tools/k8s-integration-test/secret/ca.crt
          type: File
      - name: conf
        hostPath:
          path: %HOME%/ed-load-testing-tools/k8s-integration-test/openvpn/client.conf
          type: File
      - name: script-down
        hostPath:
          path: %HOME%/ed-load-testing-tools/k8s-integration-test/openvpn/script_down.sh
          type: File
      - name: scripts
        hostPath:
          path: %HOME%/ed-load-testing-tools/k8s-integration-test/scripts
          type: Directory
      - name: tun-device
        hostPath:
          path: /dev/net/tun
          type: CharDevice

---
apiVersion: v1
kind: Service
metadata:
  name: module-update-service
  namespace: default
spec:
  selector:
    app: module-update-pod
  ports:
  - protocol: UDP
    name: udp
    port: 5686      # Открытый порт сервиса
    targetPort: 5686 # Порт контейнера, сопоставленный
  - protocol: TCP
    name: ftp-crtl
    port: 21         # FTP контрольный канал
    targetPort: 21
  - protocol: TCP
    name: ftp-data
    port: 5000 # Порты данных FTP в пассивном режиме
    targetPort: 5000
  type: NodePort

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-ingress-egress
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - {}
  egress:
  - {}

Ответ или решение

Подключение клиента OpenVPN к подам Kubernetes: Решение проблем с маршрутизацией

Введение

Вам необходимо выполнить нагрузочное тестирование сервера OpenVPN, используя кластеры Kubernetes, созданные с Minikube. На данный момент вы успешно настроили клиент OpenVPN внутри контейнеров, однако столкнулись с проблемой маршрутизации трафика через интерфейс tun0. Давайте подробно разберем, как правильно установить маршрутизацию для вашего клиента OpenVPN, чтобы обеспечить корректное подключение из подов Kubernetes.

Текущая ситуация

  1. Создание образа Docker: Вы успешно создали образ, содержащий клиента OpenVPN, и настроили рабочее окружение в Kubernetes.

  2. Подключение к OpenVPN: Вы смогли установить VPN-туннель, что подтверждается состоянием интерфейса tun0 и записями в логах сервера. Однако, несмотря на успешное соединение, пакеты не проходят через tun0.

  3. Различия в маршрутизации: При пинге на внешний IP-адрес (например, 8.8.8.8) через интерфейс tun0 пакеты не доходят, в отличие от eth0, где вы видите успешные ответы.

Искусственная изоляция и проблема маршрутизации

При использовании CNI Calico в режиме IP-in-IP, трафик, идущий на интерфейс tun0, может не маршрутизироваться должным образом. Поскольку tun0 – это виртуальный интерфейс, его маршрутизация по умолчанию может быть отсутствующей, что объясняет 100% потерю пакетов.

Решение проблем

1. Настройки маршрутизации

Убедитесь, что маршрут для внешних адресов конфигурирован правильно. В вашем случае это должно быть установлено следующим образом:

ip route add 0.0.0.0/1 via <VPN_GATEWAY_IP> dev tun0
ip route add 128.0.0.0/1 via <VPN_GATEWAY_IP> dev tun0

Обратите внимание, что <VPN_GATEWAY_IP> должен быть IP-адресом, предоставляемым сервером OpenVPN.

2. Применение Kubernetes NetworkPolicy

Вы создали базовую NetworkPolicy, которая разрешает все ingress и egress трафики. Убедитесь, что это не влияет на маршрутизацию. Если требуется более строгая политика, убедитесь, что разрешаются все необходимые порты и разрешен весь трафик через интерфейс tun0.

3. Использование iptables

Контейнерные сети могут требовать дополнительных правил iptables, чтобы правильно маршрутизировать трафик из tun0 на eth0. Убедитесь, что у вас есть необходимые правила, которые разрешают передачу трафика между интерфейсами. Рассмотрите возможность добавления правил, например:

iptables -A FORWARD -i tun0 -j ACCEPT
iptables -A FORWARD -o tun0 -m state --state RELATED,ESTABLISHED -j ACCEPT

4. Поддержка маршрутизации

Также стоит убедиться, что включена IP-маршрутизация в каждом из подов. Проверьте это командой:

sysctl net.ipv4.ip_forward

Если параметр не включен (0), выполните команду:

sysctl -w net.ipv4.ip_forward=1

5. Тестирование

Проведите тестирование через traceroute с интерфейса tun0, чтобы удостовериться, что маршруты настроены правильно. Это позволит визуализировать, где пакеты теряются.

traceroute -i tun0 8.8.8.8

Заключение

Проблема с туннелем tun0 связана с неправильной маршрутизацией в кластере Kubernetes. Применяя описанные шаги, вы сможете успешно настроить маршруты и обеспечить корректное функционирование вашего клиента OpenVPN в подах Kubernetes. Также помните, что правильная настройка сетей в Kubernetes может значительно повлиять на производительность и стабильность ваших приложений.

Попробуйте реализовать предложенные решения и протестировать их, чтобы выявить работоспособность вашего подключения через tun0.

Оцените материал
Добавить комментарий

Капча загружается...