Настраиваем Ingress Controller Traefik и Let's Encrypt в кластере Kubernetes на Ubuntu 22.04
Ubuntu / Containers Сегодня, 18:47 sobir 13 0
На уже развёрнутом kubeadm-кластере поднимем Ingress Controller Traefik, дадим ему принимать входящий трафик на портах 80/443, настроим persistent-хранилище для сертификатов и получим рабочий HTTPS через Let's Encrypt встроенным ACME-клиентом Traefik.
Требования
- Рабочий kubeadm-кластер: control-plane и минимум один worker.
- Доменное имя, A-запись которого указывает на публичный IP одной из worker-нод.
- Открытые порты 80 и 443 на этой ноде — в облачном firewall, если он есть, отдельно от firewall самой ОС.
- Email для регистрации в Let's Encrypt.
1. Установка Helm
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-4
chmod 700 get_helm.sh
./get_helm.sh
helm version2. Установка Traefik через Helm
Добавляем репозиторий:
helm repo add traefik https://traefik.github.io/charts
helm repo updateСтавим с hostNetwork: true — под будет напрямую биндиться на порты ноды, без облачного LoadBalancer (актуально для self-managed VPS, где его просто нет):
helm install traefik traefik/traefik \
--namespace traefik \
--create-namespace \
--set hostNetwork=true \
--set service.enabled=false \
--set nodeSelector."kubernetes\.io/hostname"=<hostname_worker_ноды>nodeSelector жёстко закрепляет Traefik за конкретной нодой — именно за той, на чей IP указывает ваш домен.
3. Меняем порты на 80/443
По умолчанию чарт слушает 8000/8443 (непривилегированные порты), а не 80/443. Меняем явно:
helm upgrade traefik traefik/traefik \
--namespace traefik \
--reuse-values \
--set ports.web.port=80 \
--set ports.websecure.port=443 \
--set securityContext.runAsUser=0 \
--set securityContext.runAsNonRoot=false \
--set podSecurityContext.runAsUser=0 \
--set podSecurityContext.runAsNonRoot=false \
--set securityContext.capabilities.add[0]=NET_BIND_SERVICEПроверяем, что порты реально слушаются на нужной ноде:
ss -tlpn | grep traefikОжидаем *:80 и *:443.
4. Настраиваем DNS для hostNetwork-пода
Под с hostNetwork: true по умолчанию использует DNS-настройки самой ноды (/etc/resolv.conf хоста), а не кластерный CoreDNS — из-за этого под не сможет резолвить имена вида *.svc.cluster.local других сервисов кластера. Для Ingress-роутинга это не критично (Traefik получает адреса подов напрямую из Kubernetes API, а не через DNS), но пригодится для любых будущих проверок и интеграций изнутри самого Traefik:
helm upgrade traefik traefik/traefik \
--namespace traefik \
--reuse-values \
--set deployment.dnsPolicy=ClusterFirstWithHostNetClusterFirstWithHostNet — официальное значение Kubernetes специально для hostNetwork-подов, которым всё равно нужен доступ к кластерному DNS.
5. Открываем порты в облачном firewall
Отдельно от firewall самой ОС: если используете, например, Hetzner Cloud Firewall, добавьте inbound-правила для TCP 80 и 443 на эту ноду. Проверить снаружи:
telnet <публичный_IP> 806. Устанавливаем StorageClass (local-path-provisioner)
Без него любой PersistentVolumeClaim в кластере зависнет в Pending навсегда — в self-managed kubeadm-кластере, в отличие от managed (EKS/GKE), StorageClass по умолчанию не существует.
kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.36/deploy/local-path-storage.yaml
kubectl get pods -n local-path-storageДелаем его default-классом кластера:
kubectl patch storageclass local-path -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'7. Включаем persistence для сертификатов
Без этого шага сертификат будет теряться при каждом перезапуске пода, а частые повторные запросы упрутся в rate limit Let's Encrypt — не больше 5 дубликатов в неделю на домен.
helm upgrade traefik traefik/traefik \
--namespace traefik \
--reuse-values \
--set persistence.enabled=true \
--set persistence.size=128Mi \
--set persistence.storageClass=local-path8. Настраиваем ACME (Let's Encrypt)
helm upgrade traefik traefik/traefik \
--namespace traefik \
--reuse-values \
--set certificatesResolvers.le.acme.email=<ваш_email> \
--set certificatesResolvers.le.acme.storage=/data/acme.json \
--set certificatesResolvers.le.acme.httpChallenge.entryPoint=web9. Добавляем init-container для прав на acme.json
Traefik сам предупреждает об этом при первом упоминании persistence и ACME: без явного init-container права на файл могут теряться при перезапуске.
cat <<EOF > traefik-acme-init.yaml
deployment:
initContainers:
- name: volume-permissions
image: busybox:latest
command: ["sh", "-c", "touch /data/acme.json; chmod -v 600 /data/acme.json"]
volumeMounts:
- mountPath: /data
name: data
EOF
helm upgrade traefik traefik/traefik \
--namespace traefik \
--reuse-values \
-f traefik-acme-init.yamlПроверяем логи — должна появиться строка о старте ACME-провайдера:
kubectl logs -n traefik -l app.kubernetes.io/name=traefik --tail=30 | grep -i acme10. Деплоим тестовое приложение: HTTP и HTTPS независимо, двумя отдельными Ingress
kubectl create deployment demo --image=traefik/whoami --replicas=1
kubectl expose deployment demo --port=80 --target-port=80Если нужен редирект HTTP в HTTPS (частый случай) — достаточно одного Ingress с TLS-секцией, роутер сам обработает оба направления. Но если протоколы должны работать независимо, без редиректа — нужны два отдельных Ingress, каждый со своим entrypoints и backend:
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-http
annotations:
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/router.entrypoints: web
spec:
rules:
- host: <ваш_домен>
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: demo
port:
number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-https
annotations:
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls.certresolver: le
spec:
tls:
- hosts:
- <ваш_домен>
rules:
- host: <ваш_домен>
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: demo
port:
number: 80
EOFTraefik автоматически инициирует HTTP-01 challenge (через роутер demo-http на порту 80) и получит сертификат для роутера demo-https — проверяем:
kubectl logs -n traefik -l app.kubernetes.io/name=traefik --tail=30 | grep -i acmeПроверяем оба протокола отдельно:
curl -I http://<ваш_домен>/
curl -I https://<ваш_домен>/Оба должны вернуть 200 OK.
Возможные проблемы
PVC зависает в Pending: unbound immediate PersistentVolumeClaims
Причина — не указан storageClass явно, а в кластере нет default StorageClass. Решение — шаги 6 и 7 выше: поставить local-path-provisioner, пометить его как default либо явно указать persistence.storageClass=local-path.
Если PVC уже создан пустым, без storageClass, — storageClassName неизменяемое поле, апгрейд Helm его не поправит. Нужно удалить и пересоздать:
kubectl delete pvc traefik -n traefik
kubectl delete pod -n traefik -l app.kubernetes.io/name=traefikbind: permission denied даже с runAsUser=0
Root сам по себе не спасает от capability-based проверки ядра. Чарт по умолчанию выставляет securityContext.capabilities.drop: [ALL] — обнуляет всё, включая право биндиться на порт меньше 1024. Добавьте capability явно, вместе с root:
--set securityContext.capabilities.add[0]=NET_BIND_SERVICEHTTP отдаёт 404, хотя HTTPS на том же домене работает нормально
Причина — общий Ingress с аннотацией router.tls.certresolver, которая делает единственный роутер TLS-only для всех перечисленных entrypoints (см. шаг 10 выше). Разделите на два отдельных Ingress-объекта: один чисто HTTP, другой чисто HTTPS.
При каждом helm upgrade новый под зависает в Pending с ошибкой didn't have free ports
Классика для hostNetwork: true — два пода с одинаковыми портами физически не могут одновременно жить на одной ноде. Rolling update не может завершиться сам. Перед апгрейдами, меняющими сетевую конфигурацию, проще сразу остановить старый под:
kubectl scale deployment traefik -n traefik --replicas=0
# helm upgrade ...
kubectl scale deployment traefik -n traefik --replicas=1Traefik слушает 8000/8443 вместо 80/443, хотя ports.web.port=80 указан
Проверьте фактические слушающие порты прямо на ноде:
ss -tlpn | grep traefikЕсли видите старые порты — под не пересоздался после апгрейда (сверьте PID процесса до и после). Удалите под вручную, Deployment пересоздаст его с актуальным конфигом.
Разворачиваем полноценный кластер Kubernetes через kubeadm на трёх серверах с Ubuntu 22.04....
ПодробнееРассмотрим настройку прозрачного проксирования в Squid без подмены сертификатов на базе ОС Ubuntu 22.04....
ПодробнееПолучаем валидные сертификаты SSL от Let's Encrypt для NGINX с использованием различных плагинов....
ПодробнееПоднимаем сервер SSL VPN OpenConnect для удаленного доступа пользователям....
ПодробнееНастраиваем обратный прокси сервер NGINX с SSL-терминацией и генерируем бесплатные валидные сертификаты SSL...
ПодробнееУстановка последней стабильной версии популярного веб сервера NGINX....
ПодробнееНовые комментарии
Цитата: FidoNet Цитата: sobir Цитата: FidoNet Спасибо за статью. Остальные
Цитата: sobir Цитата: FidoNet Спасибо за статью. Остальные статьи что находил
Цитата: FidoNet Цитата: sobir Цитата: FidoNet Можт быть дело в
Цитата: sobir Цитата: FidoNet Можт быть дело в dnsmasq.service? Ошибка Failed
Цитата: FidoNet Цитата: sobir Цитата: FidoNet Спасибо за статью. Остальные
Можт быть дело в dnsmasq.service? Ошибка Failed to set DNS configuration: Unit





