Развертывание простого приложения Node.js в кластере K8s на Hetzner Cloud с использованием Envoy Gateway

Вопрос или проблема

Я пытаюсь развернуть простое приложение Node.js в кластере Kubernetes на Hetzner Cloud. Приложение слушает на порту 8080 и предназначено для возврата “Hello, World!” при обращении к нему.

Вот мое базовое приложение на Express:

const express = require('express');
const app = express();
const PORT = 8080;

// Определите маршрут для корневого URL
app.get("https://serverfault.com/", (req, res) => {
    res.send('Hello, World!');
});

// Запустите сервер
app.listen(PORT, () => {
    console.log(`Сервер работает на http://localhost:${PORT}`);
});

Мой кластер Kubernetes имеет следующую конфигурацию

  • 1 узел управляющей панели
  • 2 рабочие узла

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

resource "hcloud_load_balancer" "cluster_load_balancer" {
  name               = "cluster_lb"
  load_balancer_type = "lb11"
  network_zone       = var.network_zone
  delete_protection  = false
}

resource "hcloud_load_balancer_service" "load_balancer_service_master" {
  load_balancer_id = hcloud_load_balancer.cluster_load_balancer.id
  protocol         = "tcp"
  listen_port      = 6443
  destination_port = 6443

  health_check {
    protocol = "tcp"
    port     = 6443
    interval = 10
    timeout  = 5
    retries  = 3
  }

}

resource "hcloud_load_balancer_service" "load_balancer_service_http" {
  load_balancer_id = hcloud_load_balancer.cluster_load_balancer.id
  protocol         = "http"
  listen_port      = 80
  destination_port = 80

  health_check {
    protocol = "http"
    port     = 80
    interval = 10
    timeout  = 5
    retries  = 3
  }

}

resource "hcloud_load_balancer_network" "lb_network_cluster" {
  load_balancer_id = hcloud_load_balancer.cluster_load_balancer.id
  network_id       = hcloud_network.private_network.id
}

resource "hcloud_load_balancer_target" "load_balancer_target_master" {
  for_each = { for idx, server in hcloud_server.master-node : idx => server }

  type             = "server"
  load_balancer_id = hcloud_load_balancer.cluster_load_balancer.id
  server_id        = each.value.id
  use_private_ip   = true

  depends_on = [hcloud_server.master-node]
}

resource "hcloud_load_balancer_target" "load_balancer_target_worker" {
  for_each = { for idx, server in hcloud_server.worker-node : idx => server }

  type             = "server"
  load_balancer_id = hcloud_load_balancer.cluster_load_balancer.id
  server_id        = each.value.id
  use_private_ip   = true

  depends_on = [hcloud_server.worker-node]
}

Ресурсы Kubernetes

Чтобы позволить пользователям получать доступ к моему приложению Node.js извне через балансировщик нагрузки, я создал следующие ресурсы:

apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: eg
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: eg
spec:
  gatewayClassName: eg
  listeners:
    - name: http
      protocol: HTTP
      port: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: example-httproute
  namespace: socials
spec:
  parentRefs:
    - name: eg
  rules:
    - backendRefs:
        - name: example-service
          kind: Service
          port: 80
      matches:
        - path:
            type: PathPrefix
            value: /
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: example-service-account
  namespace: socials
---
apiVersion: v1
kind: Service
metadata:
  name: example-service
  namespace: socials
spec:
  selector:
    app: example
  ports:
    - name: http
      port: 80
      targetPort: 8080

Определение развертывания

Вот определение развертывания моего пода:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: example-deployment
  namespace: socials
spec:
  replicas: 1
  selector:
    matchLabels:
      app: example
  template:
    metadata:
      labels:
        app: example
    spec:
      serviceAccountName: example-service-account
      containers:
        - name: example-container
          image: "redacted"
          imagePullPolicy: Always
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: "100m"
              memory: "1Gi"
            limits:
              cpu: "800m"
              memory: "2Gi"

Текущая проблема

Тем не менее, когда я посещаю IP-адрес балансировщика нагрузки в форме http://<load-balancer-ip>, я получаю следующую ошибку:

503 Service Unavailable
Нет доступного сервера для обработки этого запроса.

Правила брандмауэра

Я также добавил необходимые правила брандмауэра, как ниже, но не могу получить доступ к моему приложению Node.js извне:

resource "hcloud_firewall" "k8s_firewall" {
  name = "k8s-firewall"

  rule {
    description = "Разрешить входящие запросы TCP - Kube API Server"
    direction    = "in"
    protocol     = "tcp"
    port         = "6443"
    source_ips   = [
      "0.0.0.0/0",
      "::/0"
    ]
  }

  rule {
    description = "Разрешить входящий SSH-трафик"
    direction    = "in"
    protocol     = "tcp"
    port         = "22"
    source_ips   = ["0.0.0.0/0"]
  }

  rule {
    description = "Разрешить входящий HTTPS-трафик"
    direction    = "in"
    protocol     = "tcp"
    port         = "443"
    source_ips   = [
      "0.0.0.0/0",
      "::/0"
    ]
  }

  rule {
    description = "Разрешить входящий HTTP-трафик"
    direction    = "in"
    protocol     = "tcp"
    port         = "80"
    source_ips   = [
      "0.0.0.0/0",
      "::/0"
    ]
  }
}

Несмотря на все это, я не могу получить доступ к моему приложению Node.js извне кластера. Я буду очень признателен за любую помощь по этому вопросу.

Ответ или решение

Для развертывания вашего простого приложения Node.js на кластере Kubernetes в Hetzner Cloud с использованием Envoy Gateway, давайте рассмотрим все возможные проблемы, которые могут вызывать ошибку 503 Service Unavailable, и шаги, которые помогут вам успешно запустить ваше приложение.

1. Проверьте настройки Envoy Gateway

Убедитесь, что ваш Gateway настроен правильно:

  • GatewayClass и Gateway выглядят хорошо, но вам нужно подтвердить, что Envoy установлен и корректно работает в вашем кластере. Убедитесь, что контроллер Envoy Gateway работает и доступен на всех узлах вашего кластера.

  • Проверьте состояние ресурсов:

kubectl get pods -n kube-system
kubectl get gateways
kubectl get httproutes -n socials

2. Убедитесь в корректности определения маршрутов

Ваша спецификация HTTPRoute ссылается на сервис example-service, который по-умолчанию имеет порт 80. Проверьте, что приложение действительно прослушивает на этом порту:

  • Убедитесь, что ваш сервис правильно настроен:
apiVersion: v1
kind: Service
metadata:
  name: example-service
  namespace: socials
spec:
  selector:
    app: example
  ports:
    - name: http
      port: 80      # Это порт, по которому ваш сервис доступен
      targetPort: 8080  # Порт, на котором работает ваше приложение внутри контейнера
  • Убедитесь, что ваш деплоймент также правильно настроен, и метки соответствуют:
spec:
  selector:
    matchLabels:
      app: example  # Это должно совпадать с меткой в Service

3. Убедитесь, что приложение развёрнуто и работает

Проверьте состояние вашего пода:

kubectl get pods -n socials
kubectl logs <имя вашего пода> -n socials

Убедитесь, что под находится в состоянии Running и приложение работает без ошибок.

4. Проверка правил брандмауэра

Убедитесь, что ваши правила брандмауэра корректно настроены.

Вы уже добавили необходимые правила для порта 80, но проверьте следующее:

  • Правила на уровне загрузчика (load balancer) также должны быть настроены, чтобы перенаправлять трафик на ваш сервис. Убедитесь, что все необходимые порты правильно открыты и ограничения отсутствуют.

5. Логи Gateway и сервисов

Проверьте логи вашего Envoy Gateway и сервисов:

kubectl logs -l app=your-envoy-app -n kube-system

Проверьте, если есть какие-либо ошибки, указывающие на проблемы с подключениями.

Заключение

Пройдя все вышеуказанные шаги, вы сможете диагностировать основную причину проблемы 503. Убедитесь, что все сервисы, маршруты и правила брандмауэра правильно настроены. Если после всех этих проверок проблема сохраняется, рекомендуется просмотреть документацию Envoy Gateway и Hetzner Cloud на предмет возможных известных проблем и конфигураций.

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

Оцените материал
Добавить комментарий

Капча загружается...