Service, Ingress, DNS внутри кластера

↑ Этап 5 · Kubernetes

Желательно~6 мин чтенияУровень: middle

Зачем это на собесе

Сетевые абстракции Kubernetes — одна из главных тем: как поды находят друг друга и как трафик попадает снаружи.

Проблема

IP подов эфемерны. Service — стабильная точка доступа (виртуальный IP + DNS-имя) и балансировка между подами, выбранными по селектору меток (только Ready поды).

Типы Service

ТипДоступПрименение
ClusterIP (по умолчанию)внутри кластера (виртуальный IP)общение между сервисами
NodePortпорт 30000–32767 на каждой нодетесты, bare metal, база для LB
LoadBalancerвнешний балансировщик облака (или MetalLB)прямой внешний доступ к сервису (L4)
ExternalNameDNS CNAME на внешнее имяобращение к внешним сервисам по внутреннему имени
Headless (clusterIP: None)DNS возвращает IP подов (без VIP)StatefulSet, клиентская балансировка, gRPC
apiVersion: v1
kind: Service
metadata: { name: api }
spec:
  selector: { app: api }
  ports:
    - name: http
      port: 80            # порт сервиса
      targetPort: 8080    # порт контейнера (число или имя порта)
  type: ClusterIP
  sessionAffinity: None   # ClientIP при необходимости

Механизм: контроллер EndpointSlice формирует список IP:port готовых подов; kube-proxy (iptables/IPVS) перенаправляет трафик с ClusterIP на один из них (DNAT). Service без селектора + ручные Endpoints — для внешних систем.

DNS внутри кластера

CoreDNS создаёт записи:

  • <service>.<namespace>.svc.cluster.local → ClusterIP;
  • в том же namespace достаточно короткого имени api; между namespaces: api.clinic или api.clinic.svc;
  • headless: A-записи всех подов; у StatefulSet — pod-0.service.ns.svc.cluster.local;
  • SRV-записи для именованных портов;
  • переменные окружения API_SERVICE_HOST, API_SERVICE_PORT (устаревший способ, внедряются при старте пода).

Поды получают /etc/resolv.conf с search <ns>.svc.cluster.local svc.cluster.local cluster.local и ndots:5: короткие имена дополняются; внешние имена порождают несколько лишних запросов (оптимизация: FQDN с точкой example.com., dnsConfig, NodeLocal DNSCache).

kubectl run -it --rm dns --image=busybox:1.36 -- nslookup api.clinic.svc.cluster.local
kubectl get endpoints api; kubectl get endpointslices -l kubernetes.io/service-name=api

Ingress

Ingress — L7-правила маршрутизации внешнего HTTP(S) трафика на Services; реализуется Ingress-контроллером (NGINX, Traefik, HAProxy, Envoy/Contour, cloud LB). Один внешний IP обслуживает много хостов/путей, терминирует TLS.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: clinic
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "20m"
    cert-manager.io/cluster-issuer: letsencrypt
spec:
  ingressClassName: nginx
  tls:
    - hosts: [app.example.com]
      secretName: app-tls
  rules:
    - host: app.example.com
      http:
        paths:
          - { path: /api,  pathType: Prefix, backend: { service: { name: api, port: { number: 80 } } } }
          - { path: /,     pathType: Prefix, backend: { service: { name: web, port: { number: 80 } } } }

pathType: Exact, Prefix, ImplementationSpecific. Настройки зависят от контроллера (аннотации).

Gateway API — современная замена Ingress: разделение ролей (GatewayClass → Gateway → HTTPRoute/GRPCRoute/TCPRoute), богатая маршрутизация (веса, заголовки, зеркалирование), стандартизированные функции без аннотаций.

Внешний доступ: схемы

Клиент → DNS → LoadBalancer (облачный L4, один IP) → Ingress Controller (поды nginx) → Service → Pods
  • LoadBalancer на каждый сервис дорог; Ingress — один LB на много сервисов;
  • bare metal: MetalLB (L2/BGP) даёт IP для LoadBalancer; hostNetwork/NodePort + внешний LB;
  • externalTrafficPolicy: Cluster (по умолчанию, SNAT, равномерно, теряется IP клиента) или Local (сохраняет IP клиента, только локальные поды);
  • X-Forwarded-For / PROXY protocol для реального IP;
  • gRPC/WebSocket — аннотации/настройки контроллера, L7-балансировка.

Session affinity и балансировка

Service распределяет соединения (kube-proxy, не запросы): долгие HTTP/2/gRPC-соединения «прилипают» к одному поду → L7-балансировка (Envoy/Linkerd) или headless + клиентская балансировка. sessionAffinity: ClientIP — привязка по IP; cookie-affinity — на Ingress.

Диагностика

СимптомПроверка
Service недоступенkubectl get endpoints пуст → селектор не совпадает с метками подов / поды не Ready
Connection refusedtargetPort не тот; приложение слушает 127.0.0.1
Работает по IP пода, не по имениDNS (CoreDNS, ndots, namespace)
Ingress 404/503нет правила/host, backend без endpoints, неверный ingressClassName
502 от Ingressподы не отвечают, протокол (HTTPS backend), таймауты
Снаружи недоступен LoadBalancersecurity group/firewall, EXTERNAL-IP <pending> (нет облачного провайдера/MetalLB)
Теряется IP клиентаexternalTrafficPolicy: Cluster, L4 без PROXY protocol
kubectl port-forward svc/api 8080:80           # обход Ingress
kubectl exec -it debug -- curl -v http://api.clinic.svc:80/health
kubectl describe ingress clinic; kubectl logs -n ingress-nginx deploy/ingress-nginx-controller

Вопросы с ответами