Вопрос или проблема
Я пытаюсь развернуть простое приложение 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 на предмет возможных известных проблем и конфигураций.
Если вы обнаружите любые сообщения об ошибках, предоставьте их для дальнейшего анализа.