Як під у Kubernetes отримує IP-адресу

Прим. перев.: ця стаття, написана SRE-інженером з LinkedIn, в деталях розповідає про ту «внутрішню магію» в Kubernetes — точніше, про взаємодію CRI, CNI і kube-apiserver, — що відбувається, коли черговому pod'у потрібно призначити IP-адресу.

Одна з базових вимог мережевої моделі Kubernetes полягає в тому, що у кожного pod'а має бути своя власна IP-адреса і будь-який інший pod у кластері повинен мати можливість зв'язатися з ним за цією адресою. Є безліч мережевих «провайдерів» (Flannel, Calico, Canal тощо), які допомагають реалізувати цю мережеву модель.

Коли я тільки-но починав працювати з Kubernetes, мені було не зовсім ясно, як саме pod'и отримують свої IP-адреси. Навіть із розумінням, як функціонують окремі компоненти, було складно уявити їхню спільну роботу. Наприклад, я знав, навіщо потрібні плагіни CNI, але не уявляв, як саме вони викликаються. Тому вирішив написати цю статтю, щоб поділитися знаннями про різні мережеві компоненти та їх спільну роботу в кластері Kubernetes, які й дозволяють кожному pod'у отримати свою унікальну IP-адресу.

Існують різні способи організації мережевої взаємодії в Kubernetes — аналогічно до того, як і різні варіанти виконуваних середовищ (runtime) для контейнерів. У цій публікації буде використовуватись Фланель для організації мережі в кластері, а як виконуване середовище — Контейнер. Також я виходжу з припущення, що ви знаєте, як влаштована мережна взаємодія між контейнерами, тому лише коротко торкнуся її, виключно для контексту.

Деякі базові поняття

Контейнери та мережа: короткий огляд

В інтернеті досить відмінних публікацій, які пояснюють, як контейнери зв'язуються один з одним через мережу. Тому проведу лише загальний огляд основних понять і обмежуся одним підходом, що передбачає створення Linux-мосту та інкапсуляцію пакетів. Подробиці опущені, оскільки сама тема мережевої взаємодії контейнерів заслуговує на окрему статтю. Посилання на деякі особливо змістовні та пізнавальні публікації будуть наведені нижче.

Контейнери на одному хості

Один із способів організації зв'язку по IP-адрес між контейнерами, що працюють на тому самому хості, передбачає створення Linux-моста. Для цього у Kubernetes (і Docker) створюються віртуальні пристрої veth (virtual ethernet). Один кінець veth-пристрою підключається до мережного простору імен контейнера, інший до Linux-мосту у мережі хоста.

У всіх контейнерів на одному хості один з кінців veth підключений до мосту, через який вони можуть зв'язуватися один з одним IP-адресами. У Linux-моста також є IP-адреса, і він виступає як шлюз для вихідного (egress) трафіку з pod'ів, призначеного для інших вузлів.

Як під у Kubernetes отримує IP-адресу

Контейнери на різних хостах

Інкапсуляція пакетів - один із способів, що дозволяє контейнерам на різних вузлах зв'язуватися один з одним за IP-адресами. У Flannel за цю можливість відповідає технологія vxlan, яка «упаковує» вихідний пакет у UDP і потім відправляє його за призначенням.

У кластері Kubernetes Flannel створює пристрій vxlan і доповнює таблицю маршрутів на кожному з вузлів. Кожен пакет, призначений для контейнера на іншому хості, проходить через пристрій vxlan та інкапсулюється у пакет UDP. У пункті призначення вкладений пакет витягується та перенаправляється на потрібний pod.

Як під у Kubernetes отримує IP-адресу
Це лише один із способів організації мережевої взаємодії між контейнерами.

Що таке CRI?

CRI (Container Runtime Interface) — це плагін, що дозволяє kubelet'у використовувати різні середовища контейнерів. API CRI вбудований в різні середовища, тому користувачі можуть вибирати runtime на свій розсуд.

Що таке CNI?

Проект CNI являє собою специфікацію для організації універсального мережевого рішення для Linux-контейнерів Крім того, він включає в себе плагіни, що відповідають за різні функції при налаштуванні мережі pod'а. Плагін CNI - це файл, що виконується, відповідні специфікації (деякі плагіни ми обговоримо нижче).

Виділення підмереж вузлам для призначення IP-адрес pod'ам

Оскільки кожен pod кластера повинен мати IP-адресу, важливо переконатися в тому, щоб ця адреса була унікальною. Це досягається шляхом виділення кожному вузлу унікальної підмережі, з якої потім pod'ам на цьому вузлі призначаються IP-адреси.

Контролер IPAM вузла

Коли nodeipam передається як параметр прапора --controllers kube-controller-manager'а, він кожному вузлу виділяє окрему підмережу (podCIDR) з CIDR кластера (тобто діапазону IP-адрес для мережі кластера). Оскільки ці podCIDR'и не перетинаються, стає можливим кожному pod'у виділити унікальну IP-адресу.

Вузолу Kubernetes присвоюється podCIDR у момент його початкової реєстрації кластері. Щоб змінити podCIDR у вузлів, необхідно їх дереєструвати і потім повторно зареєструвати, в проміжку внісши відповідні зміни до конфігурації керуючого шару Kubernetes. Вивести podCIDR вузла можна за допомогою наступної команди:

$ kubectl get no <nodeName> -o json | jq '.spec.podCIDR'
10.244.0.0/24

Kubelet, середовище запуску контейнера та плагіни CNI: як це все працює

Планування pod'а на вузол пов'язане з виконанням безлічі підготовчих дій. У цьому розділі я сконцентруюсь тільки на тих з них, які безпосередньо пов'язані з налаштуванням мережі pod'а.

Планування pod'а на якийсь вузол запускає наступний ланцюжок подій:

Як під у Kubernetes отримує IP-адресу

Довідка: Архітектура CRI-плагінів Containerd.

Взаємодія середовища запуску контейнерів та плагінів CNI

Кожен мережний провайдер має свій плагін CNI. Runtime контейнер запускає його, щоб налаштувати мережу для pod'a в процесі його запуску. У разі containerd запуском CNI-плагіна займається плагін Containerd CRI.

При цьому кожен провайдер має свій агент. Він встановлюється у всі вузли Kubernetes та відповідає за мережеве налаштування pod'ів. Цей агент йде або в комплекті з конфігом CNI або самостійно створює його на вузлі. Конфіг допомагає CRI-плагіну встановити, який плагін CNI викликати.

Місце розташування конфігу CNI можна налаштувати; за умовчанням він лежить у /etc/cni/net.d/<config-file>. Адміністратори кластера також відповідають за встановлення CNI плагінів на кожен вузол кластера. Їхнє місцезнаходження також налаштовується; директорія за замовчуванням /opt/cni/bin.

При використанні containerd шляху для конфігу та бінарників плагіна можна задати в розділі [plugins.«io.containerd.grpc.v1.cri».cni] в файл конфігурації containerd.

Оскільки ми використовуємо Flannel як мережевий провайдер, давайте трохи поговоримо про його налаштування:

  • Flanneld (демон Flannel'а) зазвичай встановлюється в кластер як DaemonSet з install-cni як init-контейнер.
  • Install-cni створює файл конфігурації CNI (/etc/cni/net.d/10-flannel.conflist) на кожному вузлі.
  • Flanneld створює пристрій vxlan, витягує мережні метадані з API-сервера та стежить за оновленнями pod'ів. У міру їх створення він розповсюджує маршрути для всіх pod'ів по всьому кластеру.
  • Ці маршрути і дозволяють pod'ам зв'язуватися один з одним за IP-адресами.

Для отримання більш детальної інформації про роботу Flannel рекомендую скористатися посиланнями наприкінці статті.

Ось схема взаємодії між плагіном Containerd CRI та плагінами CNI:

Як під у Kubernetes отримує IP-адресу

Як видно вище, kubelet викликає плагін Containerd CRI, щоб створити pod, а той вже викликає плагін CNI для налаштування мережі pod'а. При цьому CNI-плагін мережного провайдера викликає інші базові плагіни CNI для налаштування різних аспектів мережі.

Взаємодія між CNI-плагінами

Існують різні плагіни CNI, завдання яких – допомогти налаштувати мережну взаємодію між контейнерами на хості. У цій статті йтиметься про три з них.

CNI-плагін Flannel

При використанні Flannel як мережного провайдера компонент Containerd CRI викликає CNI-плагін Flannel, використовуючи конфігураційний файл CNI /etc/cni/net.d/10-flannel.conflist.

$ cat /etc/cni/net.d/10-flannel.conflist
{
  "name": "cni0",
  "plugins": [
    {
      "type": "flannel",
      "delegate": {
         "ipMasq": false,
        "hairpinMode": true,
        "isDefaultGateway": true
      }
    }
  ]
}

CNI-плагін Flannel працює спільно з Flanneld. Під час запуску Flanneld витягує podCIDR та інші пов'язані з мережею подробиці з API-сервера та зберігає їх у файл /run/flannel/subnet.env.

FLANNEL_NETWORK=10.244.0.0/16 
FLANNEL_SUBNET=10.244.0.1/24
FLANNEL_MTU=1450 
FLANNEL_IPMASQ=false

CNI-плагін Flannel використовує дані з /run/flannel/subnet.env для налаштування та виклику CNI-плагіна мосту (bridge).

CNI-плагін Bridge

Цей плагін викликається з наступною конфігурацією:

{
  "name": "cni0",
  "type": "bridge",
  "mtu": 1450,
  "ipMasq": false,
  "isGateway": true,
  "ipam": {
    "type": "host-local",
    "subnet": "10.244.0.0/24"
  }
}

При першому виклику він створює Linux-міст з «name»: «cni0», що вказується у конфізі. Потім для кожного pod'а створюється пара veth. Один її кінець підключається до мережного простору імен контейнера, інший входить до Linux-місту в мережі хоста. CNI-плагін Bridge підключає всі контейнери хоста до Linux-мосту у мережі хоста.

Закінчивши з налаштуванням пари veth, плагін Bridge викликає локальний для хоста (host-local) CNI-плагін IPAM. Тип IPAM-плагіна можна налаштувати в конфізі CNI, який плагін CRI використовує для виклику CNI-плагіна Flannel.

Локальні для хоста IPAM-плагіни CNI

Bridge CNI викликає хост-локальний IPAM-плагін CNI з наступною конфігурацією:

{
  "name": "cni0",
  "ipam": {
    "type": "host-local",
    "subnet": "10.244.0.0/24",
    "dataDir": "/var/lib/cni/networks"
  }
}

Host-local IPAM-плагін (IP Aдрес Management - управління IP-адресами) повертає IP-адресу для контейнера з підмережі та зберігає виділену IP на хості в директорії, зазначеній у розділі dataDir - /var/lib/cni/networks/<network-name=cni0>/<ip>. У цьому файлі міститься ID контейнера, якому присвоєно дану IP-адресу.

При виклику host-local IPAM-плагіну він повертає такі дані:

{
  "ip4": {
    "ip": "10.244.4.2",
    "gateway": "10.244.4.3"
  },
  "dns": {}
}

Резюме

Kube-controller-manager кожному вузлу надає podCIDR. Pod'и кожного вузла отримують IP-адреси з простору адрес у виділеному діапазоні podCIDR. Оскільки podCIDR'и вузлів не перетинаються, всі pod'и отримують унікальні IP-адреси.

Адміністратор кластера Kubernetes налаштовує та встановлює kubelet, середовище запуску контейнерів, агента мережного провайдера та копіює плагіни CNI на кожен вузол. Під час старту агент мережного провайдера генерує конфіг CNI. Коли ПД планується на вузол, кубелет викликає CRI-плагін для його створення. Далі, якщо використовується containerd, плагін Containerd CRI викликає CNI-плагін, зазначений у конфізі CNI, для налаштування мережі pod'а. В результаті pod отримує IP-адресу.

Мені знадобився деякий час, щоб розібратися у всіх тонкощах і нюансах усіх цих взаємодій. Сподіваюся, отриманий досвід допоможе вам краще зрозуміти, як працює Kubernetes. Якщо я в чомусь помиляюсь, будь ласка, зв'яжіться зі мною у Twitter або за адресою [захищено електронною поштою]. Не соромтеся звертатися, якщо захочете обговорити аспекти цієї статті чи щось інше. Я із задоволенням поспілкуюсь з вами!

Посилання

Контейнери та мережа

Як працює Flannel

CRI та CNI

PS від перекладача

Читайте також у нашому блозі:

Джерело: habr.com

Додати коментар або відгук