Как разрешить службу TCP (не http) на пользовательском порту внутри Kubernetes

У меня есть контейнер, на котором работает OPC-сервер на порту 4840. Я пытаюсь настроить свои microk8, чтобы мой OPC-клиент мог подключаться к порту 4840. Вот примеры моего развертывания и обслуживания:

(Здесь не определено пространство имен, но они развертываются через конвейеры Azure, и именно там определяется пространство имен, пространство имен для развертывания и службы — «jawcrusher»).

развертывание.yml

      apiVersion: apps/v1
kind: Deployment
metadata:
  name: jawcrusher
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jawcrusher
  strategy: {}
  template:
    metadata:
      labels:
        app: jawcrusher
    spec:
      volumes:
        - name: jawcrusher-config
          configMap:
            name: jawcrusher-config
      containers:
      - image: XXXmicrok8scontainerregistry.azurecr.io/jawcrusher:#{Version}#
        name: jawcrusher
        ports:
          - containerPort: 4840
        volumeMounts:
          - name: jawcrusher-config
            mountPath: "/jawcrusher/config/config.yml"
            subPath: "config.yml"
      imagePullSecrets:
        - name: acrsecret

сервис.yml

      apiVersion: v1
kind: Service
metadata:
  name: jawcrusher-service
spec:
  ports:
  - name: 4840-4840
    port: 4840
    protocol: TCP
    targetPort: 4840
  selector:
    app: jawcrusher
  type: ClusterIP
status:
  loadBalancer: {}

Итак, теперь я хочу сказать microk8s, чтобы они обслуживали мой OPC-сервер через порт 4840 «извне». Например, если мой DNS для сервера — microk8s.xxxx.internal, я хотел бы подключиться к моему OPC-клиенту к microk8s.xxxx.internal:4840.

Я последовал этому примеру: https://microk8s.io/docs/addon-ingress (прокрутите немного вниз, чтобы увидеть tcp-часть)

Там написано обновить tcp-конфигурацию для входа, вот как это выглядит после того, как я ее обновил:

nginx-ingress-tcp-microk8s-conf:

      apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-ingress-tcp-microk8s-conf
  namespace: ingress
  ......
data:
  '4840': jawcrusher/jawcrusher-service:4840
binaryData: {}

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

nginx-ingress-microk8s-контроллер:

      spec:
      containers:
        - name: nginx-ingress-microk8s
          image: registry.k8s.io/ingress-nginx/controller:v1.2.0
          args:
            - /nginx-ingress-controller
            - '--configmap=$(POD_NAMESPACE)/nginx-load-balancer-microk8s-conf'
            - >-
              --tcp-services-configmap=$(POD_NAMESPACE)/nginx-ingress-tcp-microk8s-conf
            - >-
              --udp-services-configmap=$(POD_NAMESPACE)/nginx-ingress-udp-microk8s-conf
            - '--ingress-class=public'
            - ' '
            - '--publish-status-address=127.0.0.1'
          ports:
            - name: http
              hostPort: 80
              containerPort: 80
              protocol: TCP
            - name: https
              hostPort: 443
              containerPort: 443
              protocol: TCP
            - name: health
              hostPort: 10254
              containerPort: 10254
              protocol: TCP
            ####THIS IS WHAT I ADDED####
            - name: jawcrusher
              hostPort: 4840
              containerPort: 4840
              protocol: TCP

После обновления демонсета он перезапускает все модули. Порт кажется открытым, если я запустил этот скрипт, он выведет:

       Test-NetConnection -ComputerName microk8s.xxxx.internal -Port 4840                                                                                                                                                                                                                                                                             
 ComputerName     : microk8s.xxxx.internal                                                                            
 RemoteAddress    : 10.161.64.124                                                                                        
 RemotePort       : 4840                                                                                                 
 InterfaceAlias   : Ethernet 2                                                                                           
 SourceAddress    : 10.53.226.55
 TcpTestSucceeded : True

Прежде чем я внес изменения, было написано TcpTestSucceeded: False.

Но OPC-клиент не может подключиться. Просто пишет: Не удалось подключиться к серверу: BadCommunicationError.

Я вижу сообщение об ошибке в журналах ingress-daemonset-pod, когда пытаюсь подключиться к серверу с помощью моего OPC-клиента:

2023/02/15 09:57:32 [ошибка] 999#999: *63002 ошибка подключения() (111: Соединение отклонено) при подключении к восходящему каналу, клиент:10.53.225.232, сервер: 0.0.0.0:4840, восходящий поток: «10.1.98.125:4840», байты от/к клиенту:0/0, байты от/к восходящему потоку:0/0

10.53.225.232 — это IP-адрес клиентских компьютеров (где запущен OPC-клиент), а 10.1.98.125 — это IP-номер модуля, на котором работает OPC-сервер.

Похоже, он понял, что внешний порт 4840 должен быть проксирован/перенаправлен на мою службу, которая, в свою очередь, указывает на модуль OPC-сервера. Но почему я получаю ошибку...

Я не хочу использовать решение с переадресацией портов, но я попробовал это, просто чтобы посмотреть, сработает ли оно.

      kubectl port-forward service/jawcrusher-service 5000:4840 -n jawcrusher --address='0.0.0.0'

Это позволяет мне подключиться к моему OPC-клиенту к серверу через порт 5000. Но я не хочу использовать переадресацию порта, мне нужно более постоянное решение.

Кто-нибудь видит, я где-то ошибся или знает, как это сделать в микрок8с.

Обновление 1: Вот что выводит netstat:

      root@jawcrusher-7787464c5-8w5ww:/jawcrusher# netstat -tulpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.1:4840          0.0.0.0:*               LISTEN      1/python
tcp6       0      0 ::1:4840                :::*                    LISTEN      1/python

1 ответ

Практически в любых обстоятельствах, когда настройки не работают, а работа работает, почти всегда контейнер прослушивает 127.0.0.1, тогда как все поды должны прослушивать 0.0.0.0. Причинаkubectl port-forwardработает все время, заключается в том, что он фактически использует копиюsocatсоздается в той же сетевой контрольной группе, что и контейнер песочницы пода, поэтому его подключение не отражает подключение кластера к поду.

Быстрый тест может состоять в том, чтобыkubectl execв любой другой под в кластере (или подключение к узлу по ssh/ssm также должно работать) и выдачу завитка (или wget) на IP-адрес пода и проверку, доступен ли он из другого места в кластере. Поскольку конструкция kubernetes требует, чтобы все поды могли соединяться друг с другом (сетевая политика по модулю), это дешевый тест, позволяющий выяснить, может ли кто-нибудь получить доступ к этому контейнеру, а не толькоIngressилиServiceконфигурации

Другие вопросы по тегам