сеньорчикОткрыть в Telegram
← вся теориятеория к собесу · Kubernetes

Service и Ingress в Kubernetes

Сеть кластера

Поднял сервис перед двумя подами (под - это запущенный экземпляр приложения в кластере). Сервис получил постоянный адрес 10.43.33.209, а за ним встал список из двух адресов подов: 10.42.0.4 и 10.42.0.5. Из соседнего пода запрос по имени web-svc вернул страницу. Потом я удалил один под - и в списке появился адрес нового, 10.42.0.12. Имя и адрес сервиса не менялись ни разу.

Стержень: сервис - это постоянное имя и адрес поверх меняющегося списка подов; связывает их не конфигурация, а метки.

// Формулировки: «как поды находят друг друга?», «чем отличаются типы сервисов?», «что такое ingress?»

Сервис, метки и список адресов

Адрес пода недолговечен: я это видел, при пересоздании он сменился. Поэтому обращаются не к подам, а к сервису. У сервиса есть постоянный адрес внутри кластера и постоянное имя, которое разрешает встроенный сервер имён.

Связь сервиса с подами - по МЕТКАМ, а не по списку. Сервис говорит «мне все поды с меткой приложение равно web», и кластер сам поддерживает список подходящих адресов. Я наблюдал это вживую: удалил под - из списка ушёл его адрес и появился адрес нового.

// Отсюда самая частая поломка новичка: сервис есть, а список адресов пуст. Причин ровно две - метки в сервисе не совпадают с метками подов, либо поды не прошли пробу готовности. Проверяется это одной командой, которая показывает список адресов за сервисом: пусто - значит, ищите одну из этих двух причин, а не проблемы в сети.

сервис
постоянное имя и адрес поверх меняющегося набора подов
метки
пары имя-значение на объектах; по ним сервис и находит свои поды
список адресов
фактические адреса подов за сервисом; пустой список - главный симптом

Имена и поиск

Внутри кластера у каждого сервиса есть полное имя вида имя-сервиса.пространство.svc.cluster.local, где пространство - это отсек кластера, в котором живёт группа объектов. Поды при этом настроены так, что короткого имени достаточно: я посмотрел настройки резолвера внутри пода и увидел строку поиска с тремя суффиксами и порог в пять точек.

Это ровно та настройка, о которой я рассказывал в теме про службу имён, и цена у неё измеримая: имя с двумя точками считается неполным, поэтому сначала перебираются суффиксы кластера и только потом спрашивается настоящее имя. На обращениях к внешним адресам это добавляет лишние вопросы к серверу имён на каждый запрос.

// Лечится это точкой в конце внешнего имени или своими настройками резолвера для конкретного пода. А внутри кластера коротким именем пользоваться удобно и правильно - к соседу в том же пространстве обращаются просто по имени сервиса.

полное имя сервиса
имя.пространство.svc.cluster.local; внутри достаточно короткого
суффиксы поиска
что дописывается к неполному имени; для внешних адресов это лишние запросы

Типы сервисов и вход снаружи

Внутренний сервис - тот, что я поднимал: адрес виден только внутри кластера, снаружи не достучаться. Это тип по умолчанию и правильный выбор для общения сервисов между собой.

Порт на узле открывает один и тот же порт на всех узлах кластера и заворачивает его на сервис. Работает везде, но порт из ограниченного диапазона и адрес узла надо где-то держать. Балансировщик просит внешний адрес у облака - удобно, но каждый такой сервис это отдельный платный балансировщик, и на тридцати сервисах это заметная сумма.

// Поэтому наружу обычно выставляют ОДИН вход, а за ним маршрутизируют по именам и путям. Правила описываются отдельным объектом, а исполняет их контроллер входа - по сути посредник, который принимает запросы снаружи и раздаёт их нужным сервисам внутри. Один внешний адрес, один сертификат на домен, десятки сервисов за ним.

внутренний сервис
адрес виден только внутри кластера; тип по умолчанию
контроллер входа
обратный прокси в кластере: один внешний адрес и маршруты по именам и путям

Как отвечать: «Сервис создан, но приложение по нему не отвечает. Где искать?»

Первым делом смотрю список адресов за сервисом - это одна команда. Если он пуст, дело не в сети вообще. Причин ровно две: метки в сервисе не совпадают с метками подов, либо поды не проходят пробу готовности, и кластер честно не пускает на них трафик. Обе проверяются за минуту. Если список не пуст, проверяю порты: у сервиса есть свой порт и порт контейнера, и их путают постоянно. Дальше захожу в соседний под и стучусь сначала по адресу пода напрямую, потом по адресу сервиса, потом по имени - так сразу видно, на каком шаге ломается: приложение, маршрутизация или разрешение имени. Я на стенде проверял всю цепочку, включая то, что при удалении пода список адресов обновляется сам и имя сервиса при этом не меняется.

Ответ даёт порядок проверки от самого частого к редкому и разбивает проблему на три различимых шага. Именно так это и делают в жизни.

На чём валятся

  • Не смотрят список адресов за сервисом и ищут проблему в сети.
  • Путают метки сервиса и метки подов.
  • Забывают, что под без пройденной пробы готовности в список не попадает.
  • Заводят отдельный внешний балансировщик на каждый сервис и платят за все.
  • Прописывают адреса подов вместо имён сервисов.

Проверьте себя

Пять вопросов из банка по этой подтеме. Всего их 6, остальные разбираются в тренажёре.

  1. #dvo_k8s_network1 / 5
    Создали Ingress с правилами, но по домену ничего не открывается. Что забыли?
    A)Прописать в Ingress порт ноды: без него правило не активируется
    B)Перевести сервис в тип LoadBalancer — Ingress работает лишь поверх него
    C)Поставить ingress-контроллер: сам объект — только описание правил
    D)Включить Ingress в настройках kube-proxy на каждой ноде
    показать ответ и разбор
    +C)Поставить ingress-контроллер: сам объект — только описание правил

    // разбор: Ingress — декларация маршрутов: домен, путь, целевой сервис, TLS-секрет. Исполняет её контроллер (nginx, Traefik, HAProxy, облачный), который слушает объекты этого типа и настраивает реальный прокси. Без установленного контроллера и класса ingressClassName объект просто лежит в кластере. Точку входа снаружи при этом даёт сервис самого контроллера — LoadBalancer или NodePort.

  2. #dvo_k8s_network2 / 5
    Навесили NetworkPolicy с одним правилом ingress на под — и часть его связей отвалилась. Почему?
    A)Политика применяется ко всему namespace, а не к выбранным подам
    B)Выбранный политикой под пускает лишь описанное
    C)Политики работают на отказ и запрещают перечисленное в правилах
    D)Правило ingress закрывает исходящий трафик, пока не добавлен egress
    показать ответ и разбор
    +B)Выбранный политикой под пускает лишь описанное

    // разбор: Пока под не выбран ни одной политикой, разрешено всё. Как только его выбрала хотя бы одна политика с секцией ingress, входящий трафик становится запрещённым по умолчанию, и живёт только то, что явно разрешено правилами. Egress работает симметрично и отдельно. Плюс важная деталь эксплуатации: политики исполняет сетевой плагин — на CNI без их поддержки объект создастся и не будет делать ничего.

  3. #dvo_k8s_network3 / 5
    Чем отличаются Service типа ClusterIP, NodePort и LoadBalancer по тому, откуда доступен сервис?
    A)Все три доступны лишь внутри кластера, разница только в балансировке
    B)ClusterIP смотрит наружу, NodePort внутрь, LoadBalancer между кластерами
    C)ClusterIP — внутри кластера, NodePort — через порт нод, LoadBalancer — внешний LB
    D)Отличаются протоколом: TCP, UDP и HTTP соответственно
    показать ответ и разбор
    +C)ClusterIP — внутри кластера, NodePort — через порт нод, LoadBalancer — внешний LB

    // разбор: ClusterIP (по умолчанию) доступен только внутри кластера (стабильный виртуальный IP). NodePort открывает порт на IP каждой ноды, чтобы дотянуться снаружи. LoadBalancer поднимает внешний балансировщик (в облаке), который фронтит NodePort'ы. Типы надстраиваются друг над другом. L7-вход (Ingress) — отдельный слой поверх Service.

  4. #dvo_k8s_network4 / 5
    Обращение к Service висит и отваливается, а kubectl get endpoints по нему пуст. Что не так?
    A)Под ещё не получил ClusterIP, надо подождать его выдачи
    B)У Service закончились свободные порты под эндпоинты
    C)kube-proxy не запущен, поэтому список эндпоинтов и пуст
    D)Селектор Service не совпал с метками подов — эндпоинтов нет
    показать ответ и разбор
    +D)Селектор Service не совпал с метками подов — эндпоинтов нет

    // разбор: Service выбирает поды по меткам; его Endpoints/EndpointSlice наполняется подами, которые матчат селектор И прошли readiness. Пустые эндпоинты → селектор не совпал ни с одним готовым подом (опечатка в labels, не тот namespace, поды не Ready). Трафику некуда идти — зависание/отказ. Проверяют kubectl get endpoints, сверяют селектор Service с метками подов и их готовность.

  5. #dvo_k8s_network5 / 5
    Поды на одной ноде общаются, а между нодами связи нет; часть подов висит в ContainerCreating. Куда смотреть?
    A)В kube-proxy: без него поды разных нод не видят друг друга
    B)В CNI-плагин: межнодовую сеть подов обеспечивает он
    C)В CoreDNS: это он маршрутизирует трафик между нодами
    D)В Ingress-контроллер: он связывает поды разных нод
    показать ответ и разбор
    +B)В CNI-плагин: межнодовую сеть подов обеспечивает он

    // разбор: Сеть pod-to-pod между нодами обеспечивает CNI-плагин (Calico, Cilium, Flannel): он строит плоскую сеть подов, veth и маршруты. Если CNI не установлен/сломан, поды не получают сеть (застревают в ContainerCreating: network plugin not ready), а межнодовой трафик не идёт. kube-proxy отвечает за VIP сервисов (не за сырые маршруты подов), CoreDNS — за имена, Ingress — за L7-вход; сеть подов дают не они.

дальше

Теорию прочитали. Навык ставится повторением

В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.