Как выяснить, почему NodePort отказывается от соединений в K8S?
Введение
Недавно у меня появилось простое веб-приложение, работающее на трехузловом сервере Ubuntu с MicroK8S. Я решил попробовать перестроить свой кластер и переустановить все, используя манифесты YAML, чтобы обеспечить воспроизводимость процесса. Однако теперь приложение недоступно за пределами кластера. Я ищу методы отладки, чтобы понять, почему NodePort, по-видимому, не создает прослушиватель TCP на всех узлах.
Вот мои узлы:
Кластер снова решил выполнить рабочую нагрузку на третьем узле, Yamazaki. Я ожидаю, что любой веб-трафик, поступающий на Arran или Nikka, будет перенаправлен на Yamazaki для обслуживания, как это происходило ранее.
Что я сделал
Вот что я сделал, чтобы сбросить все из ранее работавшего кластера/приложения:
Делать
microk8s leave
на всех подчиненных узлахДелать
microk8s kubectl delete node <nodename>
на лидере для каждого последующего узла (они не удалялись автоматически при выходе)Делать
microk8s reset
на всех узлахВключить аддоны (DNS, Ingress). Я не знаю, нужно ли то и другое
Создайте команду соединения для лидера,
microk8s add-node
за каждого подписчикаЗапустите новую команду соединения
microk8s join <ip>/<token>
на каждого подписчикаБегать
microk8s status
на любом узле, чтобы убедиться, что кластер находится в режиме высокой доступностиЗагрузите архив с изображением приложения от лидера, используя
microk8s images import workload.tar
Запустите приложение через
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]
Убедитесь, что приложение работает через внутренний вызов контейнера,
microk8s kubectl exec -ti k8s-workload -- curl http://localhost:9090
- это отличноУбедитесь, что приложение работает через переадресатор портов на любом узле.
microk8s kubectl port-forward pod/k8s-workload 9090 --address='0.0.0.0'
- это отличноУзлы не прослушивают внешнее (
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
Есть всего две новые строки для добавления уникальной метки к этому объекту.