Использование широковещательной рассылки UDP для обнаружения подов/пиров в Kubernetes

Мне нужно использовать широковещательную рассылку UDP для обнаружения одноранговых узлов.

Окружающая обстановка:

  • docker-desktop с кластером Kubernetes с одним узлом

Мой код выглядит следующим образом:

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MainApp {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        int inPort = Integer.parseInt(System.getenv("IN_PORT"));
        int outPort = Integer.parseInt(System.getenv("OUT_PORT"));
        String name = System.getenv("NAME");
        Client client = new Client(name, outPort);
        Server server = new Server(name, inPort);

        ExecutorService service = Executors.newFixedThreadPool(2);
        service.submit(client);
        service.submit(server).get();
    }


    static class Client implements Runnable {
        final String name;
        final int port;

        Client(String name, int port) {
            this.name = name;
            this.port = port;
        }

        @Override
        public void run() {
            System.out.println(name + " client started, port = " + port);
            try (DatagramSocket socket = new DatagramSocket()) {
                socket.setBroadcast(true);
                while (!Thread.currentThread().isInterrupted()) {
                    byte[] buffer = (name + ": hi").getBytes();

                    DatagramPacket packet = new DatagramPacket(buffer, buffer.length,
                            InetAddress.getByName("255.255.255.255"), port);
                    socket.send(packet);
                    Thread.sleep(1000);
                    System.out.println("packet sent");
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }


    static class Server implements Runnable {
        final String name;
        final int port;

        Server(String name, int port) {
            this.name = name;
            this.port = port;
        }

        @Override
        public void run() {

            System.out.println(name + " server started, port = " + port);

            try (DatagramSocket socket = new DatagramSocket(port)) {

                byte[] buf = new byte[256];
                while (!Thread.currentThread().isInterrupted()) {
                    DatagramPacket packet = new DatagramPacket(buf, buf.length);
                    socket.receive(packet);
                    String received = new String(packet.getData(), 0, packet.getLength());

                    System.out.println(String.format(name + " received '%s' from %s:%d", received,
                            packet.getAddress().toString(),
                            packet.getPort()));
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

    }

}

Настройки пода Kubernetes:

Для peer-1:

    spec:
      containers:
        - name: p2p
          image: p2p:1.0-SNAPSHOT
          env:
          - name: NAME
            value: "peer-1"
          - name: IN_PORT
            value: "9996"
          - name: OUT_PORT
            value: "9997"

Для peer-2 :

    spec:
      containers:
        - name: p2p-2
          image: p2p:1.0-SNAPSHOT
          env:
          - name: NAME
            value: "peer-2"
          - name: IN_PORT
            value: "9997"
          - name: OUT_PORT
            value: "9996"

Для простоты я использовал разные входные/выходные порты. На самом деле это должен быть тот же порт, например: 9999

Я вижу, что каждый модуль имеет уникальный IP-адрес.

kubectl get pods -o wide

NAME                                READY   STATUS    RESTARTS   AGE     IP          NODE             NOMINATED NODE   READINESS GATES
p2p-deployment-2-59bb89f9d6-ghclv   1/1     Running   0          2m26s   10.1.0.38   docker-desktop   <none>           <none>
p2p-deployment-567bb5bd77-5cnsl     1/1     Running   0          2m29s   10.1.0.37   docker-desktop   <none>           <none>

Логи от peer-1:

peer-1 received 'peer-2: hi' from /10.1.0.1:57565

Логи от peer-2:

peer-2 received 'peer-1: hi' from /10.1.0.1:44777

Вопрос: почему peer-1 получает UDP-пакеты от 10.1.0.1 вместо 10.1.0.37?

Если я войду в контейнер peer-2: kubectl exec -it p2p-deployment-2-59bb89f9d6-ghclv -- /bin/bash

потом

socat - UDP-DATAGRAM:255.255.255.255:9996,broadcast
test
test
...

в логах peer-1 вижу peer-1 received 'test' from /10.1.0.1:43144. Опять же, почему сетевой адрес 10.1.0.1 вместо 10.1.0.37.

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

Примечание: при использовании одного и того же порта для отправки/получения пакетов UDP какой-либо одноранговый узел может получить пакет со своего собственного IP-адреса. Другими словами, одноранговый узел может обнаружить только свой собственный IP-адрес, но всегда получает 10.1.0.1 для пакетов, полученных от других одноранговых узлов/модулей.


person dmgcodevil    schedule 27.12.2019    source источник
comment
Это действительно неправильный способ сделать это. Вы используете многоадресную рассылку для таких вещей. Попросите одноранговые узлы подписаться на определенную группу многоадресной рассылки. Использование многоадресной рассылки не будет прерывать работу всех остальных узлов в локальной сети (маршрутизаторы, принтеры, другие ПК и т. д.). Использование широковещания является ошибкой, и если вы его используете, вы не сможете добавить или преобразовать в IPv6, потому что в нем нет широковещания. Многоадресная рассылка предназначена только для общения с определенной группой заинтересованных хостов, которые подписаны на группу многоадресной рассылки, но широковещательная рассылка прерывает все хосты в локальной сети, независимо от того, заинтересованы они или нет.   -  person Ron Maupin    schedule 27.12.2019


Ответы (1)


По какой-то причине широковещательная рассылка UDP не работает должным образом в инфраструктуре Kubernetes, однако многоадресная рассылка работает нормально.

Спасибо Рону Мопену за предложение многоадресной рассылки.

Здесь вы можете найти код Java + конфигурацию kube

person dmgcodevil    schedule 28.12.2019