Игровые серверы K8s: динамическая пересылка TCP и UDP для модулей через сервис / вход

#nginx #kubernetes #traefik #agones

#nginx #kubernetes #traefik #agones

Вопрос:

Итак, в последние несколько дней я пытался найти способ динамического присоединения имен входа (например game-1.myapp.com ) для решения TCP и UDP для выделенных серверов Steam на Kubernetes. Я приложил следующую диаграмму о том, как я это планировал, но есть некоторые проблемы, с которыми я столкнулся.

Я могу динамически создавать пространства имен, модули (управляемые наборами с отслеживанием состояния), PVCS, сервисы и входы для каждого отдельного игрового сервера, используя Kubernetes API. Каждый игровой сервер находится в своем собственном пространстве имен, полностью отделенном от других. Я заверил, что сервер работает под капотом, модуль также запущен и активен, журналы в порядке.

Я был заблокирован, когда мне нужно было назначить службу набора состояния для входа, которая способна непрерывно отвечать на трафик TCP / UDP с помощью DNS с пространством имен, который направляется к контроллеру входа кластера (в Minikube; для производства следует использовать ALB / NLB, AFAIK).

Каким-то образом мне нужен способ входа game-xxxxx.myapp.com в модуль определенного game-xxxxx пространства имен. На самом деле не имеет значения, будут ли у них добавленные порты или нет.

Для этого я могу просто вызвать API-решатель DNS myapp.com и добавить или удалить A Records , когда это необходимо. Это кажется нормальным, но я обнаружил, что могу использовать ExternalDNS (https://github.com/bitnami/charts/tree/master/bitnami/external-dns ), чтобы сделать это автоматически для меня, на основе существующих сервисов.

Что я пробовал, пока не повезло:

NGINX

Настройка NGINX, но мне пришлось определить открытые порты для каждой службы. На основе их документации (https://kubernetes.github.io/ingress-nginx/user-guide/exposing-tcp-udp-services ), было бы ИЗЛИШНИМ изменять эту конфигурационную карту и каждый раз заново создавать модули NGINX, поскольку может быть много изменений, и это не кажется жизнеспособным. Кроме того, я очень сомневаюсь, что NGINX будет легким при большой нагрузке, я считаю его более подходящим для веб-серверов, а не для игровых серверов.

Кроме того, мне может понадобиться способ убедиться, что у меня могут быть дублированные порты. Например, я не могу назначить в NGINX один и тот же 28015 порт многим другим серверам, даже если они находятся в разных пространствах имен. Если я использую Agones (https://github.com/googleforgames/agones/blob/release-1.9.0/examples/gameserver.yaml ) чтобы назначить случайные порты, в какой-то момент у меня может закончиться их количество для назначения.

Traefik

Я пытался использовать Traefik, но безуспешно. IngressRoute разрешает маршрутизацию TCP / UDP от маршрутизатора к точке входа и затем направляет ее к назначенной службе. Я не совсем уверен, как это работает, я попытался установить аннотации к службам и определить точки входа, но он по-прежнему отказывается работать: https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/#kind-ingressroutetcp

Agones

Agones должен работать для игровых серверов и поддерживает TCPUDP протокол для сервисных портов, но опять же, с этим не повезло.

Поток

Я опубликовал ниже диаграмму о том, как все должно работать. У меня также есть следующий файл YAML, который создаст набор с отслеживанием состояния, ПВХ и Службу. Вы можете ясно видеть, что я попробовал настроить ExternalName, так что, возможно, я смогу установить IP-адрес Minikube на это имя и смогу подключиться, но опять же, безуспешно:

Рабочий процесс выделенного сервера Steam

 apiVersion: v1
kind: Service
metadata:
  name: rust-service
  labels:
    game: rust
spec:
  # type: ExternalName
  # externalName: rust-1.rust.coal.app
  # clusterIP: ""
  selector:
    game: rust
  ports:
  - name: rust-server-tcp
    protocol: TCP
    port: 28015
    targetPort: 28015
  - name: rust-server-udp
    protocol: UDP
    port: 28015
    targetPort: 28015
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: rust-server
spec:
  selector:
    matchLabels:
      game: rust
  replicas: 1
  serviceName: rust-service
  template:
    metadata:
      name: rust-server
      labels:
        game: rust
    spec:
      containers:
      - name: rust
        image: didstopia/rust-server:latest
        ports:
          - name: rust-server-tcp
            protocol: TCP
            containerPort: 28015
          - name: rust-server-udp
            protocol: UDP
            containerPort: 28015
  volumeClaimTemplates:
    - metadata:
        name: local-disk
      spec:
        resources:
          requests:
            storage: "10Gi"
        accessModes: ["ReadWriteOnce"]
  

Редактировать: удар

Ответ №1:

Дополнительное замечание!

Если используется / упоминается входной ресурс, он ссылается на HTTP / HTTPS трафик.


Опубликованная вами диаграмма выглядит как хорошая возможность для использования Service типа LoadBalancer .

Служба типа LoadBalancer используется для обработки внешнего TCP / UDP трафика (уровень 4).

Отказ от ответственности!

Это решение поддерживает только один протокол, либо TCP или UDP .

Чтобы иметь оба протокола на одном и том же порту, вам нужно будет перейти к Service типу of NodePort (который выделяет порт на узле от 30000 to 32767 ).

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

В этой настройке Ingress контроллеры вроде Traefik или Nginx не нужны, поскольку они будут лишь дополнительным шагом между вашим Client и a Pod .

Пример такого LoadBalancer у вас уже есть в вашем YAML определении (я немного изменил его):

 apiVersion: v1
kind: Service
metadata:
  name: rust-service
  labels:
    game: rust
spec:
  type: LoadBalancer # <-- THE CHANGE
  selector:
    game: rust
  ports:
  - name: rust-server-tcp
    protocol: TCP
    port: 28015
    targetPort: 28015
  

Если вы собираетесь использовать AWS с ним EKS , пожалуйста, обратитесь к его документации:

Пример возможной настройки (шаги):

  • Для каждой «game-X»:
    • Создайте namespace «game-X-namespace»
    • Создайте deployment «game-X-deployment»
    • Создайте service тип LoadBalancer «game-X-«, который указывал бы на «game-X-deployment»
    • Создайте DNS запись, указывающую «game-X.com » к IP LoadBalancer -адресу, созданному на предыдущем шаге.

У каждого LoadBalancer будет свой собственный IP-адрес и DNS имя, связанное с ним, например:

  • awesome-game.com с IP 123.123.123.123 и портом для подключения 28015/TCP
  • magnificent-game.com с IP 234.234.234.234 и портом для подключения 28015/TCP

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


Дополнительные ресурсы:

Ответ №2:

Итак, как говорилось в предыдущем ответе, входы предназначены для веб-трафика. Я не добился рабочих настроек с использованием Ingresses, НО мне удалось использовать службу с NodePort помощью и убедиться, что вы создали DNS-запись с использованием внешнего DNS, которая привязывает пользовательское поддоменное имя к правильному IP: https://github.com/kubernetes-sigs/external-dns

Теперь проблема стоит далеко после идеи создания развертывания, ожидания назначения модуля и проверки того, что модуль привязан к этому узлу или, в случае, если узел будет разряжен, чтобы каким-то образом сохранить тот же IP-адрес узла (не эфемерный), который будет оставаться смодуль до тех пор, пока развертывание не будет удалено. Таким образом, я должен убедиться, что я помечаю узлы, когда мне нужно существующее развертывание для развертывания модулей.