Как мне настроить доступ к нескольким узлам с помощью одной службы в кубернетах?

Я пытаюсь настроить доступ к модулям на нескольких узлах с помощью одного Service yaml. Все стручки имеют одинаковые ярлыки (скажем,label:app), но распределены между несколькими узлами, а не на одном узле.

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

spec:
  type: NodePort
  selector:
    label:app
  ports:
    targetPort: 5000
    nodePort: 30000 

где доступ к порту 30000 на узле перенаправляет на порт 5000 на модуле.

Если у меня есть модули на нескольких узлах, есть ли способ, которым клиент может получить доступ к одной конечной точке, например к самой Службе, чтобы получить любой модуль в циклическом режиме? Или клиенту нужно получить доступ к набору модулей на определенном узле, используя IP-адрес этого узла, как вxx.xx.xx.xx:30000?

2 ответа

Решение

Хотя LoadBalancer - безусловно рекомендуемое решение (особенно в облачной среде), стоит отметить, что NodePort также имеет возможности балансировки нагрузки.

Тот факт, что вы получаете доступ к своему NodePort Обслуживание на конкретном узле не означает, что вы можете получить доступ только таким образом Pods которые были запланированы на этом конкретном узле.

Как вы можете прочитать в NodePortУслуги по спецификации:

Каждый узел передает этот порт (один и тот же номер порта на каждом узле) в ваш Service.

Итак, получив доступ к порту 30080 на одном конкретном узле ваш запрос не идет напрямую на какой-то случайный Pod, запланированный на этом узле. Он проксируется наServiceобъект, который является абстракцией, охватывающей все узлы. И это, наверное, ключевой момент здесь, поскольку вашNodePort Сервис никаким образом не привязан к узлу, IP-адрес которого вы используете для доступа к своим модулям.

Следовательно NodePortСервис может направлять клиентские запросы ко всем подам в кластере, используя простой алгоритм циклического перебора.

Вы можете легко проверить это, используя следующие Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      initContainers:
      - name: init-myservice
        image: nginx:1.14.2
        command: ['sh', '-c', "echo $MY_NODE_NAME > /usr/share/nginx/html/index.html"]
        env:
        - name: MY_NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        volumeMounts:
        - mountPath: /usr/share/nginx/html
          name: cache-volume
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /usr/share/nginx/html
          name: cache-volume
      volumes:
      - name: cache-volume
        emptyDir: {}

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

kubectl scale deployment nginx-deployment --replicas=9

Затем убедитесь, что ваши поды запланированы на разных узлах:

kubectl get pods -o wide

Перечислите все свои узлы:

kubectl get nodes -o wide

и выберите IP-адрес узла, который вы хотите использовать для доступа к своим модулям.

Теперь вы можете выставить Deployment запустив:

kubectl expose deployment nginx-deployment --type NodePort --port 80 --target-port 80

или если вы хотите указать номер порта самостоятельно, например, как 30080, примените следующие NodePort Определение услуги как kubectl expose не позволяет указать точный nodePort ценность:

apiVersion: v1
kind: Service
metadata:
  name: nginx-deployment
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30080

Затем попробуйте получить доступ к своим модулям через NodePortСервис с использованием IP ранее выбранного узла. Возможно, вам придется попробовать как обычный, так и частный режим / режим инкогнито или даже другой браузер (простое обновление может не работать), но в конечном итоге вы увидите, что разные запросы попадают в модули, запланированные на разных узлах.

Имейте в виду, что если вы решите использовать NodePortвы не сможете использовать хорошо известные порты. На самом деле это может быть даже возможно, поскольку вы можете изменить диапазон портов по умолчанию (30000-32767) на что-то вроде 1-1024в конфигурации kube-apiserver с помощью--service-node-port-range вариант, но его не рекомендуется, так как это может привести к некоторым неожиданным проблемам.

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

spec:
  ports:
    - name: httpsPort
      port: 443
      protocol: TCP
      targetPort: 443
  selector:
    label: app
  type: LoadBalancer

Если у вас есть несколько сервисов в одном кластере, к которым необходимо получить доступ из внешней системы, вы можете использовать Ingress.

Спасибо Кируба

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