Как выяснить, почему NodePort отказывается от соединений в K8S?

Введение

Недавно у меня появилось простое веб-приложение, работающее на трехузловом сервере Ubuntu с MicroK8S. Я решил попробовать перестроить свой кластер и переустановить все, используя манифесты YAML, чтобы обеспечить воспроизводимость процесса. Однако теперь приложение недоступно за пределами кластера. Я ищу методы отладки, чтобы понять, почему NodePort, по-видимому, не создает прослушиватель TCP на всех узлах.

Вот мои узлы:

Кластер снова решил выполнить рабочую нагрузку на третьем узле, Yamazaki. Я ожидаю, что любой веб-трафик, поступающий на Arran или Nikka, будет перенаправлен на Yamazaki для обслуживания, как это происходило ранее.

Что я сделал

Вот что я сделал, чтобы сбросить все из ранее работавшего кластера/приложения:

  1. Делатьmicrok8s leaveна всех подчиненных узлах

  2. Делатьmicrok8s kubectl delete node <nodename>на лидере для каждого последующего узла (они не удалялись автоматически при выходе)

  3. Делатьmicrok8s resetна всех узлах

  4. Включить аддоны (DNS, Ingress). Я не знаю, нужно ли то и другое

  5. Создайте команду соединения для лидера,microk8s add-nodeза каждого подписчика

  6. Запустите новую команду соединенияmicrok8s join <ip>/<token>на каждого подписчика

  7. Бегатьmicrok8s statusна любом узле, чтобы убедиться, что кластер находится в режиме высокой доступности

  8. Загрузите архив с изображением приложения от лидера, используяmicrok8s images import workload.tar

  9. Запустите приложение черезmicrok8s kubectl apply -f k8s-manifests/production/pod.yaml -f k8s-manifests/production/nodeport.yaml

    Вот под:

             apiVersion: v1
     kind: Pod
     metadata:
       name: k8s-workload
       annotations:
         kubectl.kubernetes.io/last-applied-configuration: |
           {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"k8s-workload","namespace":"default"},"spec":{"containers":[{"image":"k8s-workload","imagePullPolicy":"Never","name":"k8s-workload","ports":[{"containerPort":9090,"protocol":"TCP"}]}]}}
     spec:
       containers:
       - image: k8s-workload
         imagePullPolicy: Never
         name: k8s-workload
         ports:
         - containerPort: 9090
           protocol: TCP
    

    Вот NodePort:

             apiVersion: v1
     kind: Service
     metadata:
       name: np-service
     spec:
       type: NodePort
       ports:
         - port: 9090
           targetPort: 9090
           nodePort: 30090
       selector:
         run: k8s-workload
       # This should not be needed, but it didn't help
       # this time anyway
       externalIPs: [192.168.50.251]
    
  10. Убедитесь, что приложение работает через внутренний вызов контейнера,microk8s kubectl exec -ti k8s-workload -- curl http://localhost:9090- это отлично

  11. Убедитесь, что приложение работает через переадресатор портов на любом узле.microk8s kubectl port-forward pod/k8s-workload 9090 --address='0.0.0.0'- это отлично

  12. Узлы не прослушивают внешнее (curl http://localhost:30090получает отказ в соединении, то же самое с IP-адресом любого узла с некластерной машины в локальной сети)

Состояние системы

Вот что бежит отmicrok8s kubectl get all -o wide:

      NAME               READY   STATUS    RESTARTS   AGE   IP             NODE       NOMINATED NODE   READINESS GATES
pod/k8s-workload   1/1     Running   0          20h   10.1.134.193   yamazaki   <none>           <none>

NAME                 TYPE        CLUSTER-IP       EXTERNAL-IP      PORT(S)          AGE     SELECTOR
service/kubernetes   ClusterIP   10.152.183.1     <none>           443/TCP          35d     <none>
service/np-service   NodePort    10.152.183.175   192.168.50.251   9090:30090/TCP   3d21h   run=k8s-workload

я не знаю чтоservice/kubernetesесть, я предполагаю, что это просто часть стандартной инфраструктуры K8S.

Наблюдения

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

В статье также предлагается использовать входную систему. Однако, учитывая, что в настоящее время я изучаю NodePort, я не хочу пока отказываться от него. Ингресс может произойти позже.

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

Я хотел бы запустить что-то вродеmicrok8s kubectl logs service np-service, чтобы увидеть, что делает NodePort, но подкоманда logs работает только с модулями.

Что я могу попробовать дальше?

2 ответа

Когда используешьkubectl runдля запуска подов Kubernetes автоматически помечает их именем, использованным при развертывании.

Например, взгляните на YAML, сгенерированныйkubectl run nginx --image=nginx -o yaml:

      apiVersion: v1
kind: Pod
metadata:
  labels:
    run: nginx <- Automatically assigned
  name: nginx
  namespace: default
spec:
  containers:
  - image: nginx
    ...

Теперь, предполагая, что YAML Podk8s-workloadПредоставленный вами файл заполнен, эта метка в настоящее время отсутствует. Это важно, посколькуselectorты использовал вNodePort's specs.

      apiVersion: v1
kind: Service
metadata:
  name: np-service
spec:
  ...
  selector:
    run: k8s-workload <- This tells Kubernetes who the Service is for

Я предполагаю, что на данный момент Kubernetes просто не может найти под, для которого предназначен сервис. Вы можете проверить эту теорию, запустивkubectl get pods -l run=k8s-workload. Вы должны получить сообщение об ошибке, которое выглядит примерно так:No resources found in default namespace.

Исправить это так же просто, как (пере)назначить метку. Это можно сделать с помощьюkubectl labelкомандовать какkubectl label pod k8s-workload run=k8s-workload.

Подробное руководство по отладке Services , а также дополнительную информацию о том, как работают Labels и Selectors, можно найти в официальной документации.

Обновлять

Что касается того, будет ли эта ситуация регистрироваться: Служба без конечных точек не является ошибкой и (насколько мне известно) не будет нигде регистрироваться. Представьте себе развертывание, которое необходимо всего несколько часов в неделю. Ожидается, что развертывание неактивно и, следовательно, у Службы нет конечных точек в течение 90% недели, что не означает, что что-то настроено неправильно или не работает.

Как я и подозревал, решение было простым. Элеасар любезно предоставилlabelкоманду, чтобы решить проблему, но я предпочел исправить ее в YAML, так как считаю, что это более повторяемо. Вот мой новыйpod.yaml:

      apiVersion: v1
kind: Pod
metadata:
  name: k8s-workload
  labels:
    run: k8s-workload
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"k8s-workload","namespace":"default"},"spec":{"containers":[{"image":"k8s-workload","imagePullPolicy":"Never","name":"k8s-workload","ports":[{"containerPort":9090,"protocol":"TCP"}]}]}}
spec:
  containers:
  - image: k8s-workload
    imagePullPolicy: Never
    name: k8s-workload
    ports:
    - containerPort: 9090
      protocol: TCP

Есть всего две новые строки для добавления уникальной метки к этому объекту.

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