← К программе курса

Модуль 8 / 19

Ingress, TLS, маршрутизация трафика и диагностика edge

KUBERNETES

Содержание
01

1. Цели и результат модуля

Вы опубликуете два HTTP backend через одну точку входа, настроите TLS termination и научитесь локализовать отказ между клиентом, ingress controller, Service и Pod.

  • Ingress описывает L7-маршруты, но не обрабатывает пакеты
  • IngressClass связывает ресурс с controller
  • Host и path выбирают backend Service
  • TLS Secret хранит сертификат и ключ
  • 404 и 503 указывают на разные слои
02

2. Теория: Service, Ingress и controller

Service даёт стабильный L4 endpoint набору Pods. Ingress добавляет HTTP/HTTPS routing по host и path, но API-объект сам не является proxy. Controller наблюдает Ingress, Service, EndpointSlice и Secret и строит реальную конфигурацию edge.

В лаборатории используется поддерживаемый Traefik. Community ingress-nginx завершил сопровождение в марте 2026 года, поэтому новый стенд на нём не строим.

03

3. Теория: host, path и IngressClass

Сначала сопоставляется Host, затем path. Prefix учитывает сегменты, Exact требует точного совпадения, ImplementationSpecific зависит от controller. Самый длинный совпавший path приоритетнее. ingressClassName должен ссылаться на существующий IngressClass.

Ingress не обязан переписывать URL: backend получает исходный path. Rewrite — непереносимая controller-specific функция.

04

4. Теория: TLS termination и SNI

SNI сообщает имя сайта во время TLS handshake. Controller выбирает сертификат из Secret kubernetes.io/tls, завершает TLS и направляет запрос backend. Шифрование от edge до Pod настраивается отдельно.

  • Проверяйте SAN, issuer, срок и цепочку доверия
  • Secret находится в namespace Ingress
  • Закрытый ключ не хранится в Git
  • Самоподписанный сертификат — только для лаборатории
05

5. Путь запроса и модель отказов

DNS/Node address → NodePort controller → entrypoint → host/path router → Service → EndpointSlice → Ready Pod → приложение.

  • Timeout/refused: адрес, firewall, NodePort или controller
  • 404 edge: class, host или path не совпал
  • 503 edge: route найден, backend недоступен
  • 404 приложения: backend достигнут, приложение не знает path
  • TLS error: SNI, SAN, trust chain или срок
06

6. Ingress API и Gateway API

Ingress API стабилен, но функционально заморожен. Новые возможности развиваются в Gateway API: GatewayClass, Gateway и HTTPRoute разделяют роли инфраструктуры, cluster operator и application developer.

Fundamentals закрепляет Ingress; Gateway API практикуется в Advanced/HA части на multi-node edge.

07

7. Методические указания

  • При проверке по IP передавайте Host
  • Проверяйте controller и IngressClass до route
  • Сверяйте backend name/port, Service и EndpointSlice
  • TLS проверяйте с CA и SNI
  • Не считайте curl -k доказательством корректного TLS
  • Не начинайте с рестарта controller
  • Отделяйте Ingress API от vendor annotations
08

8. Лабораторная работа: ingress controller

Установите фиксированную версию chart. Dashboard отключён, HTTP/HTTPS открыты через предсказуемые NodePort.

terminal
helm repo add traefik https://traefik.github.io/charts
helm repo update traefik
helm upgrade --install traefik traefik/traefik \
  --version 41.4.0 --namespace traefik-system --create-namespace \
  --wait --timeout 5m --set api.dashboard=false \
  --set ingressRoute.dashboard.enabled=false \
  --set service.spec.type=NodePort \
  --set ports.web.nodePort=30080 --set ports.websecure.nodePort=30443
kubectl -n traefik-system get deployment,pod,service
kubectl get ingressclass traefik -o yaml
09

9. Лабораторная работа: два backend

Два Deployment и два ClusterIP Service возвращают имя фактического Pod.

terminal
mkdir -p /tmp/k8s-m08
kubectl create namespace k8s-m08
cat > /tmp/k8s-m08/app.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata: {name: web, namespace: k8s-m08}
spec:
  replicas: 2
  selector: {matchLabels: {app: web}}
  template:
    metadata: {labels: {app: web}}
    spec:
      containers:
      - name: nginx
        image: nginx:1.29-alpine
        command: ["sh", "-c"]
        args: ["printf 'web=%s\n' "$HOSTNAME" > /usr/share/nginx/html/index.html; exec nginx -g 'daemon off;'"]
        ports: [{name: http, containerPort: 80}]
---
apiVersion: apps/v1
kind: Deployment
metadata: {name: api, namespace: k8s-m08}
spec:
  replicas: 2
  selector: {matchLabels: {app: api}}
  template:
    metadata: {labels: {app: api}}
    spec:
      containers:
      - name: nginx
        image: nginx:1.29-alpine
        command: ["sh", "-c"]
        args: ["mkdir -p /usr/share/nginx/html/api; printf 'api=%s\n' "$HOSTNAME" > /usr/share/nginx/html/api/index.html; exec nginx -g 'daemon off;'"]
        ports: [{name: http, containerPort: 80}]
---
apiVersion: v1
kind: Service
metadata: {name: web, namespace: k8s-m08}
spec: {selector: {app: web}, ports: [{name: http, port: 80, targetPort: http}]}
---
apiVersion: v1
kind: Service
metadata: {name: api, namespace: k8s-m08}
spec: {selector: {app: api}, ports: [{name: http, port: 80, targetPort: http}]}
EOF
kubectl apply --dry-run=server -f /tmp/k8s-m08/app.yaml
kubectl apply -f /tmp/k8s-m08/app.yaml
kubectl -n k8s-m08 wait --for=condition=Available deployment/web deployment/api --timeout=180s
kubectl -n k8s-m08 get service,endpointslice,pod -o wide
10

10. Лабораторная работа: routing и TLS

Корень идёт в web, /api — в api. Затем добавьте лабораторный сертификат и проверьте доверие, SNI и SAN без отключения проверки.

terminal
cat > /tmp/k8s-m08/ingress.yaml <<'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: course
  namespace: k8s-m08
  annotations: {traefik.ingress.kubernetes.io/router.entrypoints: "web,websecure"}
spec:
  ingressClassName: traefik
  rules:
  - host: app.course.test
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend: {service: {name: api, port: {name: http}}}
      - path: /
        pathType: Prefix
        backend: {service: {name: web, port: {name: http}}}
EOF
kubectl apply --dry-run=server -f /tmp/k8s-m08/ingress.yaml
kubectl apply -f /tmp/k8s-m08/ingress.yaml
kubectl -n k8s-m08 describe ingress course
node_ip=$(hostname -I | awk '{print $1}')
curl -fsS -H 'Host: app.course.test' "http://$node_ip:30080/"
curl -fsS -H 'Host: app.course.test' "http://$node_ip:30080/api/"
terminal
openssl req -x509 -nodes -newkey rsa:2048 -days 30 \
  -keyout /tmp/k8s-m08/tls.key -out /tmp/k8s-m08/tls.crt \
  -subj '/CN=app.course.test' -addext 'subjectAltName=DNS:app.course.test'
kubectl -n k8s-m08 create secret tls edge-tls --cert=/tmp/k8s-m08/tls.crt --key=/tmp/k8s-m08/tls.key
kubectl -n k8s-m08 patch ingress course --type=merge -p \
  '{"spec":{"tls":[{"hosts":["app.course.test"],"secretName":"edge-tls"}]}}'
node_ip=$(hostname -I | awk '{print $1}')
curl --resolve "app.course.test:30443:$node_ip" --cacert /tmp/k8s-m08/tls.crt https://app.course.test:30443/
openssl s_client -connect "$node_ip:30443" -servername app.course.test </dev/null 2>/dev/null \
 | openssl x509 -noout -subject -issuer -dates -ext subjectAltName
11

11. Диагностика: 404 и 503

Несуществующий IngressClass оставляет запрос default handler и даёт 404. При правильном class, но отсутствующем backend route совпадает и ожидается 503.

terminal
kubectl -n k8s-m08 patch ingress course --type=merge -p '{"spec":{"ingressClassName":"missing"}}'
curl -sS -o /dev/null -w 'status=%{http_code}\n' -H 'Host: app.course.test' "http://$(hostname -I | awk '{print $1}'):30080/"
kubectl get ingressclass; kubectl -n k8s-m08 describe ingress course
kubectl -n k8s-m08 patch ingress course --type=merge -p '{"spec":{"ingressClassName":"traefik"}}'
kubectl -n k8s-m08 patch service api --type=merge -p '{"spec":{"selector":{"app":"missing"}}}'
curl -sS -o /dev/null -w 'status=%{http_code}\n' -H 'Host: app.course.test' "http://$(hostname -I | awk '{print $1}'):30080/api/"
kubectl -n traefik-system logs deployment/traefik --since=2m | tail -40
kubectl -n k8s-m08 patch service api --type=merge -p '{"spec":{"selector":{"app":"api"}}}'
12

12. Контроль, критерии освоения и cleanup

  • Почему Ingress нужен controller?
  • Чем Ingress отличается от Service?
  • Как работает ingressClassName?
  • Prefix против Exact?
  • Почему backend видит /api?
  • Что выбирает SNI?
  • Где хранится TLS Secret?
  • Почему -k опасен?
  • Что различает 404 и 503?
  • Зачем Gateway API?
terminal
kubectl delete namespace k8s-m08 --wait=true
rm -rf /tmp/k8s-m08
# Traefik остаётся инфраструктурой следующих лабораторий.
# Полное удаление: helm uninstall traefik -n traefik-system

Модуль освоен, если оба backend работают по host/path, TLS проверяется с CA, а route и upstream ошибки различаются по evidence.