Поды постоянно пересоздаются и меняют IP. Service даёт им стабильное имя и адрес, Ingress или Gateway API пускают HTTP-трафик снаружи, NetworkPolicy ограничивает, кто с кем может говорить.
Service
apiVersion: v1
kind: Service
metadata:
name: api
spec:
selector:
app: api
ports:
- port: 80 # порт сервиса
targetPort: 8080 # порт контейнера (число или имя порта)
Service выбирает поды по селектору меток и балансирует трафик на те, что готовы (прошли readiness probe). Список адресов хранится в объектах EndpointSlice, их обновляет контроллер. На узлах kube-proxy (iptables или IPVS) или CNI на eBPF превращает обращения к адресу сервиса в соединения с подами.
Балансировка идёт на уровне соединений (L4). Долгоживущие соединения (gRPC, HTTP/2, пулы к базе) закрепляются за одним подом, и после масштабирования новые поды могут простаивать. Для gRPC нужна балансировка на уровне запросов: на клиенте или в сервис-меше.
Типы Service
- ClusterIP (по умолчанию): виртуальный IP внутри кластера. Для общения сервисов между собой.
- NodePort: ClusterIP плюс порт на каждом узле (по умолчанию из диапазона 30000-32767). Внешний трафик на
<IP узла>:<nodePort>попадает в сервис. - LoadBalancer: NodePort плюс внешний балансировщик облака (через cloud-controller-manager) или MetalLB на своём железе.
- ExternalName: DNS-псевдоним (CNAME) на внешнее имя, без проксирования.
- Headless (
clusterIP: None): виртуального IP нет, DNS отдаёт IP подов напрямую. Нужен StatefulSet (db-0.db.prod.svc) и клиентам, которые балансируют сами.
DNS в кластере
CoreDNS создаёт записи для сервисов:
apiиз того же namespace;api.prodиз другого namespace;api.prod.svc.cluster.localполное имя.
В /etc/resolv.conf пода прописаны search-домены и options ndots:5. Имя с менее чем пятью точками сначала пробуется с каждым суффиксом из search. Поэтому запрос к api.example.com из пода порождает несколько лишних DNS-запросов. Для внешних имён помогает точка в конце (api.example.com.) или настройка dnsConfig.
Отладка «Service есть, а запросы не доходят»
kubectl get svc api -o wide
kubectl get endpointslices -l kubernetes.io/service-name=api
kubectl get pods -l app=api --show-labels
kubectl run tmp --rm -it --image=nicolaka/netshoot -- curl -v http://api.prod
Самая частая причина: пустые эндпоинты. Либо селектор не совпадает с метками подов (опечатка), либо поды не проходят readiness. Вторая по частоте: targetPort не совпадает с портом, который реально слушает приложение (или приложение слушает 127.0.0.1).
Ingress
Ingress описывает HTTP(S)-маршрутизацию: хост и путь → Service. Сам объект ничего не делает, нужен Ingress-контроллер (NGINX, Traefik, HAProxy, облачные), который читает Ingress и настраивает прокси.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api
spec:
ingressClassName: nginx
tls:
- hosts: [api.example.com]
secretName: api-tls
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api
port:
number: 80
TLS-сертификаты лежат в Secret типа kubernetes.io/tls, их обычно выпускает и продлевает cert-manager. Многие настройки (таймауты, размер тела, rewrite) задаются аннотациями конкретного контроллера и между контроллерами не переносятся.
Gateway API
Gateway API это более новый стандарт для входящего трафика. Ресурсы разделены по ролям: GatewayClass (тип реализации), Gateway (точка входа, слушатели и сертификаты, зона ответственности платформы) и маршруты HTTPRoute, GRPCRoute (зона команд). Стандартизованы вещи, которые в Ingress делались аннотациями: разделение трафика по весам, заголовки, перезапись путей. Многие контроллеры поддерживают и Ingress, и Gateway API.
NetworkPolicy
По умолчанию всем подам можно всё. NetworkPolicy ограничивает трафик для выбранных подов. Как только под выбран хотя бы одной политикой на вход (Ingress) или выход (Egress), разрешено только то, что явно разрешено политиками.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-allow-api
spec:
podSelector:
matchLabels: { app: postgres }
policyTypes: [Ingress]
ingress:
- from:
- podSelector:
matchLabels: { app: api }
ports:
- port: 5432
Работает, только если CNI поддерживает политики (Calico, Cilium; Flannel без дополнений не поддерживает). Ограничивая Egress, не забудь разрешить DNS (порт 53 к CoreDNS), иначе всё сломается.
Частые ошибки
- Селектор Service не совпадает с метками подов.
- Перепутаны
portиtargetPort. - Нет readiness probe, трафик идёт на неготовые поды.
- Ingress создан, а контроллер не установлен или не тот
ingressClassName. - Egress-политика без разрешения DNS.
Что спросят на собесе
- Типы Service и когда какой.
- Как Service находит поды и что такое EndpointSlice.
- Service есть, а запросы не доходят: как отлаживать.
- Чем Ingress отличается от Service LoadBalancer, что такое Ingress-контроллер.
- Как ограничить доступ к базе только с подов API.