Це багатосторінковий друкований вигляд цього розділу. Натисність щоб друкувати.

Повернутися до звичайного перегляду сторінки.

Огляд API

Цей розділ містить довідкову інформацію про API Kubernetes.

REST API є фундаментальною основою Kubernetes. Усі операції та комунікації між компонентами та зовнішніми командами користувачів є викликами REST API, які обробляє API-сервер. Внаслідок цього все в Kubernetes обробляється як обʼєкти API та має відповідний запис в API.

Довідник API Kubernetes містить список API для версії Kubernetes v1.37.

Загальні відомості дивіться в розділі API Kubernetes. Контроль доступу до API Kubernetes описує, як клієнти можуть автентифікуватися на API-сервері Kubernetes і як авторизуються їхні запити.

Версіювання API

Схеми серіалізації JSON та Protobuf дотримуються однакових правил щодо змін схеми. Наведені нижче описи стосуються обох форматів.

Версіювання API та версіювання програмного забезпечення опосередковано повʼязані. Пропозиція з версіювання API та релізів описує звʼязок між версіюванням API та версіюванням програмного забезпечення.

Різні версії API вказують на різні рівні стабільності та підтримки. Докладнішу інформацію про критерії кожного рівня можна знайти в документації API Changes.

Ось короткий огляд кожного рівня:

  • Alpha:

    • Назви версій містять alpha (наприклад, v1alpha1).
    • Вбудовані версії API рівня alpha типово вимкнені та повинні бути явно увімкнені в конфігурації kube-apiserver для використання.
    • Програмне забезпечення може містити помилки. Увімкнення функції може виявити помилки.
    • Підтримку alpha API може бути припинено будь-коли без попередження.
    • API може змінитися несумісним чином у подальших версіях програмного забезпечення без попередження.
    • Програмне забезпечення рекомендується використовувати лише в короткочасних тестових кластерах через збільшений ризик помилок та відсутність довгострокової підтримки.
  • Beta:

    • Назви версій містять beta (наприклад, v2beta3).

    • Вбудовані версії API рівня beta типово вимкнені та повинні бути явно увімкнені в конфігурації kube-apiserver для використання (за винятком бета-версій API, представлених до Kubernetes 1.22, які були типово увімкнені).

    • Вбудовані версії API рівня beta мають максимальний термін існування 9 місяців або 3 мінорні випуски (залежно від того, що довше), починаючи від введення до застаріння, і 9 місяців або 3 мінорні випуски (залежно від того, що довше) від застаріння до вилучення.

    • Програмне забезпечення добре протестоване. Увімкнення функції вважається безпечним.

    • Підтримку функції не буде припинено, хоча деталі можуть змінитися.

    • Схема та/або семантика обʼєктів може змінюватися несумісним чином у подальших версіях API рівня beta або стабільного. Коли це відбувається, надаються інструкції з міграції. Адаптація до наступної версії API рівня beta або стабільного може вимагати редагування чи повторного створення обʼєктів API, і це може бути не простим. Міграція може вимагати перерви у роботі застосунків, які покладаються на цю функцію.

    • Програмне забезпечення не рекомендується для використання в промисловому середовищі. Подальші випуски можуть вносити несумісні зміни. Після того як версію API рівня beta визнано застарілою і вона більше не обслуговується, тим, хто її використовує, доведеться перейти на наступні версії API рівня beta або стабільні.

    Примітка:

    Спробуйте бета-функції та надавайте відгуки. Після того, як функції вийдуть з бета, може бути непрактично вносити більше змін.
  • Stable:

    • Назва версії — vX, де X – це ціле число.
    • Стабільні версії API залишаються доступними для всіх майбутніх випусків в межах основної версії Kubernetes, і немає поточних планів щодо ревізії основної версії Kubernetes, що вилучає стабільні API.

Групи API

Групи API спрощують розширення API Kubernetes. Група API вказується в REST-шляху та в полі apiVersion серіалізованого обʼєкта.

У Kubernetes існує кілька груп API:

  • Група core (також називається legacy) знаходиться за REST-шляхом /api/v1. Група core не вказується як частина поля apiVersion, наприклад, apiVersion: v1.
  • Іменовані групи знаходяться за REST-шляхом /apis/$GROUP_NAME/$VERSION та використовують apiVersion: $GROUP_NAME/$VERSION (наприклад, apiVersion: batch/v1). Повний список підтримуваних груп API можна знайти в довіднику API Kubernetes.

Увімкнення чи вимкнення груп API

Деякі ресурси та групи API типово увімкнені. Ви можете увімкнути чи вимкнути їх, встановивши --runtime-config на API-сервері. Прапорець --runtime-config приймає розділені комами пари <key>[=<value>], що описують конфігурацію запуску API-сервера. Якщо частина =<value> пропущена, вона розглядається так, ніби вказано =true. Наприклад:

  • для вимкнення batch/v1 встановіть --runtime-config=batch/v1=false
  • для увімкнення batch/v2alpha1 встановіть --runtime-config=batch/v2alpha1
  • для увімкнення конкретної версії API, наприклад, storage.k8s.io/v1beta1/csistoragecapacities, встановіть --runtime-config=storage.k8s.io/v1beta1/csistoragecapacities

Примітка:

Коли ви вмикаєте чи вимикаєте групи або ресурси, потрібно перезапустити API-сервер і controller manager, щоб вони врахували зміни --runtime-config.

Збереження

Kubernetes зберігає свій серіалізований стан у вигляді ресурсів API, записуючи їх в etcd.

Що далі

1 - Концепції API Kubernetes

API Kubernetes — це програмний інтерфейс на основі ресурсів (RESTful), який надається через HTTP. Він підтримує отримання, створення, оновлення та видалення основних ресурсів за допомогою стандартних HTTP-дієслів (POST, PUT, PATCH, DELETE, GET).

Для деяких ресурсів API включає додаткові субресурси, що дозволяють детальніше налаштовувати авторизацію (наприклад, окремі представлення для деталей Pod та отримання логів), і може приймати та надавати ці ресурси в різних представленнях для зручності або ефективності.

Kubernetes підтримує ефективні сповіщення про зміни ресурсів за допомогою спостережень (watches):

в API Kubernetes watch — це дієслово, яке використовується для відстеження змін обʼєкта в Kubernetes у вигляді потоку. Використовується для ефективного виявлення змін.

Kubernetes також забезпечує узгоджені операції отримання списків, щоб клієнти API могли ефективно кешувати, відстежувати та синхронізувати стан ресурсів.

Ви можете переглянути довідник API онлайн або прочитати далі, щоб дізнатися про API загалом.

Терміни API Kubernetes

Kubernetes зазвичай використовує загальноприйняту термінологію RESTful для опису концепцій API:

  • Тип ресурсу — це назва, що використовується в URL (pods, namespaces, services)
  • Усі типи ресурсів мають конкретне представлення (їхню схему обʼєкта), яке називається kind (вид)
  • Список екземплярів типу ресурсу називається колекцією
  • Окремий екземпляр типу ресурсу називається ресурсом і зазвичай також представляє обʼєкт
  • Для деяких типів ресурсів API включає один або більше субресурсів, які представлені як URI-шляхи під ресурсом

Більшість типів ресурсів API Kubernetes є обʼєктами — вони представляють конкретний екземпляр концепції у кластері, як-от Pod або простір імен. Невелика кількість типів ресурсів API є віртуальними, оскільки вони часто представляють операції над обʼєктами, а не самі обʼєкти, такі як перевірка дозволів (використання POST із JSON-кодованим тілом SubjectAccessReview для ресурсу subjectaccessreviews), або субресурс eviction у Pod (використовується для запуску виселення, ініційованого API).

Імена обʼєктів

Усі обʼєкти, які ви можете створити через API, мають унікальне імʼя (name), що дозволяє ідемпотентне створення та отримання, за винятком віртуальних типів ресурсів, які можуть не мати унікальних імен, якщо вони не можуть бути отримані або не залежать від ідемпотентності.

У межах Namespace (простору імен) унікальна ідентичність обʼєкта визначається кортежем з його групи API, ресурсу, простору імен та імені.

  • Між групами: Ви можете мати два обʼєкти з однаковим іменем, якщо вони належать до різних груп API (наприклад, apps та example.com).
  • Між версіями: Різні версії API (наприклад, v1 та v1beta1) однієї групи та ресурсу представляють ті самі базові дані. Створення обʼєкта з однаковим іменем в іншій версії тієї ж групи призводить до конфлікту імен, оскільки вони мають однакову ідентичність у сховищі.

Деякі обʼєкти не належать до простору імен (наприклад: Nodes), тому їхні імена повинні бути унікальними в межах усього кластера.

Дієслова API

Майже всі типи ресурсів обʼєктів підтримують стандартні HTTP-дієслова — GET, POST, PUT, PATCH та DELETE. Kubernetes також використовує власні дієслова, які часто пишуться малими літерами, щоб відрізняти їх від HTTP-дієслів.

Kubernetes використовує термін list для опису дії повернення колекції ресурсів, щоб відрізняти її від отримання одного ресурсу, яке зазвичай називається get. Якщо ви надішлете HTTP-запит GET із параметром запиту ?watch, Kubernetes називає це watch, а не get (див. Ефективне виявлення змін для деталей).

Запити PUT Kubernetes внутрішньо класифікує як create або update залежно від стану наявного обʼєкта. update відрізняється від patch; HTTP-дієслово для patch — PATCH.

URI ресурсів

Усі типи ресурсів або належать кластеру (/apis/GROUP/VERSION/*), або простору імен (/apis/GROUP/VERSION/namespaces/NAMESPACE/*). Тип ресурсу, що належить простору імен, буде видалений при видаленні простору імен, і доступ до цього типу ресурсу контролюється перевірками авторизації в межах простору імен.

Примітка: основні ресурси використовують /api замість /apis і пропускають сегмент шляху GROUP.

Приклади:

  • /api/v1/namespaces
  • /api/v1/pods
  • /api/v1/namespaces/my-namespace/pods
  • /apis/apps/v1/deployments
  • /apis/apps/v1/namespaces/my-namespace/deployments
  • /apis/apps/v1/namespaces/my-namespace/deployments/my-deployment

Ви також можете отримати доступ до колекцій ресурсів (наприклад, до переліку усіх Nodes). Для отримання колекцій та ресурсів використовуються такі шляхи:

  • Ресурси кластерного рівня:

    • GET /apis/GROUP/VERSION/RESOURCETYPE — повертає колекцію ресурсів вказаного типу ресурсу
    • GET /apis/GROUP/VERSION/RESOURCETYPE/NAME — повертає ресурс з імʼям NAME вказаного типу ресурсу
  • Ресурси рівня простору імен:

    • GET /apis/GROUP/VERSION/RESOURCETYPE — повертає колекцію всіх екземплярів вказаного типу ресурсу в усіх просторах імен
    • GET /apis/GROUP/VERSION/namespaces/NAMESPACE/RESOURCETYPE — повертає колекцію всіх екземплярів вказаного типу ресурсу в просторі імен NAMESPACE
    • GET /apis/GROUP/VERSION/namespaces/NAMESPACE/RESOURCETYPE/NAME — повертає екземпляр вказаного типу ресурсу з імʼям NAME в просторі імен NAMESPACE

Оскільки простір імен є типом ресурсу кластерного рівня, ви можете отримати перелік («колекцію») всіх просторів імен за допомогою GET /api/v1/namespaces та деталі про конкретний простір імен за допомогою GET /api/v1/namespaces/NAME.

  • Субресурс кластерного рівня: GET /apis/GROUP/VERSION/RESOURCETYPE/NAME/SUBRESOURCE
  • Субресурс рівня простору імен: GET /apis/GROUP/VERSION/namespaces/NAMESPACE/RESOURCETYPE/NAME/SUBRESOURCE

Підтримувані дієслова для кожного субресурсу будуть відрізнятися залежно від обʼєкта — див. довідник API для отримання додаткової інформації. Немає можливості отримати доступ до субресурсів через декілька ресурсів — зазвичай, якщо це стає необхідним, використовується новий віртуальний тип ресурсу.

HTTP медіатипи

Через HTTP Kubernetes підтримує кодування даних JSON, YAML, CBOR та Protobuf.

Типово Kubernetes повертає обʼєкти у серіалізації JSON, використовуючи медіатип application/json. Хоча JSON є типовим форматом, клієнти можуть запитувати відповідь у форматі YAML або використовувати ефективніше двійкове представлення Protobuf для кращої продуктивності у великих масштабах.

API Kubernetes реалізує стандартне узгодження типів вмісту HTTP: передача заголовка Accept у виклику GET вказує серверу спробувати повернути відповідь у бажаному для вас медіатипі. Якщо ви хочете надіслати обʼєкт у форматі Protobuf на сервер для запиту PUT або POST, вам необхідно відповідно встановити заголовок запиту Content-Type.

Якщо ви запитуєте доступний медіатип, API-сервер повертає відповідь з відповідним заголовком Content-Type; якщо жоден із запитаних медіатипів не підтримується, API-сервер повертає повідомлення про помилку 406 Not acceptable. Усі вбудовані типи ресурсів підтримують медіатип application/json.

Кодування колекцій частинами

Для кодування JSON та Protobuf Kubernetes реалізує власні кодувальники, які записують дані елемент за елементом. Ця функція не змінює вихідні дані, але дозволяє API-серверу уникати завантаження всієї відповіді LIST в памʼять. Слід уникати використання інших типів кодування (включно з форматованим представленням JSON) для великих колекцій ресурсів (>100MB), оскільки це може негативно вплинути на продуктивність.

Кодування ресурсів у форматі JSON

API Kubernetes типово використовує JSON для кодування тіла HTTP-повідомлень.

Наприклад:

  1. Отримати список усіх Podʼів у кластері без вказування бажаного формату

    GET /api/v1/pods
    
    200 OK
    Content-Type: application/json
    
    … JSON encoded collection of Pods (PodList object)
    
  2. Створити Pod, надіславши JSON на сервер та запросивши відповідь у форматі JSON.

    POST /api/v1/namespaces/test/pods
    Content-Type: application/json
    Accept: application/json
    … JSON encoded Pod object
    
    200 OK
    Content-Type: application/json
    
    {
      "kind": "Pod",
      "apiVersion": "v1",
      …
    }
    

Ви також можете запитувати в цьому кодуванні таблиці та лише метадані.

Кодування ресурсів у форматі YAML

Kubernetes також підтримує медіатип application/yaml як для запитів, так і для відповідей. YAML можна використовувати для визначення маніфестів Kubernetes та взаємодії з API.

Наприклад:

  1. Отримати список усіх Podʼів у кластері у форматі YAML

    GET /api/v1/pods
    Accept: application/yaml
    
    200 OK
    Content-Type: application/yaml
    
    … YAML encoded collection of Pods (PodList object)
    
  2. Створити Pod, надіславши дані у форматі YAML на сервер і запросивши відповідь у форматі YAML:

    POST /api/v1/namespaces/test/pods
    Content-Type: application/yaml
    Accept: application/yaml
    … YAML encoded Pod object
    
    200 OK
    Content-Type: application/yaml
    
    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
      …
    

Ви також можете запитувати в цьому кодуванні таблиці та лише метадані.

Кодування Kubernetes Protobuf

Kubernetes використовує обгортку-конверт для кодування відповідей у форматі Protobuf. Ця обгортка починається з 4-байтового магічного числа, щоб допомогти ідентифікувати вміст на диску або в etcd як Protobuf (на відміну від JSON). За 4-байтовим магічним числом слідує закодоване у форматі Protobuf повідомлення-обгортка, яке описує кодування та тип основного обʼєкта. Усередині повідомлення-обгортки Protobuf дані внутрішнього обʼєкта записуються за допомогою поля raw повідомлення Unknown (дивіться IDL для докладної інформації).

Наприклад:

  1. Отримати список усіх Podʼів у кластері у форматі Protobuf.

    GET /api/v1/pods
    Accept: application/vnd.kubernetes.protobuf
    
    200 OK
    Content-Type: application/vnd.kubernetes.protobuf
    
    … binary encoded collection of Pods (PodList object)
    
  2. Створити Pod, надіславши дані, закодовані у форматі Protobuf, на сервер, але запросити відповідь у форматі JSON.

    POST /api/v1/namespaces/test/pods
    Content-Type: application/vnd.kubernetes.protobuf
    Accept: application/json
    … binary encoded Pod object
    
    200 OK
    Content-Type: application/json
    
    {
      "kind": "Pod",
      "apiVersion": "v1",
      ...
    }
    

Ви можете використовувати обидві техніки разом і застосовувати кодування Protobuf Kubernetes для взаємодії з будь-яким API, яке його підтримує, як для читання, так і для запису. Лише деякі типи ресурсів API є сумісними з Protobuf.

Формат обгортки:

Префікс — чотирибайтове магічне число:
  Bytes 0-3: "k8s\x00" [0x6b, 0x38, 0x73, 0x00]

Закодоване повідомлення Protobuf з таким IDL:
  message Unknown {
    // typeMeta повинне містити рядкові значення для "kind" та "apiVersion", як вони встановлені в обʼєкті JSON
    optional TypeMeta typeMeta = 1;

    // raw містить повний серіалізований обʼєкт у форматі protobuf. Дивіться визначення protobuf у клієнтських бібліотеках для конкретного kind.
    optional bytes raw = 2;

    // contentEncoding — це кодування, яке використовується для даних raw. Якщо не вказано, кодування відсутнє.
    optional string contentEncoding = 3;

    // contentType — це метод серіалізації, який використовується для серіалізації 'raw'. Якщо не вказано, використовується application/vnd.kubernetes.protobuf, і зазвичай
    // цей параметр пропускається.
    optional string contentType = 4;
  }

  message TypeMeta {
    // apiVersion — це група/версія для цього типу
    optional string apiVersion = 1;
    // kind — це назва схеми обʼєкта. Для цього обʼєкта має існувати визначення protobuf.
    optional string kind = 2;
  }

Примітка:

Клієнти, які отримують відповідь у форматі application/vnd.kubernetes.protobuf, що не відповідає очікуваному префіксу, повинні відхилити відповідь, оскільки майбутні версії можуть змінити формат серіалізації несумісним чином і зроблять це шляхом зміни префікса.

Ви також можете запитувати в цьому кодуванні таблиці та лише метадані.

Сумісність із Kubernetes Protobuf

Не всі типи ресурсів API підтримують кодування Kubernetes Protobuf; зокрема, Protobuf недоступний для ресурсів, які визначені як CustomResourceDefinitions або надаються через рівень агрегації.

Як клієнт, якщо вам може знадобитися працювати з типами розширень, слід вказати кілька типів вмісту в заголовку запиту Accept для підтримки резервного переходу на JSON. Наприклад:

Accept: application/vnd.kubernetes.protobuf, application/json

Кодування ресурсів у форматі CBOR

СТАН ФУНКЦІОНАЛУ: Alpha since Kubernetes v1.32; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the CBORServingAndStorage feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

З увімкненою функціональною можливістю CBORServingAndStorage тіла запитів і відповідей для всіх вбудованих типів ресурсів і всіх ресурсів, визначених за допомогою CustomResourceDefinition, можуть бути закодовані у двійковий формат даних CBOR. CBOR також підтримується на рівні агрегації, якщо його увімкнено в окремих агрегованих API-серверах.

Клієнти повинні вказувати медіатип IANA application/cbor в заголовку HTTP-запиту Content-Type, коли тіло запиту містить один CBOR-закодований елемент даних, і в заголовку HTTP-запиту Accept, коли вони готові прийняти CBOR-кодований елемент даних у відповіді. API-сервери використовуватимуть application/cbor в заголовку HTTP-відповіді Content-Type, коли тіло відповіді містить CBOR-кодований обʼєкт.

Якщо API-сервер кодує свою відповідь на запит watch за допомогою CBOR, тіло відповіді буде послідовністю CBOR (CBOR Sequence), а в заголовку HTTP-відповіді Content-Type буде використано медіатип IANA application/cbor-seq. Кожен елемент послідовності (якщо такі є) є окремою CBOR-кодованою подією спостереження.

На додаток до наявного медіатипу application/apply-patch+yaml для YAML-кодованих конфігурацій server-side apply, API-сервери, у яких увімкнено CBOR, прийматимуть медіатип application/apply-patch+cbor для CBOR-кодованих конфігурацій server-side apply. Для application/json-patch+json або application/merge-patch+json, або application/strategic-merge-patch+json немає підтримуваного еквівалента в CBOR.

Ви також можете запитувати в цьому кодуванні таблиці та лише метадані.

Ефективне виявлення змін

API Kubernetes дозволяє клієнтам зробити початковий запит на обʼєкт або колекцію, а потім відстежувати зміни з моменту цього початкового запиту: це watch. Клієнти можуть надіслати list або get, а потім зробити наступний запит watch.

Для реалізації цього відстеження змін кожен обʼєкт Kubernetes має поле resourceVersion, яке представляє версію цього ресурсу, що зберігається в базовому шарі постійного зберігання. При отриманні колекції ресурсів (як рівня простору імен, так і кластерного рівня) відповідь від API-сервера містить значення resourceVersion. Клієнт може використовувати це значення resourceVersion для ініціювання watch до API-сервера.

Коли ви надсилаєте запит watch, API-сервер відповідає потоком змін. Ці зміни перераховують результати операцій (таких як create, delete та update), що відбулися після resourceVersion, значення якого було вказане як параметр запиту watch. Загальний механізм watch дозволяє клієнту отримати поточний стан, а потім підписатися на подальші зміни, не пропускаючи жодної події.

Якщо watch клієнта відʼєднується, цей клієнт може розпочати новий watch з останнього повернутого resourceVersion; клієнт також може виконати новий запит get / list і почати знову. Див. Семантика версій ресурсів для отримання детальнішої інформації.

Наприклад:

  1. Отримати список усіх Podʼів у вказаному просторі імен.

    GET /api/v1/namespaces/test/pods
    ---
    200 OK
    Content-Type: application/json
    
    {
      "kind": "PodList",
      "apiVersion": "v1",
      "metadata": {"resourceVersion":"10245"},
      "items": [...]
    }
    
  2. Починаючи з версії ресурсу 10245, отримувати сповіщення про будь-які операції API (такі як create, delete, patch або update), що впливають на Podʼи у просторі імен test. Кожне сповіщення про зміну — це документ JSON. Тіло HTTP-відповіді (надається як application/json) складається із серії документів JSON.

    GET /api/v1/namespaces/test/pods?watch=1&resourceVersion=10245
    ---
    200 OK
    Transfer-Encoding: chunked
    Content-Type: application/json
    
    {
      "type": "ADDED",
      "object": {"kind": "Pod", "apiVersion": "v1", "metadata": {"resourceVersion": "10596", ...}, ...}
    }
    {
      "type": "MODIFIED",
      "object": {"kind": "Pod", "apiVersion": "v1", "metadata": {"resourceVersion": "11020", ...}, ...}
    }
    ...
    

Сервер Kubernetes зберігає історичний запис змін лише протягом обмеженого часу. Кластери, що використовують etcd 3, типово зберігають зміни за останні 5 хвилин. Коли запитувані операції watch не вдаються через недоступність історичної версії цього ресурсу, клієнти повинні обробляти цей випадок, розпізнаючи код статусу 410 Gone, очищаючи свій локальний кеш, виконуючи нову операцію get або list і починаючи watch з resourceVersion, яке було повернуто.

Для підписки на колекції клієнтські бібліотеки Kubernetes зазвичай пропонують певну форму стандартного інструменту для логіки «спочатку list, потім watch». (У клієнтській бібліотеці Go це називається Reflector і знаходиться в пакеті k8s.io/client-go/tools/cache.)

Закладки спостереження

Щоб зменшити вплив короткого вікна історії, API Kubernetes надає подію спостереження під назвою BOOKMARK (закладка). Це особливий вид події, що позначає, що всі зміни до вказаної клієнтом resourceVersion вже були надіслані. Документ, що представляє подію BOOKMARK, має тип, який запитується запитом, але містить лише поле .metadata.resourceVersion. Наприклад:

GET /api/v1/namespaces/test/pods?watch=1&resourceVersion=10245&allowWatchBookmarks=true
---
200 OK
Transfer-Encoding: chunked
Content-Type: application/json

{
  "type": "ADDED",
  "object": {"kind": "Pod", "apiVersion": "v1", "metadata": {"resourceVersion": "10596", ...}, ...}
}
...
{
  "type": "BOOKMARK",
  "object": {"kind": "Pod", "apiVersion": "v1", "metadata": {"resourceVersion": "12746"} }
}

Як клієнт, ви можете запитувати події BOOKMARK, встановлюючи параметр запиту allowWatchBookmarks=true у запиті watch, але не слід припускати, що закладки повертатимуться з певним інтервалом, і клієнти не можуть очікувати, що API-сервер надішле будь-яку подію BOOKMARK, навіть якщо її було запитано.

Потокові списки

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.34; (стандартно увімкнено)

У великих кластерах отримання колекції деяких типів ресурсів може призвести до значного збільшення використання ресурсів (переважно RAM) панелі управління. Щоб зменшити вплив і спростити використання шаблону list + watch, у Kubernetes v1.32 переведено в бета-версію функцію, яка дозволяє запитувати початковий стан (який раніше запитувався за допомогою запиту list) як частину запиту watch.

На боці клієнта початковий стан можна запросити, вказавши sendInitialEvents=true як параметр рядка запиту в запиті watch. Якщо його встановлено, API-сервер починає потік спостереження із синтетичних початкових подій (типу ADDED) для побудови всього стану всіх наявних обʼєктів, після чого йде подія BOOKMARK (якщо її запитано через параметр allowWatchBookmarks=true). Подія закладки містить версію ресурсу, до якої виконано синхронізацію. Після надсилання події закладки API-сервер продовжує роботу як для будь-якого іншого запиту watch.

Коли ви встановлюєте sendInitialEvents=true у рядку запиту, Kubernetes також вимагає, щоб ви встановили для resourceVersionMatch значення NotOlderThan. Якщо ви вказали resourceVersion у рядку запиту без значення або не вказали його взагалі, це інтерпретується як запит на узгоджене читання (consistent read); подія закладки надсилається, коли стан синхронізовано щонайменше до моменту узгодженого читання з часу, коли запит почав оброблятися. Якщо ви вказуєте resourceVersion (у рядку запиту), подія закладки надсилається, коли стан синхронізовано щонайменше до вказаної версії ресурсу.

Приклад

Приклад: ви хочете спостерігати за колекцією Podʼів. Для цієї колекції поточна версія ресурсу становить 10245, і є два Podʼи: foo та bar. Надсилання наступного запиту (який явно запитує узгоджене читання, встановлюючи порожню версію ресурсу за допомогою resourceVersion=) може призвести до такої послідовності подій:

GET /api/v1/namespaces/test/pods?watch=1&sendInitialEvents=true&allowWatchBookmarks=true&resourceVersion=&resourceVersionMatch=NotOlderThan
---
200 OK
Transfer-Encoding: chunked
Content-Type: application/json

{
  "type": "ADDED",
  "object": {"kind": "Pod", "apiVersion": "v1", "metadata": {"resourceVersion": "8467", "name": "foo"}, ...}
}
{
  "type": "ADDED",
  "object": {"kind": "Pod", "apiVersion": "v1", "metadata": {"resourceVersion": "5726", "name": "bar"}, ...}
}
{
  "type": "BOOKMARK",
  "object": {"kind": "Pod", "apiVersion": "v1", "metadata": {"resourceVersion": "10245"} }
}
...
<followed by regular watch stream starting from resourceVersion="10245">

Фрагментовані list і watch

СТАН ФУНКЦІОНАЛУ: Alpha since Kubernetes v1.36; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the ShardedListAndWatch feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

У великих кластерах контролери, які спостерігають за типами ресурсів з високою кардинальністю (наприклад, Pod або Endpoints), можуть споживати значну частину пропускної здатності мережі та CPU, отримуючи та десеріалізуючи повний потік подій, навіть якщо їм потрібна лише підмножина обʼєктів. Фрагментовані list і watch дозволяють горизонтально масштабованим контролерам розподіляти навантаження так, щоб кожна репліка отримувала лише ті події, за які вона відповідає.

Kubernetes 1.37 впроваджує альфа-функцію, яка дозволяє клієнтам запитувати з API-сервера відфільтрований фрагмент обʼєктів, використовуючи розбиття на основі хешування полів метаданих. Щоб використовувати цю функцію, увімкніть на API-сервері функціональну можливість ShardedListAndWatch. Коли її увімкнено, API-сервер фільтрує як відповіді на list, так і потоки подій watch на боці сервера, доставляючи лише ті обʼєкти та події, хешоване значення метаданих яких потрапляє в запитаний діапазон.

Поле shardSelector

Поле ShardSelector у ListOptions приймає вираз на основі CEL з використанням функції shardRange():

shardRange(<field-path>, '<hex-start>', '<hex-end>')

Де:

  • <field-path> — це поле метаданих, яке потрібно хешувати, у синтаксисі в стилі CEL з коренем в обʼєкті. Наразі підтримуються такі шляхи:
    • object.metadata.uid
    • object.metadata.namespace
  • <hex-start> — включна нижня межа діапазону хешу у вигляді 16-значного шістнадцяткового рядка в нижньому регістрі з префіксом 0x (наприклад, '0x0000000000000000').
  • <hex-end> — виключна верхня межа у вигляді шістнадцяткового рядка з префіксом 0x. Максимальне значення — '0x10000000000000000' (2^64).

API-сервер обчислює детермінований 64-бітний хеш FNV-1a вказаного значення поля і повертає лише ті обʼєкти, хеш яких потрапляє в діапазон [start, end). Функція хешування дає однаковий результат для одного й того самого вхідного значення на всіх екземплярах API-сервера, тому фрагментовані запити безпечно використовувати з кількома репліками API-сервера.

Ви можете комбінувати кілька діапазонів за допомогою || (логічне АБО), щоб охопити несуміжні частини простору хешів. Усі діапазони в одному виразі повинні використовувати той самий шлях до поля.

Використання фрагментованих list і watch у контролерах

Контролери зазвичай використовують інформери для отримання списку ресурсів і спостереження за ними. Щоб розподілити навантаження між репліками, кожна репліка вставляє поле ShardSelector у ListOptions, які використовуються її інформерами.

Стандартний спосіб зробити це — використовувати WithTweakListOptions при створенні спільної фабрики інформерів. Функція коригування виконується перед кожним викликом list і watch, який робить інформер, тому селектор фрагментів застосовується послідовно:

import (
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/informers"
)

// shardSelector визначається ідентичністю репліки (наприклад, з порядкового номера
// StatefulSet або призначення на основі lease). Кожна репліка отримує
// діапазон простору хешів, що не перетинається з іншими.
shardSelector := "shardRange(object.metadata.uid, '0x0000000000000000', '0x8000000000000000')"

factory := informers.NewSharedInformerFactoryWithOptions(client, resyncPeriod,
    informers.WithTweakListOptions(func(opts *metav1.ListOptions) {
        opts.ShardSelector = shardSelector
    }),
)

З цією конфігурацією кожен інформер, створений фабрикою, отримує список і спостерігає лише за тими обʼєктами, хешований UID яких потрапляє в призначений діапазон. Кожна репліка отримує неперетинну підмножину повної колекції, що зменшує мережевий трафік і використання памʼяті на кожну репліку.

Для розгортання з 2 репліками селектори будуть такими:

// Репліка 0: нижня половина простору хешів
"shardRange(object.metadata.uid, '0x0000000000000000', '0x8000000000000000')"

// Репліка 1: верхня половина простору хешів
"shardRange(object.metadata.uid, '0x8000000000000000', '0x10000000000000000')"

Одна репліка також може обробляти несуміжні діапазони, використовуючи ||:

"shardRange(object.metadata.uid, '0x0000000000000000', '0x4000000000000000') || " +
    "shardRange(object.metadata.uid, '0x8000000000000000', '0xc000000000000000')"

Інформація про фрагменти у відповідях

Коли API-сервер враховує ShardSelector, відповідь на list містить поле shardInfo у metadata списку. Воно повертає селектор, щоб клієнти могли перевірити, який фрагмент вони отримали. Для потоків watch селектор фрагментів застосовується так само: API-сервер надсилає події лише для обʼєктів, хеш яких потрапляє в запитаний діапазон.

{
  "kind": "PodList",
  "apiVersion": "v1",
  "metadata": {
    "resourceVersion": "10245",
    "shardInfo": {
      "selector": "shardRange(object.metadata.uid, '0x0000000000000000', '0x8000000000000000')"
    }
  },
  "items": [...]
}

Примітка:

Відповідь на list, що містить shardInfo, представляє відфільтровану підмножину повної колекції. Клієнти не повинні розглядати фрагментовані відповіді на list як повне представлення типу ресурсу.

Виявлення підтримки сервером

Якщо API-сервер не підтримує фрагментовані list і watch (через те, що функціональну можливість не увімкнено, або сервер має старішу версію), поле ShardSelector ігнорується, і сервер повертає повний, нефільтрований набір результатів. Клієнти можуть виявити це, перевіривши наявність shardInfo у метаданих відповіді на list. Якщо shardInfo відсутнє, сервер не врахував селектор фрагментів, і клієнт отримав повну, нефільтровану колекцію. У цьому випадку клієнт повинен бути готовий обробляти повний набір результатів, наприклад, застосовуючи фільтрацію на боці клієнта, щоб відкинути обʼєкти поза призначеним йому діапазоном фрагментів.

Стиснення відповідей

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.16; (стандартно увімкнено)

APIResponseCompression — це опція, яка дозволяє API-серверу стискати відповіді на запити get та list, зменшуючи використання пропускної здатності мережі та покращуючи продуктивність великих кластерів. Її типово увімкнено з Kubernetes 1.16, і її можна вимкнути, додавши APIResponseCompression=false у прапорець --feature-gates на API-сервері.

Стиснення відповідей API може значно зменшити розмір відповіді, особливо для великих ресурсів або колекцій. Наприклад, запит list для Podʼів може повернути сотні кілобайт або навіть мегабайти даних, залежно від кількості Podʼів та їхніх атрибутів. Стиснення відповіді дозволяє заощадити пропускну здатність мережі та зменшити затримку.

Щоб перевірити, чи працює APIResponseCompression, ви можете надіслати запит get або list до API-сервера із заголовком Accept-Encoding і перевірити розмір відповіді та заголовки. Наприклад:

GET /api/v1/pods
Accept-Encoding: gzip
---
200 OK
Content-Type: application/json
content-encoding: gzip
...

Заголовок content-encoding вказує, що відповідь стиснута за допомогою gzip.

Отримання великих наборів результатів частинами

This is a stable feature in Kubernetes, and has been since the 1.29 release. You can no longer toggle this feature (the associated feature gate has been removed).

У великих кластерах отримання колекції деяких типів ресурсів може призвести до дуже великих відповідей, що може вплинути на сервер і клієнта. Наприклад, у кластері можуть бути десятки тисяч Podʼів, кожен з яких відповідає приблизно 2 КіБ закодованого JSON. Отримання всіх Podʼів в усіх просторах імен може призвести до дуже великої відповіді (10-20 МБ) і спожити багато ресурсів сервера.

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

Ви можете запросити, щоб API-сервер обробляв list, надаючи одну колекцію сторінками (які Kubernetes називає chunks — частинами). Щоб отримати одну колекцію частинами, у запитах до колекцій підтримуються два параметри запиту limit та continue, а поле відповіді continue повертається з усіх операцій list у полі metadata колекції. Клієнт повинен вказати максимальну кількість результатів, яку він бажає отримати в кожній частині, за допомогою limit, і сервер поверне в результаті не більше limit ресурсів та включить значення continue, якщо в колекції є ще ресурси.

Як клієнт API, ви можете передати це значення continue API-серверу в наступному запиті, щоб вказати серверу повернути наступну сторінку (частину) результатів. Продовжуючи доти, доки сервер не поверне порожнє значення continue, ви можете отримати всю колекцію.

Як і у випадку з операцією watch, термін дії токена continue спливає через короткий проміжок часу (типово 5 хвилин), і повертається 410 Gone, якщо більше результатів не може бути повернуто. У цьому випадку клієнту потрібно буде почати спочатку або пропустити параметр limit.

Наприклад, якщо в кластері є 1253 Podʼи і ви хочете отримувати частини по 500 Podʼів за раз, запитуйте ці частини таким чином:

  1. Отримати список усіх Podʼів у кластері, отримуючи до 500 Podʼів за раз.

    GET /api/v1/pods?limit=500
    ---
    200 OK
    Content-Type: application/json
    
    {
      "kind": "PodList",
      "apiVersion": "v1",
      "metadata": {
        "resourceVersion":"10245",
        "continue": "ENCODED_CONTINUE_TOKEN",
        "remainingItemCount": 753,
        ...
      },
      "items": [...] // повертає Podʼи 1-500
    }
    
  2. Продовжити попередній виклик, отримуючи наступний набір з 500 Podʼів.

    GET /api/v1/pods?limit=500&continue=ENCODED_CONTINUE_TOKEN
    ---
    200 OK
    Content-Type: application/json
    
    {
      "kind": "PodList",
      "apiVersion": "v1",
      "metadata": {
        "resourceVersion":"10245",
        "continue": "ENCODED_CONTINUE_TOKEN_2",
        "remainingItemCount": 253,
        ...
      },
      "items": [...] // повертає Podʼи 501-1000
    }
    
  3. Продовжити попередній виклик, отримуючи останні 253 Podʼи.

    GET /api/v1/pods?limit=500&continue=ENCODED_CONTINUE_TOKEN_2
    ---
    200 OK
    Content-Type: application/json
    
    {
      "kind": "PodList",
      "apiVersion": "v1",
      "metadata": {
        "resourceVersion":"10245",
        "continue": "", // токен continue порожній, тому що ми досягли кінця списку
        ...
      },
      "items": [...] // повертає Podʼи 1001-1253
    }
    

Зверніть увагу, що resourceVersion колекції залишається незмінним у кожному запиті, що вказує на те, що сервер показує вам узгоджений знімок Podʼів. Podʼи, що створюються, оновлюються або видаляються після версії 10245, не будуть показані, якщо ви не зробите окремий запит list без токена continue. Це дозволяє вам розбивати великі запити на менші частини, а потім виконувати операцію watch для повного набору, не пропускаючи жодного оновлення.

remainingItemCount — це кількість наступних елементів у колекції, які не включені в цю відповідь. Якщо запит list містив селектори міток або полів, тоді кількість решти елементів невідома, і API-сервер не включає поле remainingItemCount у свою відповідь. Якщо list завершено (або тому, що отримання частинами не використовується, або тому, що це остання частина), то елементів більше не залишилося, і API-сервер не включає поле remainingItemCount у свою відповідь. Призначення remainingItemCount — оцінка розміру колекції.

Колекції

У термінології Kubernetes відповідь, яку ви отримуєте від list, є колекцією. Однак Kubernetes визначає конкретні види (kind) для колекцій різних типів ресурсів. Колекції мають вид, названий за видом ресурсу, з доданим List.

Коли ви надсилаєте запит до API для певного типу, всі елементи, повернуті цим запитом, мають цей тип. Наприклад, коли ви виконуєте list для Services, відповідь-колекція має kind, встановлений у ServiceList; кожен елемент у цій колекції представляє один Service. Наприклад:

GET /api/v1/services
{
  "kind": "ServiceList",
  "apiVersion": "v1",
  "metadata": {
    "resourceVersion": "2947301"
  },
  "items": [
    {
      "metadata": {
        "name": "kubernetes",
        "namespace": "default",
...
      "metadata": {
        "name": "kube-dns",
        "namespace": "kube-system",
...

В API Kubernetes визначено десятки типів колекцій (таких як PodList, ServiceList та NodeList). Більше інформації про кожен тип колекції можна отримати з документації API Kubernetes.

Деякі інструменти, такі як kubectl, представляють механізм колекцій Kubernetes трохи інакше, ніж сам API Kubernetes. Оскільки вивід kubectl може включати відповіді кількох операцій list на рівні API, kubectl представляє список елементів, використовуючи kind: List. Наприклад:

kubectl get services -A -o yaml
apiVersion: v1
kind: List
metadata:
  resourceVersion: ""
  selfLink: ""
items:
- apiVersion: v1
  kind: Service
  metadata:
    creationTimestamp: "2021-06-03T14:54:12Z"
    labels:
      component: apiserver
      provider: kubernetes
    name: kubernetes
    namespace: default
...
- apiVersion: v1
  kind: Service
  metadata:
    annotations:
      prometheus.io/port: "9153"
      prometheus.io/scrape: "true"
    creationTimestamp: "2021-06-03T14:54:14Z"
    labels:
      k8s-app: kube-dns
      kubernetes.io/cluster-service: "true"
      kubernetes.io/name: CoreDNS
    name: kube-dns
    namespace: kube-system

Примітка:

Памʼятайте, що API Kubernetes не має kind з назвою List.

kind: List — це внутрішня деталь реалізації на боці клієнта для обробки колекцій, які можуть містити обʼєкти різних видів. Уникайте залежності від kind: List в автоматизації або іншому коді.

Отримання ресурсів у вигляді таблиць

Коли ви запускаєте kubectl get, типовим форматом виводу є просте табличне представлення одного або кількох екземплярів певного типу ресурсу. У минулому клієнти повинні були відтворювати табличний і описовий вивід, реалізований у kubectl, щоб виконувати прості переліки обʼєктів. Серед обмежень цього підходу — нетривіальна логіка при роботі з певними обʼєктами. Крім того, типи, що надаються через агрегацію API або сторонні ресурси, невідомі під час компіляції. Це означає, що для типів, які не розпізнаються клієнтом, мали бути загальні реалізації.

Щоб уникнути можливих обмежень, описаних вище, клієнти можуть запитувати табличне представлення обʼєктів (Table), делегуючи серверу конкретні деталі виводу. API Kubernetes реалізує стандартне узгодження типів вмісту HTTP: передача заголовка Accept, що містить значення application/json;as=Table;g=meta.k8s.io;v=v1, з викликом GET попросить сервер повернути обʼєкти з типом вмісту Table.

Наприклад, отримати список усіх Podʼів у кластері у форматі Table.

GET /api/v1/pods
Accept: application/json;as=Table;g=meta.k8s.io;v=v1
---
200 OK
Content-Type: application/json

{
    "kind": "Table",
    "apiVersion": "meta.k8s.io/v1",
    ...
    "columnDefinitions": [
        ...
    ]
}

Для типів ресурсів API, які не мають власного визначення Table, відомого панелі управління, API-сервер повертає типову відповідь Table, яка складається з полів name та creationTimestamp ресурсу.

GET /apis/crd.example.com/v1alpha1/namespaces/default/resources
---
200 OK
Content-Type: application/json
...

{
    "kind": "Table",
    "apiVersion": "meta.k8s.io/v1",
    ...
    "columnDefinitions": [
        {
            "name": "Name",
            "type": "string",
            ...
        },
        {
            "name": "Created At",
            "type": "date",
            ...
        }
    ]
}

Не всі типи ресурсів API підтримують відповідь Table; наприклад, CustomResourceDefinitions можуть не визначати відповідність полів таблиці, а APIService, що розширює основний API Kubernetes, може взагалі не надавати відповіді Table. Якщо ви створюєте клієнта, що використовує інформацію Table і повинен працювати з усіма типами ресурсів, включно з розширеннями, вам слід робити запити, які вказують кілька типів вмісту в заголовку Accept. Наприклад:

Accept: application/json;as=Table;g=meta.k8s.io;v=v1, application/json

Якщо клієнт вказує, що приймає тільки ...;as=Table;g=meta.k8s.io;v=v1, сервери, які не підтримують табличні відповіді, повернуть код помилки 406.

Якщо в цьому випадку бажано повернутися до повних обʼєктів, клієнти можуть додати ,application/json (або будь-яке інше підтримуване кодування) до свого заголовка Accept і обробляти у відповіді як таблиці, так і повні обʼєкти:

Accept: application/json;as=Table;g=meta.k8s.io;v=v1,application/json`

Для отримання додаткової інформації про узгодження типу вмісту див. MDN Content Negotiation.

Отримання лише метаданих

Щоб отримати часткові метадані обʼєкта, ви можете запросити відповіді лише з метаданими в заголовку Accept. API Kubernetes реалізує варіант узгодження типу вмісту HTTP. Як клієнт, ви можете надати заголовок Accept з бажаним медіатипом, а також параметрами, які вказують, що ви хочете отримати лише метадані. Наприклад: Accept: application/json;as=PartialObjectMetadata;g=meta.k8s.io;v=v1 для JSON для конкретного обʼєкта та Accept: application/json;as=PartialObjectMetadataList;g=meta.k8s.io;v=v1 для списку.

Примітка:

as=PartialObjectMetadata слід використовувати в запитах до конкретних ресурсів, а as=PartialObjectMetadataList — для запитів list.

Наприклад, щоб отримати список усіх Podʼів у кластері, в усіх просторах імен, але повернути лише метадані для кожного Podʼа:

GET /api/v1/pods
Accept: application/json;as=PartialObjectMetadataList;g=meta.k8s.io;v=v1
---
200 OK
Content-Type: application/json

{
    "kind": "PartialObjectMetadataList",
    "apiVersion": "meta.k8s.io/v1",
    "metadata": {
        "resourceVersion": "...",
    },
    "items": [
        {
            "apiVersion": "meta.k8s.io/v1",
            "kind": "PartialObjectMetadata",
            "metadata": {
                "name": "pod-1",
                ...
            }
        },
        {
            "apiVersion": "meta.k8s.io/v1",
            "kind": "PartialObjectMetadata",
            "metadata": {
                "name": "pod-2",
                ...
            }
        }
    ]
}

На запит колекції API-сервер повертає PartialObjectMetadataList. На запит окремого обʼєкта API-сервер повертає представлення PartialObjectMetadata цього обʼєкта. В обох випадках повернуті обʼєкти містять лише поле metadata. Поля spec та status пропускаються.

Ця функція корисна для клієнтів, яким потрібно лише перевірити наявність обʼєкта або лише прочитати його метадані. Вона може значно зменшити розмір відповіді від API-сервера.

Ви можете запросити отримання лише метаданих для всіх доступних медіатипів (JSON, YAML, CBOR і Kubernetes Protobuf). Для Protobuf заголовок Accept буде таким: application/vnd.kubernetes.protobuf;as=PartialObjectMetadata;g=meta.k8s.io;v=v1.

API-сервер Kubernetes підтримує часткове отримання майже для всіх своїх вбудованих API. Однак ви можете використовувати Kubernetes для доступу до інших API-серверів через рівень агрегації, і ці API можуть не підтримувати часткове отримання.

Якщо клієнт використовує заголовок Accept, щоб запросити лише відповідь ...;as=PartialObjectMetadata;g=meta.k8s.io;v=v1, і звертається до API, який не підтримує часткові відповіді, Kubernetes відповідає помилкою HTTP 406.

Якщо в цьому випадку бажано повернутися до повних обʼєктів, клієнти можуть додати ,application/json (або будь-яке інше підтримуване кодування) до свого заголовка Accept і обробляти у відповіді або PartialObjectMetadata, або повні обʼєкти. Варто вказати, що перевага надається частковій відповіді, використовуючи параметр q (quality — якість). Наприклад:

Accept: application/json;as=PartialObjectMetadata;g=meta.k8s.io;v=v1, application/json;q=0.9

Для отримання додаткової інформації про узгодження типу вмісту див. MDN Content Negotiation.

Видалення ресурсів

Коли ви виконуєте delete для ресурсу, цей процес проходить у два етапи.

  1. завершення (finalization)
  2. вилучення (removal)
{
  "kind": "ConfigMap",
  "apiVersion": "v1",
  "metadata": {
    "finalizers": ["url.io/neat-finalization", "other-url.io/my-finalizer"],
    "deletionTimestamp": nil,
  }
}

Коли клієнт вперше надсилає delete, щоб запросити вилучення ресурсу, .metadata.deletionTimestamp встановлюється на поточний час. Після встановлення .metadata.deletionTimestamp зовнішні контролери, які працюють із завершувачами (finalizers), можуть почати виконувати свою роботу з очищення в будь-який час, у будь-якому порядку.

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

Поле .metadata.finalizers є спільним: будь-який учасник із відповідним дозволом може змінювати його порядок. Якби список завершувачів оброблявся по порядку, це могло б призвести до ситуації, коли компонент, відповідальний за перший завершувач у списку, чекає на якийсь сигнал (значення поля, зовнішню систему або інше), що створюється компонентом, відповідальним за завершувач, розташований далі у списку, що призводить до взаємного блокування.

Без примусового впорядкування завершувачі можуть вільно впорядковуватися між собою і не є вразливими до змін порядку у списку.

Після вилучення останнього завершувача ресурс фактично видаляється з etcd.

Примусове видалення

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.37; (стандартно увімкнено)

Увага:

Це може порушити роботу робочого навантаження, повʼязаного з ресурсом, який видаляється примусово, якщо воно покладається на звичайний процес видалення, тому можливі наслідки, що порушують роботу кластера.

Увімкнувши опцію видалення ignoreStoreReadErrorWithClusterBreakingPotential, користувач може виконати небезпечну операцію примусового delete для ресурсу, який неможливо розшифрувати або який пошкоджено. Ця опція доступна, коли увімкнено функціональну можливість AllowUnsafeMalformedObjectDeletion, що є типовим, починаючи з Kubernetes v1.37. Оператор кластера може вимкнути цю поведінку, встановивши параметр командного рядка --feature-gates=AllowUnsafeMalformedObjectDeletion=false.

Примітка:

Користувач, який виконує операцію примусового delete, повинен мати привілеї на виконання обох дієслів delete і unsafe-delete-ignore-read-errors для цього ресурсу.

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

  • помилку перетворення (наприклад, помилку розшифрування), або
  • невдале декодування обʼєкта.

API-сервер спочатку намагається виконати звичайне видалення, і якщо воно завершується помилкою пошкодженого ресурсу (corrupt resource), він запускає примусове видалення. Операція примусового delete є небезпечною, оскільки вона ігнорує обмеження завершувачів і пропускає перевірку передумов.

Типове значення для цієї опції — false, що забезпечує зворотну сумісність. Для запиту delete з параметром ignoreStoreReadErrorWithClusterBreakingPotential, встановленим у true, поля dryRun, gracePeriodSeconds, orphanDependents, preconditions і propagationPolicy слід залишити не встановленими.

Примітка:

Якщо користувач надсилає запит delete з ignoreStoreReadErrorWithClusterBreakingPotential, встановленим у true, для ресурсу, який в іншому разі можна прочитати, API-сервер перериває запит з помилкою.

API для одного ресурсу

Дієслова API Kubernetes get, create, update, patch, delete та proxy підтримують лише окремі ресурси. Ці дієслова з підтримкою окремих ресурсів не підтримують надсилання кількох ресурсів разом в упорядкованому або неупорядкованому списку чи транзакції.

Коли клієнти (включно з kubectl) виконують дії з набором ресурсів, клієнт робить серію API-запитів до окремих ресурсів, а потім, за потреби, агрегує відповіді.

На відміну від цього, дієслова API Kubernetes list і watch дозволяють отримувати кілька ресурсів, а deletecollection дозволяє видаляти кілька ресурсів.

Валідація полів

Kubernetes завжди перевіряє тип полів. Наприклад, якщо поле в API визначене як число, ви не можете встановити для нього текстове значення. Якщо поле визначене як масив рядків, ви можете надати лише масив. Деякі поля можна пропустити, інші поля є обовʼязковими. Пропуск обовʼязкового поля в запиті API є помилкою.

Якщо ви зробите запит з додатковим полем, яке не розпізнається панеллю управління кластера, тоді поведінка API-сервера складніша.

Типово API-сервер відкидає поля, які він не розпізнає, з отриманих вхідних даних (наприклад, з тіла JSON запиту PUT).

Є дві ситуації, коли API-сервер відкидає поля, які ви надали в HTTP-запиті.

Ці ситуації такі:

  1. Поле не розпізнається, оскільки воно не входить до схеми OpenAPI ресурсу. (Винятком є CRD, які явно обирають не обрізати невідомі поля через x-kubernetes-preserve-unknown-fields).
  2. Поле дублюється в обʼєкті.

Валідація нерозпізнаних або дубльованих полів

This is a stable feature in Kubernetes, and has been since the 1.27 release. You can no longer toggle this feature (the associated feature gate has been removed).

Починаючи з версії 1.25, нерозпізнані або дубльовані поля в обʼєкті виявляються через валідацію на сервері, коли ви використовуєте HTTP-дієслова, які можуть надсилати дані (POST, PUT та PATCH). Можливі рівні валідації: Ignore, Warn (типово) та Strict.

Ignore
API-сервер успішно обробляє запит так, ніби помилкові поля не були встановлені, відкидаючи всі невідомі та дубльовані поля і жодним чином не повідомляючи про це.
Warn
(Типово) API-сервер успішно обробляє запит і надсилає клієнту попередження. Попередження надсилається за допомогою заголовка відповіді Warning:, додаючи один елемент попередження для кожного невідомого або дубльованого поля. Для отримання додаткової інформації про попередження та API Kubernetes дивіться статтю блогу Warning: Helpful Warnings Ahead.
Strict
API-сервер відхиляє запит з помилкою 400 Bad Request, коли виявляє будь-які невідомі або дубльовані поля. Повідомлення відповіді від API-сервера вказує всі невідомі або дубльовані поля, які виявив API-сервер.

Рівень валідації полів встановлюється параметром запиту fieldValidation.

Примітка:

Якщо ви надсилаєте запит, у якому вказано нерозпізнане поле і який також є недійсним з іншої причини (наприклад, запит надає рядкове значення там, де API очікує ціле число для відомого поля), тоді API-сервер відповідає помилкою 400 Bad Request, але не надає жодної інформації про невідомі або дубльовані поля (лише про ту фатальну помилку, яку він виявив першою).

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

Інструменти, які надсилають запити на сервер (такі як kubectl), можуть встановлювати власні типові значення, які відрізняються від рівня валідації Warn, що типово використовується API-сервером.

Інструмент kubectl використовує прапорець --validate для встановлення рівня валідації полів. Він приймає значення ignore, warn та strict, а також значення true (еквівалентно strict) і false (еквівалентно ignore). Типове налаштування валідації для kubectl — --validate=true, що означає сувору валідацію полів на боці сервера.

Коли kubectl не може підключитися до API-сервера з валідацією полів (API-сервери до Kubernetes 1.27), він повертається до використання валідації на боці клієнта. Валідацію на боці клієнта буде повністю вилучено в майбутній версії kubectl.

Примітка:

До Kubernetes 1.25 kubectl --validate використовувався як булевий прапорець для увімкнення або вимкнення валідації на боці клієнта.

Починаючи з v1.33, Kubernetes (включно з v1.37) пропонує спосіб визначення валідації полів за допомогою декларативних теґів. Це корисно для тих, хто бере участь у розробці самого Kubernetes, а також актуально, якщо ви пишете власний API з використанням бібліотек Kubernetes. Щоб дізнатися більше, див. Декларативна валідація API.

Пробний запуск (dry-run)

This is a stable feature in Kubernetes, and has been since the 1.19 release. You can no longer toggle this feature (the associated feature gate has been removed).

Коли ви використовуєте HTTP-дієслова, які можуть змінювати ресурси (POST, PUT, PATCH і DELETE), ви можете надіслати свій запит у режимі пробного запуску (dry run). Режим пробного запуску допомагає оцінити запит на типових етапах обробки запиту (ланцюжок допуску, валідація, конфлікти злиття) аж до збереження обʼєктів у сховищі. Тіло відповіді на запит максимально наближене до відповіді на звичайний запит (без пробного запуску). Kubernetes гарантує, що запити пробного запуску не будуть збережені в сховищі і не матимуть жодних інших побічних ефектів.

Виконання запиту пробного запуску

Пробний запуск активується встановленням параметра запиту dryRun. Цей параметр є рядком, працює як перелік (enum), і єдині прийнятні значення:

[значення не встановлено]
Дозволити побічні ефекти. Ви запитуєте це за допомогою рядка запиту на кшталт ?dryRun або ?dryRun&pretty=true. Відповіддю є остаточний обʼєкт, який було б збережено, або помилка, якщо запит не може бути виконаний.
All
Кожен етап виконується як зазвичай, за винятком кінцевого етапу збереження, де побічним ефектам запобігають.

Коли ви встановлюєте ?dryRun=All, усі відповідні контролери допуску виконуються, контролери допуску з валідацією перевіряють запит після мутації, для PATCH виконується злиття, полям встановлюються типові значення, і проводиться валідація схеми. Зміни не зберігаються в базовому сховищі, але остаточний обʼєкт, який було б збережено, все одно повертається користувачеві разом зі звичайним кодом статусу.

Якщо звичайна версія запиту (без пробного запуску) викликала б контролер допуску, який має побічні ефекти, запит буде відхилено, щоб не ризикувати небажаними побічними ефектами. Усі вбудовані втулки контролю допуску підтримують пробний запуск. Крім того, вебхуки допуску можуть оголосити у своєму обʼєкті конфігурації, що вони не мають побічних ефектів, встановивши поле sideEffects у None.

Примітка:

Якщо вебхук дійсно має побічні ефекти, то поле sideEffects слід встановити у "NoneOnDryRun". Ця зміна доречна за умови, що вебхук також модифіковано, щоб він розумів поле DryRun в AdmissionReview і запобігав побічним ефектам для будь-якого запиту, позначеного як пробний запуск.

Ось приклад запиту пробного запуску, який використовує ?dryRun=All:

POST /api/v1/namespaces/test/pods?dryRun=All
Content-Type: application/json
Accept: application/json

Відповідь виглядатиме так само, як для звичайного запиту (без пробного запуску), але значення деяких згенерованих полів можуть відрізнятися.

Згенеровані значення

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

  • name: якщо встановлено generateName, name матиме унікальне випадкове імʼя
  • creationTimestamp / deletionTimestamp: фіксує час створення/видалення
  • UID: унікально ідентифікує обʼєкт і генерується випадково (недетерміновано)
  • resourceVersion: відстежує збережену версію обʼєкта
  • Будь-яке поле, встановлене мутувальним контролером допуску
  • Для ресурсу Service: порти або IP-адреси, які kube-apiserver призначає обʼєктам Service

Авторизація пробного запуску

Авторизація для запитів пробного запуску та звичайних запитів ідентична. Отже, щоб виконати запит пробного запуску, ви повинні мати дозвіл на виконання звичайного запиту.

Наприклад, щоб виконати пробний запуск patch для Deployment, ви повинні мати дозвіл на виконання цього patch. Ось приклад правила для Kubernetes RBAC, що дозволяє застосовувати patch до Deployment:

rules:
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["patch"]

Дивіться Огляд авторизації.

Оновлення наявних ресурсів

Kubernetes надає декілька способів оновлення наявних обʼєктів. Ви можете прочитати розділ вибір механізму оновлення, щоб дізнатися, який підхід найкраще підходить для вашого випадку.

Ви можете перезаписати (update) наявний ресурс, наприклад ConfigMap, використовуючи HTTP PUT. Для запиту PUT відповідальність за вказання resourceVersion (взятого з обʼєкта, що оновлюється) лежить на клієнті. Kubernetes використовує інформацію resourceVersion, щоб API-сервер міг виявляти втрачені оновлення і відхиляти запити від клієнта, дані якого застаріли відносно кластера. Якщо ресурс змінився (resourceVersion, надана клієнтом, застаріла), API-сервер повертає відповідь з помилкою 409 Conflict.

Замість надсилання запиту PUT клієнт може надіслати API-серверу інструкцію застосувати patch до наявного ресурсу. patch зазвичай доречний, якщо зміна, яку клієнт хоче внести, не залежить від наявних даних. Клієнтам, яким потрібне ефективне виявлення втрачених оновлень, слід розглянути можливість зробити свій запит умовним щодо наявного resourceVersion (як HTTP PUT, так і HTTP PATCH), а потім обробляти будь-які повторні спроби, які можуть знадобитися у разі конфлікту.

API Kubernetes підтримує чотири різні операції PATCH, які визначаються відповідним заголовком HTTP Content-Type:

application/apply-patch+yaml
YAML для Server Side Apply (специфічне для Kubernetes розширення на основі YAML). Усі документи JSON є дійсним YAML, тому ви також можете надсилати JSON, використовуючи цей медіатип. Дивіться серіалізацію Server Side Apply для отримання додаткової інформації. Для Kubernetes це операція create, якщо обʼєкт не існує, або операція patch, якщо обʼєкт вже існує.
application/json-patch+json
JSON Patch, як визначено в RFC6902. JSON Patch — це послідовність операцій, які виконуються над ресурсом; наприклад, {"op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ]}. Для Kubernetes це операція patch.

patch з використанням application/json-patch+json може містити умови для перевірки узгодженості, що дозволяє операції завершитися невдачею, якщо ці умови не виконуються (наприклад, щоб уникнути втраченого оновлення).

application/merge-patch+json
JSON Merge Patch, як визначено в RFC7386. JSON Merge Patch фактично є частковим представленням ресурсу. Надісланий JSON поєднується з поточним ресурсом для створення нового, після чого новий ресурс зберігається. Для Kubernetes це операція patch.
application/strategic-merge-patch+json
Strategic Merge Patch (специфічне для Kubernetes розширення на основі JSON). Strategic Merge Patch — це власна реалізація JSON Merge Patch. Ви можете використовувати Strategic Merge Patch лише з вбудованими API або з агрегованими API-серверами, які мають спеціальну підтримку для нього. Ви не можете використовувати application/strategic-merge-patch+json з будь-яким API, визначеним за допомогою CustomResourceDefinition.

Примітка:

Механізм Kubernetes server side apply замінив Strategic Merge Patch.

Функція Server Side Apply Kubernetes дозволяє панелі управління відстежувати керовані поля для новостворених обʼєктів. Server Side Apply надає чіткий шаблон для управління конфліктами полів, пропонує операції apply та update на боці сервера і замінює функціональність kubectl apply на боці клієнта.

Для Server-Side Apply Kubernetes обробляє запит як create, якщо обʼєкт ще не існує, і як patch в іншому разі. Для інших запитів, які використовують PATCH на рівні HTTP, логічною операцією Kubernetes завжди є patch.

Дивіться Server Side Apply для отримання додаткової інформації.

Вибір механізму оновлення

HTTP PUT для заміни наявного ресурсу

Операція update (HTTP PUT) проста в реалізації та гнучка, але має недоліки:

  • Потрібно обробляти конфлікти, коли resourceVersion обʼєкта змінюється між моментом його читання вашим клієнтом і спробою записати його назад. Kubernetes завжди виявляє конфлікт, але вам як авторові клієнта потрібно реалізувати повторні спроби.
  • Ви можете випадково відкинути поля, якщо декодуєте обʼєкт локально (наприклад, використовуючи client-go, ви можете отримати поля, які ваш клієнт не вміє обробляти, а потім відкинути їх під час оновлення).
  • Якщо за обʼєкт відбувається велика конкуренція (навіть за поле або набір полів, які ви не намагаєтеся редагувати), у вас можуть виникнути проблеми з надсиланням оновлення. Проблема гостріша для великих обʼєктів та для обʼєктів з багатьма полями.

HTTP PATCH з використанням JSON Patch

Оновлення через patch корисне, оскільки:

  • Оскільки ви надсилаєте лише різницю, вам потрібно надсилати менше даних у запиті PATCH.
  • Ви можете робити зміни, які ґрунтуються на наявних значеннях, наприклад, копіювати значення певного поля в анотацію.
  • На відміну від update (HTTP PUT), ваші зміни можуть відбутися відразу, навіть якщо часто змінюються неповʼязані поля: зазвичай вам не потрібно повторювати спроби.
    • Вам все ще може знадобитися вказати resourceVersion (щоб відповідати наявному обʼєкту), якщо ви хочете бути особливо обережними, щоб уникнути втрачених оновлень
    • Все ж є доброю практикою додати певну логіку повторних спроб на випадок помилок.
  • Ви можете використовувати тестові умови, щоб ретельно сформулювати конкретні умови оновлення. Наприклад, ви можете збільшити лічильник без його читання, якщо наявне значення відповідає вашим очікуванням. Ви можете зробити це без ризику втратити оновлення, навіть якщо обʼєкт змінився іншим чином з моменту вашого останнього запису до нього. (Якщо тестова умова не виконається, ви можете повернутися до читання поточного значення, а потім записати змінене число).

Проте:

  • Вам потрібно більше локальної (клієнтської) логіки для створення patch; дуже допомагає, якщо у вас є бібліотечна реалізація JSON Patch або навіть для створення JSON Patch спеціально для Kubernetes.
  • Як автору клієнтського програмного забезпечення, вам потрібно бути обережним при створенні patch (тіла HTTP-запиту), щоб не відкинути поля (порядок операцій має значення).

HTTP PATCH з використанням Server-Side Apply

Server-Side Apply має деякі очевидні переваги:

  • Один цикл запит-відповідь: рідко потрібно спочатку робити запит GET.
    • і ви все одно можете виявляти конфлікти для неочікуваних змін
    • у вас є можливість примусово перезаписати конфлікт, якщо це доречно
  • Клієнтські реалізації легко створювати.
  • Ви отримуєте атомарну операцію створення або оновлення без додаткових зусиль (аналогічно UPSERT у деяких діалектах SQL).

Проте:

  • Server-Side Apply зовсім не працює для змін полів, які залежать від поточного значення обʼєкта.
  • Ви можете застосовувати оновлення лише до обʼєктів. Деякі ресурси в HTTP API Kubernetes не є обʼєктами (вони не мають поля .metadata), а Server-Side Apply стосується лише обʼєктів Kubernetes.

Версії ресурсів

Версії ресурсів — це рядки, які ідентифікують внутрішню версію обʼєкта на сервері. Клієнти можуть використовувати версії ресурсів, щоб визначати, коли обʼєкти змінилися, або щоб виражати вимоги до узгодженості даних під час отримання ресурсів, отримання їхнього списку та спостереження за ними. Версії ресурсів повинні передаватися назад на сервер без змін.

Рядки версій ресурсів можна впорядкувати як монотонно зростаючі цілі числа в межах одного типу ресурсів для всіх типів, що обслуговуються kube-apiserver. Сюди входять вбудовані типи API та типи, що базуються на визначеннях власних ресурсів. Обидві версії ресурсів повинні належати обʼєктам однієї групи API та одного типу ресурсів. Наприклад, можна порівняти версії ресурсів двох Deployment з групи API apps, але не можна порівняти версії ресурсів Pod і Deployment. За умови, що два обʼєкти отримано з одного типу ресурсів API, їх можна порівнювати, навіть якщо вони знаходяться в різних просторах імен.

Якщо ви використовуєте ресурси API, що обслуговуються API-сервером розширення, клієнт повинен перевірити, чи розбирається рядок версії ресурсу як десяткове число (докладніше про це в наступних кількох абзацах). Якщо будь-який із двох рядків версії ресурсу не розбирається як десяткове число, ці два рядки можна перевірити на рівність, але не можна покладатися на порівняння для впорядкування.

Починаючи з Kubernetes 1.35, можливість впорядкування версій ресурсів для всіх типів Kubernetes включено до вимог Certified Kubernetes. Базові обʼєкти API та власні ресурси повинні впорядковуватися як монотонно зростаюче ціле число в будь-якій реалізації APIServer 1.35+, щоб пройти тести на відповідність.

Щоб порівняти два рядки версій ресурсів:

Переконайтеся, що вони відповідають таким вимогам:

  • Обидві версії ресурсів повинні належати до одного типу ресурсів, як описано вище
  • Обидві повинні починатися з цифри 1-9 і містити лише цифри 0-9
  • Версії ресурсів порівнюються як десяткові цілі числа довільної розрядності

Щоб порівняти їх, не покладаючись на фіксовану розрядність, можна порівнювати їх як рядки. Не слід припускати, що розрядність має якесь фіксоване значення.

Натомість можна використовувати лексикографічне порівняння, як показано тут:

  • Якщо вони мають різну довжину, більшою є довша (наприклад, "123" > "23")
  • Якщо вони мають однакову довжину, більшою є лексикографічно більша (наприклад, "234" > "123")

Деякі приклади порівнянь версій ресурсів, які повинні працювати:

  • "2345678901234567890123456789012345678901" > "345678901234567890123456789012345678901"
  • "345678901234567890123456789012345678901" == "345678901234567890123456789012345678901"
  • "345678901234567890123456789012345678900" < "345678901234567890123456789012345678901"

Для виконання цього порівняння в client-go доступний допоміжний метод.

Поля resourceVersion в метаданих

Клієнти знаходять версії ресурсів у ресурсах, включно з ресурсами з потоку відповіді для watch або при використанні list для переліку ресурсів.

v1.meta/ObjectMeta — metadata.resourceVersion екземпляра ресурсу ідентифікує версію ресурсу, на якій екземпляр було востаннє змінено.

v1.meta/ListMeta — metadata.resourceVersion колекції ресурсів (відповіді на list) ідентифікує версію ресурсу, на якій було сформовано колекцію.

Параметри resourceVersion у рядках запитів

Операції get, list та watch підтримують параметр resourceVersion. Починаючи з версії v1.19, API-сервери Kubernetes також підтримують параметр resourceVersionMatch у запитах list.

API-сервер інтерпретує параметр resourceVersion по-різному залежно від операції, яку ви запитуєте, та від значення resourceVersion. Якщо ви встановлюєте resourceVersionMatch, то це також впливає на спосіб зіставлення.

Семантика для get та list

Для get та list семантика resourceVersion така:

get:

resourceVersion не встановленоresourceVersion="0"resourceVersion="{значення, відмінне від 0}"
НайновішаБудь-якаНе старша ніж

list:

Починаючи з версії v1.19, API-сервери Kubernetes підтримують параметр resourceVersionMatch у запитах list. Якщо ви встановлюєте як resourceVersion, так і resourceVersionMatch, то параметр resourceVersionMatch визначає, як API-сервер інтерпретує resourceVersion.

Вам завжди слід встановлювати параметр resourceVersionMatch, коли ви встановлюєте resourceVersion у запиті list. Однак будьте готові обробляти випадок, коли API-сервер, що відповідає, не знає про resourceVersionMatch і ігнорує його.

Якщо у вас немає суворих вимог до узгодженості, бажано використовувати resourceVersionMatch=NotOlderThan та відому resourceVersion, оскільки це може забезпечити кращу продуктивність і масштабованість вашого кластера, ніж залишати resourceVersion і resourceVersionMatch невстановленими, що вимагає кворумного читання для обслуговування.

Встановлення параметра resourceVersionMatch без встановлення resourceVersion є недійсним.

Ця таблиця пояснює поведінку запитів list з різними комбінаціями resourceVersion та resourceVersionMatch:

Параметри resourceVersionMatch та розбиття на сторінки для list
Параметр resourceVersionMatchПараметри розбиття на сторінкиresourceVersion не встановленоresourceVersion="0"resourceVersion="{значення, відмінне від 0}"
не встановленоlimit не встановленоНайновішаБудь-якаНе старша ніж
не встановленоlimit=<n>, continue не встановленоНайновішаБудь-якаТочна
не встановленоlimit=<n>, continue=<token>ПродовженняПродовженняНедійсно, HTTP 400 Bad Request
resourceVersionMatch=Exactlimit не встановленоНедійсноНедійсноТочна
resourceVersionMatch=Exactlimit=<n>, continue не встановленоНедійсноНедійсноТочна
resourceVersionMatch=NotOlderThanlimit не встановленоНедійсноБудь-якаНе старша ніж
resourceVersionMatch=NotOlderThanlimit=<n>, continue не встановленоНедійсноБудь-якаНе старша ніж

Примітка:

Якщо API-сервер вашого кластера не враховує параметр resourceVersionMatch, поведінка буде такою самою, як якщо б ви його не встановили.

Значення семантики get та list таке:

Будь-яка
Повернути дані на будь-якій версії ресурсу. Перевага надається найновішій доступній версії ресурсу, але сувора узгодженість не потрібна; можуть бути надані дані на будь-якій версії ресурсу. Запит може повернути дані на значно старішій версії ресурсу, ніж та, яку клієнт спостерігав раніше, особливо в конфігураціях високої доступності, через розділення мережі або застарілі кеші. Клієнти, які не можуть цього допустити, не повинні використовувати цю семантику. Завжди обслуговується з кешу спостереження, що покращує продуктивність і зменшує навантаження на etcd.
Найновіша
Повернути дані на найновішій версії ресурсу. Повернуті дані повинні бути узгодженими (докладніше: обслуговуються з etcd за допомогою кворумного читання). Для etcd v3.4.31+ та v3.5.13+ Kubernetes 1.37 обслуговує читання «найновіших» даних з кешу спостереження: внутрішнього сховища в памʼяті всередині API-сервера, яке кешує та віддзеркалює стан даних, збережених в etcd. Kubernetes запитує сповіщення про прогрес, щоб підтримувати узгодженість кешу з шаром постійного зберігання etcd. Версії Kubernetes з v1.28 до v1.30 також підтримували цю функцію, але як альфа-функція вона не рекомендувалася для промислової експлуатації і не була типово увімкненою до випуску v1.31.
Не старша ніж
Повернути дані, які є щонайменше такими ж новими, як надана resourceVersion. Перевага надається найновішим доступним даним, але можуть бути надані будь-які дані, не старші за надану resourceVersion. Для запитів list до серверів, які враховують параметр resourceVersionMatch, це гарантує, що .metadata.resourceVersion колекції не старша за запитану resourceVersion, але не дає жодних гарантій щодо .metadata.resourceVersion будь-яких елементів у цій колекції. Завжди обслуговується з кешу спостереження, що покращує продуктивність і зменшує навантаження на etcd.
Точна
Повернути дані на точно наданій версії ресурсу. Якщо надана resourceVersion недоступна, сервер відповідає HTTP 410 Gone. Для запитів list до серверів, які враховують параметр resourceVersionMatch, це гарантує, що .metadata.resourceVersion колекції збігається з resourceVersion, яку ви запросили в рядку запиту. Ця гарантія не поширюється на .metadata.resourceVersion будь-яких елементів у цій колекції. Коли функціональна можливість ListFromCacheSnapshot типово увімкнена, API-сервер намагатиметься надати відповідь зі знімка, якщо доступний знімок з resourceVersion, старішою за запитану. Це покращує продуктивність і зменшує навантаження на etcd. API-сервер запускається без знімків, створює новий знімок на кожну подію спостереження і зберігає їх, доки не виявить ущільнення (compaction) etcd або доки кеш не заповниться подіями, старшими за 75 секунд. Якщо надана resourceVersion недоступна, сервер звернеться до etcd.
Продовження
Повернути наступну сторінку даних для запиту списку з розбиттям на сторінки, забезпечуючи узгодженість з точною resourceVersion, встановленою початковим запитом у послідовності. Відповідь на запити list з limit містить токен continue, який кодує resourceVersion і останню спостережувану позицію, з якої слід продовжити список. Якщо resourceVersion у наданому токені continue недоступна, сервер відповідає HTTP 410 Gone. Коли функціональна можливість ListFromCacheSnapshot типово увімкнена, API-сервер намагатиметься надати відповідь зі знімка, якщо доступний знімок з resourceVersion, старішою за запитану. Це покращує продуктивність і зменшує навантаження на etcd. API-сервер запускається без знімків, створює новий знімок на кожну подію спостереження і зберігає їх, доки не виявить ущільнення (compaction) etcd або доки кеш не заповниться подіями, старшими за 75 секунд. Якщо resourceVersion у наданому токені continue недоступна, сервер звернеться до etcd.

Примітка:

Коли ви виконуєте list для ресурсів і отримуєте відповідь-колекцію, відповідь містить метадані списку колекції, а також метадані обʼєктів для кожного елемента в цій колекції. Для окремих обʼєктів у відповіді-колекції .metadata.resourceVersion відстежує, коли цей обʼєкт було востаннє оновлено, а не те, наскільки актуальним є обʼєкт на момент надання.

Коли використовується resourceVersionMatch=NotOlderThan і встановлено limit, клієнти повинні обробляти відповіді HTTP 410 Gone. Наприклад, клієнт може повторити спробу з новішою resourceVersion або повернутися до resourceVersion="".

Коли використовується resourceVersionMatch=Exact і limit не встановлено, клієнти повинні перевіряти, що .metadata.resourceVersion колекції збігається із запитаною resourceVersion, і обробляти випадок, коли це не так. Наприклад, клієнт може повернутися до запиту зі встановленим limit.

Семантика для watch

Для watch семантика версії ресурсу така:

watch:

resourceVersion для watch
resourceVersion не встановленоresourceVersion="0"resourceVersion="{значення, відмінне від 0}"
Отримати стан і почати з найновішоїОтримати стан і почати з будь-якоїПочати з точної

Значення цієї семантики watch таке:

Отримати стан і почати з будь-якої
Почати watch з будь-якої версії ресурсу; перевага надається найновішій доступній версії ресурсу, але це не обовʼязково. Дозволено будь-яку початкову версію ресурсу. watch може початися з набагато старішої версії ресурсу, ніж та, яку клієнт спостерігав раніше, особливо в конфігураціях високої доступності, через розділення мережі або застарілі кеші. Клієнти, які не можуть допустити такого видимого відмотування назад, не повинні починати watch з цією семантикою. Для встановлення початкового стану watch починається із синтетичних подій "Added" для всіх екземплярів ресурсів, які існують на початковій версії ресурсу. Усі подальші події спостереження стосуються всіх змін, що сталися після версії ресурсу, з якої почався watch.

Увага:

watches, ініціалізовані таким чином, можуть повертати довільно застарілі дані. Будь ласка, ознайомтеся з цією семантикою перед використанням і надавайте перевагу іншим семантикам, де це можливо.
Отримати стан і почати з найновішої
Почати watch з найновішої версії ресурсу, яка повинна бути узгодженою (докладніше: обслуговується з etcd за допомогою кворумного читання). Для встановлення початкового стану watch починається із синтетичних подій "Added" для всіх екземплярів ресурсів, які існують на початковій версії ресурсу. Усі подальші події спостереження стосуються всіх змін, що сталися після версії ресурсу, з якої почався watch.
Почати з точної
Почати watch з точної версії ресурсу. Події спостереження стосуються всіх змін після наданої версії ресурсу. На відміну від «Отримати стан і почати з найновішої» та «Отримати стан і почати з будь-якої», watch не починається із синтетичних подій "Added" для наданої версії ресурсу. Вважається, що клієнт вже має початковий стан на початковій версії ресурсу, оскільки клієнт надав цю версію ресурсу.

Відповіді "410 Gone"

Сервери не зобовʼязані надавати всі старіші версії ресурсів і можуть повернути код статусу HTTP 410 (Gone), якщо клієнт запитує resourceVersion, старішу, ніж та, що зберігається на сервері. Клієнти повинні бути готові обробляти відповіді 410 (Gone). Дивіться розділ Ефективне виявлення змін для отримання додаткової інформації про те, як обробляти відповіді 410 (Gone) під час спостереження за ресурсами.

Якщо ви запитуєте resourceVersion за межами допустимого діапазону, то, залежно від того, чи обслуговується запит з кешу чи ні, API-сервер може відповісти HTTP-відповіддю 410 Gone.

Недоступні версії ресурсів

Сервери не зобовʼязані обслуговувати нерозпізнані версії ресурсів. Якщо ви запитуєте list або get для версії ресурсу, яку API-сервер не розпізнає, то API-сервер може або:

  • трохи почекати, поки версія ресурсу стане доступною, а потім завершити запит за тайм-аутом з 504 (Gateway Timeout), якщо надана версія ресурсу не стане доступною протягом розумного часу;
  • відповісти із заголовком відповіді Retry-After, який вказує, скільки секунд клієнт повинен зачекати перед повторною спробою запиту.

Якщо ви запитуєте версію ресурсу, яку API-сервер не розпізнає, kube-apiserver додатково позначає свої відповіді з помилками повідомленням Too large resource version.

Якщо ви робите запит watch для нерозпізнаної версії ресурсу, API-сервер може чекати невизначено довго (до тайм-ауту запиту), поки версія ресурсу стане доступною.

Ініціалізація кешу спостереження

Щоб запобігти перевантаженню панелі управління та голодуванню API Priority and Fairness (APF) під час ініціалізації або повторної ініціалізації кешу спостереження, API-сервер Kubernetes застосовує два захисні механізми:

  • Захист готовності під час запуску: Під час запуску API-сервер затримує повідомлення про готовність (/readyz), доки кожен зареєстрований кеш спостереження не завершить свою початкову синхронізацію з etcd. Це запобігає передчасному спрямуванню клієнтського трафіку балансувальниками навантаження на API-сервер, усуваючи масові одночасні читання під час запуску (thundering herd), які інакше оминали б неготовий кеш і потрапляли б безпосередньо в etcd.
  • Відхилення запитів під час ініціалізації кешу: Якщо запити надходять, поки кеш спостереження для типу ресурсу не ініціалізовано — наприклад, під час завантаження сервера (до готовності) або після повторної синхронізації чи відʼєднання кешу під час роботи, — API-сервер не дає дорогим запитам перевантажити etcd або зависнути на невизначений час:
    • Запити WATCH та запити LIST без розбиття на сторінки або з фільтрацією (будь-який запит списку без limit для розбиття на сторінки або із селектором міток чи полів) негайно відхиляються з кодом статусу HTTP 429 Too Many Requests та динамічним заголовком Retry-After. Це запобігає зависанню goroutine, голодуванню місць APF та вичерпанню памʼяті etcd.
    • Безпечні читання з розбиттям на сторінки: Лише запити GET та запити LIST з розбиттям на сторінки і без фільтрації (limit > 0 без селектора міток чи полів) делегуються безпосередньо до etcd як безпечний запасний варіант.

Клієнти (включно з власними контролерами та операторами) мають бути розроблені так, щоб коректно обробляти відповіді HTTP 429 Too Many Requests, поважаючи заголовки Retry-After та реалізуючи експоненційну затримку повторних спроб.

2 - Загальна мова виразів у Kubernetes

Загальна мова виразів (Common Expression Language, CEL) використовується в API Kubernetes для оголошення правил валідації, політик та інших обмежень чи умов.

Вирази CEL оцінюються безпосередньо на API-сервері, що робить CEL зручним альтернативним рішенням для зовнішніх механізмів, таких як вебхуки, для багатьох випадків розширення функціональності. Ваші вирази CEL продовжують виконуватись, поки компонент API-сервера у складі панелі управління залишається доступним.

Огляд мови

Мова CEL має простий синтаксис, який схожий на вирази в C, C++, Java, JavaScript і Go.

CEL була розроблена для вбудовування в застосунки. Кожна "програма" CEL — це один вираз, який обраховується до одного значення. Вирази CEL зазвичай є короткими "однорядковими виразами", що добре вбудовуються в рядкові поля ресурсів API Kubernetes.

Вхідні дані для програми CEL — це "змінні". Кожне поле API Kubernetes, яке містить CEL, декларує в документації API, які змінні доступні для використання для цього поля. Наприклад, у полі x-kubernetes-validations[i].rules у CustomResourceDefinitions доступні змінні self і oldSelf, що відносяться до попереднього та поточного стану даних власного ресурсу користувача, які потрібно перевірити за допомогою виразу CEL. Інші поля API Kubernetes можуть оголошувати різні змінні. Дивіться документацію API для полів API, щоб дізнатися, які змінні доступні для цього поля.

Приклади виразів CEL:

Приклади виразів CEL та призначення кожного з них
ПравилоПризначення
self.minReplicas <= self.replicas && self.replicas <= self.maxReplicasПеревірити, що три поля, які визначають репліки, розташовані в правильному порядку
'Available' in self.stateCountsПеревірити, що в map існує запис з ключем 'Available'
(self.list1.size() == 0) != (self.list2.size() == 0)Перевірити, що один із двох списків не порожній, але не обидва одночасно
self.envars.filter(e, e.name = 'MY_ENV').all(e, e.value.matches('^[a-zA-Z]*$'))Перевірити поле 'value' у записі listMap, де поле ключа 'name' дорівнює 'MY_ENV'
has(self.expired) && self.created + self.ttl < self.expiredПеревірити, що дата 'expired' пізніша за дату 'create' плюс тривалість 'ttl'
self.health.startsWith('ok')Перевірити, що рядкове поле 'health' має префікс 'ok'
self.widgets.exists(w, w.key == 'x' && w.foo < 10)Перевірити, що властивість 'foo' елемента listMap з ключем 'x' менша за 10
type(self) == string ? self == '99%' : self == 42Перевірити поле типу int-або-string для обох випадків: int та string
self.metadata.name == 'singleton'Перевірити, що імʼя обʼєкта відповідає конкретному значенню (що робить його єдиним екземпляром — singleton)
self.set1.all(e, !(e in self.set2))Перевірити, що два listSet не перетинаються
self.names.size() == self.details.size() && self.names.all(n, n in self.details)Перевірити, що ключами map 'details' є елементи listSet 'names'
self.details.all(key, key.matches('^[a-zA-Z]*$'))Перевірити ключі map 'details'
self.details.all(key, self.details[key].matches('^[a-zA-Z]*$'))Перевірити значення map 'details'

Опції CEL, можливості мови та бібліотеки

CEL налаштовується з наступними опціями, бібліотеками та можливостями мови, введеними у зазначених версіях Kubernetes:

Опція, бібліотека або можливість мови CELВключеноДоступність
Стандартні макросиhas, all, exists, exists_one, map, filterУсі версії Kubernetes
Стандартні функціїДивіться офіційний список стандартних визначеньУсі версії Kubernetes
Однорідні агрегатні літерали-Усі версії Kubernetes
Типовий часовий пояс UTC-Усі версії Kubernetes
Рання перевірка декларацій-Усі версії Kubernetes
Розширена бібліотека рядків, версія 1charAt, indexOf, lastIndexOf, lowerAscii, upperAscii, replace, split, join, substring, trimВерсії Kubernetes від 1.25 до 1.30
Розширена бібліотека рядків, версія 2charAt, indexOf, lastIndexOf, lowerAscii, upperAscii, replace, split, join, substring, trimВерсії Kubernetes 1.30+
Бібліотека списків KubernetesДивіться бібліотеку списків KubernetesУсі версії Kubernetes
Бібліотека регулярних виразів KubernetesДивіться бібліотеку регулярних виразів KubernetesУсі версії Kubernetes
Бібліотека URL KubernetesДивіться бібліотеку URL KubernetesУсі версії Kubernetes
Бібліотека IP-адрес KubernetesДивіться бібліотеку IP-адрес KubernetesВерсії Kubernetes 1.31+
Бібліотека CIDR KubernetesДивіться бібліотеку CIDR KubernetesВерсії Kubernetes 1.31+
Бібліотека авторизатора KubernetesДивіться бібліотеку авторизатора KubernetesУсі версії Kubernetes
Бібліотека кількостей KubernetesДивіться бібліотеку кількостей KubernetesВерсії Kubernetes 1.29+
Бібліотека semver KubernetesДивіться бібліотеку semver KubernetesВерсії Kubernetes 1.34+
Бібліотека форматів KubernetesДивіться бібліотеку форматів KubernetesВерсії Kubernetes 1.32+
Опційні типи CELДивіться опційні типи CELВерсії Kubernetes 1.29+
CEL CrossTypeNumericComparisonsДивіться CEL CrossTypeNumericComparisonsВерсії Kubernetes 1.29+
CEL TwoVarComprehensionsДивіться CEL TwoVarComprehensionsВерсії Kubernetes 1.33+

Функції CEL, можливості та налаштування мови підтримують відкат панелі управління Kubernetes. Наприклад, опційні значення CEL були введені у Kubernetes 1.29, і лише API-сервери цієї версії або новіші прийматимуть запити на запис виразів CEL, які використовують опційні значення CEL. Однак, коли кластер відкочується до версії Kubernetes 1.28, вирази CEL, що використовують "опційні значення CEL", які вже збережені в ресурсах API, продовжуватимуть правильно оцінюватись.

Бібліотеки CEL Kubernetes

Крім спільнотних бібліотек CEL, Kubernetes включає бібліотеки CEL, які доступні у всіх місцях використання CEL в Kubernetes.

Бібліотека списків Kubernetes

Бібліотека списків включає indexOf та lastIndexOf, які працюють аналогічно функціям рядків з такими самими назвами. Ці функції повертають перший або останній індекс елемента у списку.

Бібліотека списків також включає min, max та sum. Сума підтримується для всіх типів чисел, а також для типу тривалості. Мінімум та максимум підтримуються для всіх типів, що можна порівняти.

Також надається функція isSorted для зручності та підтримується для всіх типів, які можна порівняти.

Приклади:

Приклади виразів CEL, що використовують функції бібліотеки списків
Вираз CELПризначення
names.isSorted()Перевірити, що список імен зберігається в алфавітному порядку
items.map(x, x.weight).sum() == 1.0Перевірити, що сума "ваг" списку обʼєктів дорівнює 1.0
lowPriorities.map(x, x.priority).max() < highPriorities.map(x, x.priority).min()Перевірити, що два набори пріоритетів не перетинаються
names.indexOf('should-be-first') == 1Вимагати, щоб перше імʼя у списку мало певне значення

Для отримання додаткової інформації дивіться бібліотеку списків Kubernetes godoc.

Бібліотека регулярних виразів Kubernetes

Крім функції matches, наданої стандартною бібліотекою CEL, бібліотека регулярних виразів надає функції find та findAll, що дозволяють виконувати значно ширший спектр операцій з регулярними виразами.

Приклади:

Приклади виразів CEL, що використовують функції бібліотеки регулярних виразів
Вираз CELПризначення
"abc 123".find('[0-9]+')Знайти перше число у рядку
"1, 2, 3, 4".findAll('[0-9]+').map(x, int(x)).sum() < 100Перевірити, що сума чисел у рядку менша за 100

Для отримання додаткової інформації дивіться бібліотеку регулярних виразів Kubernetes godoc.

Бібліотека URL Kubernetes

Для спрощення та безпечної обробки URL надані наступні функції:

  • isURL(string) перевіряє, чи є рядок дійсним URL відповідно до пакета net/url у Go. Рядок повинен бути абсолютним URL.
  • url(string) URL конвертує рядок в URL або викликає помилку, якщо рядок не є дійсним URL.

Після розбору за допомогою функції url, отриманий обʼєкт URL має наступні методи доступу: getScheme, getHost, getHostname, getPort, getEscapedPath та getQuery.

Приклади:

Приклади виразів CEL, що використовують функції бібліотеки URL
Вираз CELПризначення
url('https://example.com:80/').getHost()Отримати частину хосту 'example.com:80' URL
url('https://example.com/path with spaces/').getEscapedPath()Повертає '/path%20with%20spaces/'

Для отримання додаткової інформації дивіться бібліотеку URL Kubernetes godoc.

Бібліотека IP-адрес Kubernetes

Щоб зробити обробку IP-адрес простішою і безпечнішою, були додані наступні функції:

  • isIP(string) перевіряє, чи є рядок дійсною IP-адресою.
  • ip(string) IP конвертує рядок в обʼєкт IP-адреси або викликає помилку, якщо рядок не є дійсною IP-адресою.

Для обох функцій IP-адреса повинна бути адресою IPv4 або IPv6. Зіставлені з IPv4 IPv6-адреси (наприклад, ::ffff:1.2.3.4) не допускаються. IP-адреси з зонами (наприклад, fe80::1%eth0) не допускаються. Початкові нулі в октетах IPv4-адрес не допускаються.

Після розбору за допомогою функції ip отриманий обʼєкт IP має наступну бібліотеку функцій-членів:

Доступні функції-члени обʼєкта IP-адреси
Функція-членЗначення, що повертається (CEL)Опис
isCanonical()boolПовертає true, якщо IP-адреса знаходиться в канонічній формі. Для кожної IP-адреси існує лише одна канонічна форма, тому поля, що містять IP-адреси в канонічній формі, можна розглядати як рядки при перевірці на рівність або унікальність.
family()intПовертає сімейство IP-адреси: 4 для IPv4 та 6 для IPv6.
isUnspecified()boolПовертає true, якщо IP-адреса є невизначеною адресою. Це може бути IPv4-адреса "0.0.0.0" або IPv6-адреса "::".
isLoopback()boolПовертає true, якщо IP-адреса є loopback-адресою. Це може бути IPv4-адреса зі значенням 127.x.x.x або IPv6-адреса зі значенням ::1.
isLinkLocalMulticast()boolПовертає true, якщо IP-адреса є локальною груповою адресою каналу (link-local multicast). Це може бути IPv4-адреса зі значенням 224.0.0.x або IPv6-адреса в мережі ff00::/8.
isLinkLocalUnicast()boolПовертає true, якщо IP-адреса є локальною індивідуальною адресою каналу (link-local unicast). Це може бути IPv4-адреса зі значенням 169.254.x.x або IPv6-адреса в мережі fe80::/10.
isGlobalUnicast()boolПовертає true, якщо IP-адреса є глобальною індивідуальною адресою. Це може бути IPv4-адреса, що не є нулем або 255.255.255.255, або IPv6-адреса, що не є локальною індивідуальною адресою каналу, loopback-адресою або груповою адресою.

Приклади:

Приклади виразів CEL, що використовують функції бібліотеки IP-адрес
Вираз CELПризначення
isIP('127.0.0.1')Повертає true для дійсної IP-адреси.
ip('2001:db8::abcd').isCanonical()Повертає true для канонічної IPv6-адреси.
ip('2001:DB8::ABCD').isCanonical()Повертає false, оскільки канонічна форма використовує нижній регістр.
ip('127.0.0.1').family() == 4Перевіряє сімейство IP-адреси.
ip('::1').isLoopback()Перевіряє, чи є IP-адреса loopback-адресою.
ip('192.168.0.1').isGlobalUnicast()Перевіряє, чи є IP-адреса глобальною індивідуальною адресою.

Докладнішу інформацію наведено у Бібліотеці IP-адрес Kubernetes godoc.

Бібліотека CIDR Kubernetes

CIDR надає розширення бібліотеки функцій CEL для розбору нотації CIDR.

cidr

Конвертує рядок у нотації CIDR в представлення мережевої адреси або викликає помилку, якщо рядок не є дійсною нотацією CIDR. CIDR повинен бути підмережею IPv4 або IPv6 з маскою. Ведучі нулі в октетах IPv4-адреси не дозволяються. IPv4-адреси, що відображаються в IPv6 (наприклад, ::ffff:1.2.3.4/24), не дозволяються.

cidr(<string>) <CIDR>

Приклади:

Приклади виразів CEL, що використовують функцію cidr
Вираз CELПризначення
cidr('192.168.0.0/16')Повертає IPv4-адресу з маскою CIDR.
cidr('::1/128')Повертає IPv6-адресу з маскою CIDR.
cidr('192.168.0.0/33')Помилка, оскільки довжина префікса перевищує розмір IPv4-адреси.
cidr('::1/129')Помилка, оскільки довжина префікса перевищує розмір IPv6-адреси.
cidr('192.168.0.1/16')Помилка, оскільки після префікса є біти, що не дорівнюють 0.

isCIDR

Повертає true, якщо рядок є дійсним представленням підмережі з маскою в нотації CIDR. CIDR повинен бути підмережею IPv4 або IPv6 з маскою. Ведучі нулі в октетах IPv4-адреси не дозволяються. IPv4-адреси, що відображаються в IPv6 (наприклад, ::ffff:1.2.3.4/24), не дозволяються.

isCIDR(<string>) <bool>

Приклади:

Приклади виразів CEL, що використовують функцію isCIDR
Вираз CELПризначення
isCIDR('192.168.0.0/16')Повертає true для дійсного IPv4 CIDR.
isCIDR('::1/128')Повертає true для дійсного IPv6 CIDR.
isCIDR('192.168.0.0/33')Повертає false, оскільки довжина префікса перевищує розмір IPv4-адреси.
isCIDR('::1/129')Повертає false, оскільки довжина префікса перевищує розмір IPv6-адреси.

containsIP / containsCIDR / ip / masked / prefixLength

  • containsIP: Повертає true, якщо CIDR містить задану IP-адресу. IP-адреса має бути IPv4 або IPv6. Може приймати як аргумент рядок або IP-адресу.

  • containsCIDR: Повертає true, якщо CIDR містить заданий CIDR. CIDR повинен бути підмережею IPv4 або IPv6 з маскою. Може приймати як аргумент рядок або CIDR.

  • ip: Повертає представлення IP-адреси CIDR.

  • masked: Повертає представлення CIDR мережевої адреси з маскованим префіксом. Це можна використовувати для повернення канонічної форми мережі CIDR.

  • prefixLength: Повертає довжину префікса CIDR в бітах. Це кількість бітів у масці.

Приклади:

Приклади виразів CEL, що використовують функції бібліотеки CIDR
Вираз CELПризначення
cidr('192.168.0.0/24').containsIP(ip('192.168.0.1'))Перевіряє, чи містить CIDR вказану IP-адресу (обʼєкт IP).
cidr('192.168.0.0/24').containsIP(ip('192.168.1.1'))Перевіряє, чи містить CIDR вказану IP-адресу (обʼєкт IP).
cidr('192.168.0.0/24').containsIP('192.168.0.1')Перевіряє, чи містить CIDR вказану IP-адресу (рядок).
cidr('192.168.0.0/24').containsIP('192.168.1.1')Перевіряє, чи містить CIDR вказану IP-адресу (рядок).
cidr('192.168.0.0/16').containsCIDR(cidr('192.168.10.0/24'))Перевіряє, чи містить CIDR інший вказаний CIDR (обʼєкт CIDR).
cidr('192.168.1.0/24').containsCIDR(cidr('192.168.2.0/24'))Перевіряє, чи містить CIDR інший вказаний CIDR (обʼєкт CIDR).
cidr('192.168.0.0/16').containsCIDR('192.168.10.0/24')Перевіряє, чи містить CIDR інший вказаний CIDR (рядок).
cidr('192.168.1.0/24').containsCIDR('192.168.2.0/24')Перевіряє, чи містить CIDR інший вказаний CIDR (рядок).
cidr('192.168.0.1/24').ip()Повертає частину IP-адреси CIDR.
cidr('192.168.0.1/24').ip().family()Повертає сімейство частини IP-адреси CIDR.
cidr('::1/128').ip()Повертає частину IP-адреси IPv6 CIDR.
cidr('::1/128').ip().family()Повертає сімейство частини IP-адреси IPv6 CIDR.
cidr('192.168.0.0/24').masked()Повертає канонічну форму мережі CIDR.
cidr('192.168.0.1/24').masked()Повертає канонічну форму мережі CIDR, маскуючи біти після префікса.
cidr('192.168.0.0/24') == cidr('192.168.0.0/24').masked()Порівнює CIDR з його канонічною формою (вже канонічний).
cidr('192.168.0.1/24') == cidr('192.168.0.1/24').masked()Порівнює CIDR з його канонічною формою (не канонічний).
cidr('192.168.0.0/16').prefixLength()Повертає довжину префікса IPv4 CIDR.
cidr('::1/128').prefixLength()Повертає довжину префікса IPv6 CIDR.

Докладнішу інформацію можна знайти у Бібліотеці Kubernetes CIDR godoc.

Бібліотека авторизатора Kubernetes

Для виразів CEL в API, де доступна змінна типу Authorizer, авторизатор може використовуватися для виконання перевірок авторизації для принципала (автентифікованого користувача) запиту.

Перевірки ресурсів API виконуються наступним чином:

  1. Вкажіть групу та ресурс для перевірки: Authorizer.group(string).resource(string) ResourceCheck
  2. Опційно викличте будь-яку комбінацію наступних функцій побудови для подальшого обмеження перевірки авторизації. Зверніть увагу, що ці функції повертають тип отримувача та можуть бути зʼєднані ланцюгом:
    • ResourceCheck.subresource(string) ResourceCheck
    • ResourceCheck.namespace(string) ResourceCheck
    • ResourceCheck.name(string) ResourceCheck
  3. Викличте ResourceCheck.check(verb string) Decision, щоб виконати перевірку авторизації.
  4. Викличте allowed() bool або reason() string, щоб переглянути результат перевірки авторизації.

Авторизація для нересурсних запитів виконується так:

  1. Вкажіть лише шлях: Authorizer.path(string) PathCheck
  2. Викличте PathCheck.check(httpVerb string) Decision, щоб виконати перевірку авторизації.
  3. Викличте allowed() bool або reason() string, щоб переглянути результат перевірки авторизації.

Для виконання перевірки авторизації для службового облікового запису:

  • Authorizer.serviceAccount(namespace string, name string) Authorizer
Приклади виразів CEL, що використовують функції бібліотеки URL
Вираз CELПризначення
authorizer.group('').resource('pods').namespace('default').check('create').allowed()Повертає true, якщо принципалу (користувачу або службовому обліковому запису) дозволено створювати Podʼи у просторі імен 'default'.
authorizer.path('/healthz').check('get').allowed()Перевіряє, чи має принципал (користувач або службовий обліковий запис) дозвіл виконувати HTTP GET-запити до шляху API /healthz.
authorizer.serviceAccount('default', 'myserviceaccount').resource('deployments').check('delete').allowed()Перевіряє, чи має службовий обліковий запис дозвіл видаляти Deploymentʼи.
СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.34; (стандартно увімкнено)
More information about this feature

This is a stable feature in Kubernetes, and has been since version 1.34. It was first available in the v1.31 release.

Для виразів CEL в API, де доступна змінна типу Authorizer, селектори полів і міток можуть бути включені в перевірки авторизації.

Приклади виразів CEL із використанням функцій авторизації для селекторів
Вираз CELПризначення
authorizer.group('').resource('pods').fieldSelector('spec.nodeName=mynode').check('list').allowed()Повертає true, якщо принципалу (користувачу або службовому обліковому запису) дозволено отримувати список Podʼів із селектором полів spec.nodeName=mynode.
authorizer.group('').resource('pods').labelSelector('example.com/mylabel=myvalue').check('list').allowed()Повертає true, якщо принципалу (користувачу або службовому обліковому запису) дозволено отримувати список Podʼів із селектором міток example.com/mylabel=myvalue.

Для отримання додаткової інформації дивіться бібліотеку Kubernetes Authz та бібліотеку Kubernetes AuthzSelectors godoc.

Бібліотека форматів Kubernetes

Бібліотека format надає функції для перевірки поширених форматів рядків у Kubernetes. Це може бути корисно у messageExpression правил валідації для надання більш конкретних повідомлень про помилки.

Бібліотека надає функції format() для кожного іменованого формату, а також загальну функцію format.named().

  • format.named(string) → ?Format: Повертає обʼєкт Format для заданого імені формату, якщо він існує. Інакше повертає optional.none.
  • format.<formatName>() -> Format: Також доступні зручні функції для всіх іменованих форматів. Наприклад, format.dns1123Label() повертає обʼєкт Format для міток DNS-1123.
  • <Format>.validate(string) -> list<string>?: Перевіряє рядок на відповідність формату. Повертає optional.none, якщо рядок валідний, інакше — optional, що містить список рядків з помилками валідації.

Доступні формати:

Підтримуються наступні назви форматів:

Доступні формати для бібліотеки форматів
Назва форматуОпис
dns1123LabelПеревіряє, чи є рядок валідною DNS-1123 міткою.
dns1123SubdomainПеревіряє, чи є рядок валідним DNS-1123 піддоменом.
dns1035LabelПеревіряє, чи є рядок валідною DNS-1035 міткою.
qualifiedNameПеревіряє, чи є рядок валідним кваліфікованим іменем.
dns1123LabelPrefixПеревіряє, чи є рядок валідним префіксом DNS-1123 мітки.
dns1123SubdomainPrefixПеревіряє, чи є рядок валідним префіксом DNS-1123 піддомену.
dns1035LabelPrefixПеревіряє, чи є рядок валідним префіксом DNS-1035 мітки.
labelValueПеревіряє, чи є рядок валідним значенням мітки.
uriПеревіряє, чи є рядок валідним URI. Використовує той самий патерн, що і `isURL`, але повертає список помилок.
uuidПеревіряє, чи є рядок валідним UUID.
byteПеревіряє, чи є рядок валідним base64-кодованим рядком.
dateПеревіряє, чи є рядок валідною датою у форматі `YYYY-MM-DD`.
datetimeПеревіряє, чи є рядок валідною датою-часом у форматі RFC3339.

Приклади:

Приклади виразів CEL, що використовують функції бібліотеки форматів
Вираз CELПризначення
!format.dns1123Label().validate(self.metadata.name).hasValue()Правило валідації, що перевіряє, чи імʼя обʼєкта є валідною DNS-1123 міткою.
format.dns1123Label().validate(self.metadata.name).orValue([]).join("\\n")`messageExpression`, що повертає конкретні помилки валідації для поля. Якщо поле валідне, `validate` повертає `optional.none`, а `orValue` — порожній список, результатом буде порожній рядок.

Докладніше: Бібліотека форматів Kubernetes godoc.

Бібліотека кількостей Kubernetes

У Kubernetes 1.28 додана підтримка обробки рядків кількості (наприклад, 1.5G, 512k, 20Mi).

  • isQuantity(string) перевіряє, чи є рядок дійсною кількістю (Quantity) відповідно до resource.Quantity у Kubernetes.
  • quantity(string) Quantity конвертує рядок у кількість або викликає помилку, якщо рядок не є дійсною кількістю.

Після розбору за допомогою функції quantity отриманий обʼєкт Quantity має таку бібліотеку функцій-членів:

Доступні функції-члени Quantity
Функція-членЗначення, що повертається (CEL)Опис
isInteger()boolПовертає true тоді й лише тоді, коли asInteger можна безпечно викликати без помилки
asInteger()intПовертає представлення поточного значення як int64, якщо це можливо, або викликає помилку, якщо конвертація призводить до переповнення або втрати точності.
asApproximateFloat()floatПовертає представлення кількості як float64, яке може втратити точність. Якщо значення кількості виходить за межі діапазону float64, буде повернуто +Inf/-Inf.
sign()intПовертає 1, якщо кількість додатна, -1, якщо вона відʼємна. 0, якщо вона дорівнює нулю.
add(<Quantity>)QuantityПовертає суму двох кількостей
add(<int>)QuantityПовертає суму кількості та цілого числа
sub(<Quantity>)QuantityПовертає різницю між двома кількостями
sub(<int>)QuantityПовертає різницю між кількістю та цілим числом
isLessThan(<Quantity>)boolПовертає true тоді й лише тоді, коли отримувач менший за операнд
isGreaterThan(<Quantity>)boolПовертає true тоді й лише тоді, коли отримувач більший за операнд
compareTo(<Quantity>)intПорівнює отримувача з операндом і повертає 0, якщо вони рівні, 1, якщо отримувач більший, або -1, якщо отримувач менший за операнд

Приклади:

Приклади виразів CEL, що використовують функції бібліотеки URL
Вираз CELПризначення
quantity("500000G").isInteger()Перевірка, чи конвертація в ціле число викликає помилку
quantity("50k").asInteger()Точна конвертація в ціле число
quantity("9999999999999999999999999999999999999G").asApproximateFloat()Конвертація у float із втратою точності
quantity("50k").add(quantity("20k"))Додати дві кількості
quantity("50k").sub(20000)Відняти ціле число від кількості
quantity("50k").add(20).sub(quantity("100k")).sub(-50000)Ланцюгове додавання та віднімання цілих чисел та кількостей
quantity("200M").compareTo(quantity("0.2G"))Порівняти дві кількості
quantity("150Mi").isGreaterThan(quantity("100Mi"))Перевірити, чи кількість більша за отримувача
quantity("50M").isLessThan(quantity("100M"))Перевірити, чи кількість менша за отримувача

Бібліотека semver Kubernetes

У Kubernetes v1.34 додано підтримку розбору та порівняння рядків, що відповідають специфікації Semantic Versioning 2.0.0. Докладніше про прийняті патерни дивіться semver.org.

  • isSemver(string) перевіряє, чи є рядок валідною семантичною версією.
  • semver(string) конвертує рядок у обʼєкт Semver або повертає помилку.

Додатковий булевий аргумент normalize можна передати у isSemver та semver. Якщо true, нормалізація прибирає префікс "v", додає 0 для minor та patch, якщо вказано лише major або major.minor, і прибирає ведучі нулі.

Після розбору через функцію semver отриманий обʼєкт Semver має такі функції-члени:

Доступні функції-члени обʼєкта Semver
Функція-членЗначення, що повертається (CEL)Опис
major()intПовертає номер основної версії (major).
minor()intПовертає номер другорядної версії (minor).
patch()intПовертає номер версії виправлення (patch).
isLessThan(<Semver>)boolПовертає true тоді й лише тоді, коли отримувач менший за операнд.
isGreaterThan(<Semver>)boolПовертає true тоді й лише тоді, коли отримувач більший за операнд.
compareTo(<Semver>)intПорівнює отримувача з операндом і повертає 0, якщо вони рівні, 1, якщо отримувач більший, або -1, якщо отримувач менший за операнд.

Приклади:

Приклади виразів CEL, що використовують функції бібліотеки semver
Вираз CELПризначення
isSemver('1.0.0')Повертає true для валідного рядка Semver.
isSemver('v1.0', true)Повертає true для рядка Semver, який можна нормалізувати.
semver('1.2.3').major()Повертає основну версію Semver.
semver('1.2.3').compareTo(semver('2.0.0')) < 0Порівнює дві версії Semver.

Докладніше: Бібліотека semver Kubernetes godoc.

Перевірка типів

CEL — це мова з поступовою типізацією.

Деякі поля API Kubernetes містять вирази CEL з повною перевіркою типів. Наприклад, правила валідації CustomResourceDefinitions проходять повну перевірку типів.

Деякі поля API Kubernetes містять вирази CEL з частковою перевіркою типів. Вираз з частковою перевіркою типів — це вираз, у якому деякі змінні статично типізовані, а інші — динамічно типізовані. Наприклад, у виразах CEL ValidatingAdmissionPolicies змінна request типізована, але змінна object динамічно типізована. У звʼязку з цим вираз, що містить request.namex, не пройде перевірку типів, оскільки поле namex не визначене. Однак object.namex пройде перевірку типів навіть тоді, коли поле namex не визначене для видів ресурсів, на які посилається object, оскільки object динамічно типізований.

Макрос has() у CEL можна використовувати у виразах CEL для перевірки наявності поля змінної з динамічною типізацією перед спробою отримати доступ до значення цього поля. Наприклад:

has(object.namex) ? object.namex == 'special' : request.name == 'special'

Використовуйте has() для перевірки наявності поля. Не використовуйте has() для перевірки наявності ключа в map. Наприклад, не пишіть has(object.metadata.labels['example.com/environment']). Для перевірки ключів у map використовуйте оператор in. Наприклад:

has(object.metadata.labels) && 'example.com/environment' in object.metadata.labels

Цей вираз перевіряє, що metadata.labels присутній перед перевіркою наявності ключа example.com/environment у map.

Інтеграція системи типів

Таблиця, що показує взаємозвʼязок між типами OpenAPIv3 та типами CEL
Тип OpenAPIv3Тип CEL
'object' з Propertiesobject / "тип повідомлення" (type(<object>) обчислюється як selfType<uniqueNumber>.path.to.object.from.self)
'object' з additionalPropertiesmap
'object' з x-kubernetes-embedded-typeobject / "тип повідомлення", 'apiVersion', 'kind', 'metadata.name' і 'metadata.generateName' неявно включені в схему
'object' з x-kubernetes-preserve-unknown-fieldsobject / "тип повідомлення", невідомі поля НЕ доступні у виразі CEL
x-kubernetes-int-or-stringОбʼєднання int або string, self.intOrString < 100 | self.intOrString == '50%' обчислюється як true і для 50, і для "50%"
'array'list
'array' з x-kubernetes-list-type=maplist з рівністю на основі map і гарантіями унікальності ключів
'array' з x-kubernetes-list-type=setlist з рівністю на основі set і гарантіями унікальності елементів
'boolean'boolean
'number' (усі формати)double
'integer' (усі формати)int (64)
немає еквівалентаuint (64)
'null'null_type
'string'string
'string' з format=byte (закодований у base64)bytes
'string' з format=datetimestamp (google.protobuf.Timestamp)
'string' з format=datetimetimestamp (google.protobuf.Timestamp)
'string' з format=durationduration (google.protobuf.Duration)

Також дивіться: Типи CEL, Типи OpenAPI, Структурні схеми Kubernetes.

Порівняння рівності для масивів з x-kubernetes-list-type типу set або map ігнорує порядок елементів. Наприклад, [1, 2] == [2, 1], якщо масиви представляють значення Kubernetes set.

Конкатенація для масивів з x-kubernetes-list-type використовує семантику типу списку:

set
X + Y виконує обʼєднання, за якого позиції всіх елементів у X у масиві зберігаються, а елементи в Y, що не перетинаються, додаються в кінець зі збереженням їх часткового порядку.
map
X + Y виконує злиття, за якого позиції всіх ключів у X у масиві зберігаються, але значення перезаписуються значеннями з Y, коли множини ключів X і Y перетинаються. Елементи Y з ключами, що не перетинаються, додаються в кінець зі збереженням їх часткового порядку.

Екранування

Тільки імена властивостей ресурсів Kubernetes форми [a-zA-Z_.-/][a-zA-Z0-9_.-/]* доступні з CEL. Доступні імена властивостей екрануються згідно з наступними правилами при доступі у виразі:

Таблиця правил екранування ідентифікаторів CEL
екрануюча послідовністьеквівалент імені властивості
__underscores____
__dot__.
__dash__-
__slash__/
__{keyword}__ЗАРЕЗЕРВОВАНЕ ключове слово CEL

Коли ви екрануєте будь-яке з ЗАРЕЗЕРВОВАНИХ ключових слів CEL, збіг повинен точно відповідати імені властивості та використовувати екранування з підкресленням (наприклад, int у слові sprint не буде екрановано, і це не буде необхідно).

Приклади екранування:

Приклади екранованих ідентифікаторів CEL
імʼя властивостіправило з екранованим імʼям властивості
namespaceself.__namespace__ > 0
x-propself.x__dash__prop > 0
redact_dself.redact__underscores__d > 0
stringself.startsWith('kube')

Обмеження ресурсів

CEL не є Тюрінг-повною мовою і пропонує різноманітні засоби безпеки для промислової експлуатації, що обмежують час виконання. Функції обмеження ресурсів CEL забезпечують зворотний звʼязок розробникам щодо складності виразів та допомагають захистити API-сервер від надмірного споживання ресурсів під час обчислення. Функції обмеження ресурсів CEL використовуються для запобігання надмірному споживанню ресурсів API-сервера під час обчислення CEL.

Ключовим елементом функцій обмеження ресурсів є одиниця вартості, яку CEL визначає як спосіб відстеження використання CPU. Одиниці вартості незалежні від системного навантаження та апаратного забезпечення. Одиниці вартості також є детермінованими; для будь-якого заданого виразу CEL та вхідних даних обчислення виразу інтерпретатором CEL завжди призведе до однакової вартості.

Багато з основних операцій CEL мають фіксовані витрати. Найпростіші операції, такі як порівняння (наприклад, <), мають вартість 1. Деякі мають вищу фіксовану вартість, наприклад, оголошення літералів списку мають фіксовану базову вартість 40 одиниць вартості.

Виклики функцій, реалізованих у рідному коді, оцінюються на основі часової складності операції. Наприклад, операції, що використовують регулярні вирази, такі як match та find, оцінюються з використанням приблизної вартості length(regexString)*length(inputString). Приблизна вартість відображає найгірший випадок часової складності реалізації RE2 в Go.

Бюджет вартості під час виконання

Усі вирази CEL, які обчислює Kubernetes, обмежені бюджетом вартості під час виконання. Бюджет вартості під час виконання — це оцінка фактичного використання CPU, що обчислюється шляхом інкрементування лічильника одиниць вартості під час інтерпретації виразу CEL. Якщо інтерпретатор CEL виконає занадто багато інструкцій, бюджет вартості під час виконання буде перевищено, виконання виразу буде зупинено і результатом стане помилка.

Деякі ресурси Kubernetes визначають додатковий бюджет вартості під час виконання, який обмежує виконання декількох виразів. Якщо загальна вартість виразів перевищує бюджет, виконання виразів буде зупинено і результатом стане помилка. Наприклад, валідація власного ресурсу користувача має бюджет вартості під час виконання на одну валідацію для всіх правил валідації, які обчислюються для валідації власного ресурсу.

Обмеження оціночної вартості

Для деяких ресурсів Kubernetes API-сервер також може перевірити, чи не буде найгірший випадок оціненого часу виконання виразів CEL надто дорогим для виконання. Якщо так, API-сервер запобігає записуванню виразу CEL у ресурси API, відхиляючи операції створення або оновлення, що містять вираз CEL для ресурсів API. Ця функція пропонує сильнішу гарантію, що вирази CEL, записані у ресурс API, будуть обчислені під час виконання без перевищення бюджету вартості під час виконання.