# Server-Side Apply

LLMS index: [llms.txt](/llms.txt)

---

<!-- overview -->








  <div class="feature-state-notice feature-stable" title="Функціональна можливість: ServerSideApply">
              <span class="feature-state-name">СТАН ФУНКЦІОНАЛУ:</span> 
              <code>Kubernetes v1.22 [stable]</code>(стандартно увімкнено)</div>


Kubernetes підтримує співпрацю кількох аплікаторів для керування полями одного [обʼєкта](/docs/concepts/overview/working-with-objects/).

Server-Side Apply (Серверне застосування) надає необовʼязковий механізм для контролера вашого кластера, щоб відстежувати зміни в полях обʼєкта. На рівні конкретного ресурсу, Server-Side Apply записує та відстежує інформацію про контроль над полями цього обʼєкта.

Server-Side Apply допомагає користувачам та <a class='glossary-tooltip' title='Контролер — цикл управління, що спостерігає за загальним станом кластера через apiserver і вносить зміни в намаганні наблизити поточний стан до бажаного.' data-bs-toggle='tooltip' data-bs-placement='top' href='/uk/docs/concepts/architecture/controller/' target='_blank' aria-label='контролерам'>контролерам</a> керувати своїми ресурсами за допомогою декларативної конфігурації. Клієнти можуть створювати та змінювати <a class='glossary-tooltip' title='Сутність у системі Kubernetes, що представляє частину стану вашого кластера.' data-bs-toggle='tooltip' data-bs-placement='top' href='/uk/docs/concepts/overview/working-with-objects/#kubernetes-objects' target='_blank' aria-label='обʼєкти'>обʼєкти</a> декларативно, подаючи їх _повністю визначений намір_.

Повністю визначений намір — це частковий обʼєкт, який містить лише ті поля та значення, щодо яких у користувача є чітке уявлення. Цей намір або створює новий обʼєкт (використовуючи стандартні значення для невизначених полів), або [обʼєднується](#merge-strategy) з наявним обʼєктом через API сервер.

[Порівняння з Client-Side Apply](#comparison-with-client-side-apply) пояснює, як Server-Side Apply відрізняється від початкової реалізації `kubectl apply` на стороні клієнта.

<!-- body -->

## Управління полями {#field-management}

Kubernetes API сервер відстежує _керовані поля_ для всіх новостворених обʼєктів.

При спробі застосувати обʼєкт, поля, які мають інше значення і належать іншому [менеджеру](#managers), спричинять [конфлікт](#conflicts). Це зроблено для того, щоб сигналізувати, що операція може скасувати зміни іншого спільника. Записи до обʼєктів з керованими полями можуть бути примусовими, в такому випадку значення будь-якого конфліктного поля буде перезаписане, а право власності передане.

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

Для того, щоб користувач міг керувати полем в контексті Server-Side Apply, він повинен покладатися на те, що значення поля не зміниться. Користувач, який останнім висловив свою думку щодо значення поля, буде записаний як поточний менеджер поля. Це можна зробити, змінивши дані менеджера поля явним чином за допомогою HTTP `POST` (**створення**), `PUT` (**оновлення**), або не-застосувального `PATCH` (**патч**). Ви також можете оголосити та записати менеджера поля, включивши значення для цього поля в операції Server-Side Apply.

Запит на **патч** в контексті Server-Side Apply вимагає від клієнта вказати свою ідентичність як [менеджера поля](#managers). При використанні Server-Side Apply спроба змінити поле, що контролюється іншим менеджером, призведе до відхилення запиту, якщо клієнт не виконає примусове перевизначення. Для деталей щодо примусових перевизначень дивіться [Конфлікти](#conflicts).

Коли два або більше аплікатора встановлюють поле на однакове значення, вони спільно володіють цим полем. Будь-яка спроба змінити значення спільного поля будь-ким з аплікаторів призведе до конфлікту. Спільні власники поля можуть відмовитися від права власності на поле, здійснивши запит на **патч** в контексті Server-Side Apply, який не включає це поле.

Деталі управління полями зберігаються в полі `managedFields`, яке є частиною [`metadata`](/docs/reference/kubernetes-api/common-definitions/object-meta/) обʼєкта.

Якщо ви видалите поле з маніфесту і застосуєте цей маніфест, Server-Side Apply перевірить, чи є інші менеджери полів, які також володіють цим полем. Якщо поле не належить жодному іншому менеджеру полів, воно буде або видалене з поточного обʼєкта, або скинуте до стандартного значення, якщо таке є. Те саме правило застосовується до елементів асоціативного списку або map.

У порівнянні з (застарілою) [`kubectl.kubernetes.io/last-applied-configuration`](/docs/reference/labels-annotations-taints/#kubectl-kubernetes-io-last-applied-configuration) анотацією, яка управляється `kubectl`, Server-Side Apply використовує більш декларативний підхід, який відстежує управління полями користувача (або клієнта), а не останній застосований стан користувача. Побічним ефектом використання Server-Side Apply є також доступність інформації про те, який менеджер поля управляє кожним полем в обʼєкті.

### Приклад {#ssa-example-configmap}

Простий приклад обʼєкта, створеного за допомогою Server-Side Apply, може виглядати так:


<div class="alert alert-info" role="note"><h4 class="alert-heading">Примітка:</h4><code>kubectl get</code> типово пропускає керовані поля. Додайте <code>--show-managed-fields</code> щоб показати <code>managedFields</code> у виводі в формаі <code>json</code> або <code>yaml</code>.</div>


```yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: test-cm
  namespace: default
  labels:
    test-label: test
  managedFields:
  - manager: kubectl
    operation: Apply # зверніть увагу на великі літери: "Apply" (або "Update")
    apiVersion: v1
    time: "2010-10-10T0:00:00Z"
    fieldsType: FieldsV1
    fieldsV1:
      f:metadata:
        f:labels:
          f:test-label: {}
      f:data:
        f:key: {}
data:
  key: some value
```

Цей приклад обʼєкта ConfigMap містить один запис про управління полями в `.metadata.managedFields`. Запис управління полями складається з основної інформації про саму сутність, що виконує управління, а також з деталей про поля, якими управляють, та відповідну операцію (`Apply` або `Update`). Якщо запит, що останнім змінив це поле, був **патчем** Server-Side Apply, тоді значення `operation` буде `Apply`; в іншому випадку, це буде `Update`.

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

Однак, можливо змінити `.metadata.managedFields` за допомогою операції **оновлення** або **патчу**, які не використовують Server-Side Apply. Це наполегливо не рекомендується, але може бути доцільно спробувати, якщо, наприклад, `.metadata.managedFields` потрапить у неконсистентний стан (що не повинно відбуватися при нормальній роботі).

Формат `managedFields` описаний у [довіднику API Kubernetes](/docs/reference/kubernetes-api/common-definitions/object-meta/#System).

<div class="alert alert-caution" role="note"><h4 class="alert-heading">Увага:</h4>Поле <code>.metadata.managedFields</code> керується API сервером. Ви повинні уникати його ручного оновлення.</div>


### Конфлікти {#conflicts}

_Конфлікт_ — це спеціальна помилка статусу, яка виникає, коли операція `Apply` намагається змінити поле, на яке інший менеджер також заявляє права на керування. Це запобігає ненавмисному перезапису значення, встановленого іншим користувачем. У разі конфлікту аплікатор має 3 варіанти для вирішення конфліктів:

* **Перезаписати значення, стати єдиним менеджером:** Якщо перезапис значення був навмисним (або якщо аплікатор є автоматичним процесом, таким як контролер), аплікатор повинен встановити параметр запиту `force` в `true` (для `kubectl apply` використовується параметр командного рядка `--force-conflicts`) і повторити запит. Це змусить операцію завершитись успішно, змінить значення поля та видалить це поле з усіх інших записів менеджерів у `managedFields`.

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

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

### Менеджери полів {#managers}

Менеджери визначають окремі робочі процеси, які змінюють обʼєкт (особливо корисно при конфліктах!), і можуть бути вказані через параметр запиту [`fieldManager`](/docs/reference/kubernetes-api/common-parameters/common-parameters/#fieldManager) як частина запиту на зміни. Коли ви застосовуєте зміни до ресурсу, параметр `fieldManager` є обовʼязковим. Для інших оновлень сервер API визначає ідентифікатор менеджера поля з заголовка HTTP "User-Agent:" (якщо він присутній).

Коли ви використовуєте інструмент `kubectl` для виконання операції Server-Side Apply, `kubectl` типово встановлює ідентифікатор менеджера в `"kubectl"`.

## Серіалізація {#serialization}

На рівні протоколу Kubernetes представляє тіла повідомлень Server-Side Apply у форматі [YAML](https://yaml.org/), з медіа типом `application/apply-patch+yaml`.


<div class="alert alert-info" role="note"><h4 class="alert-heading">Примітка:</h4><p>Незалежно від того, чи ви подаєте дані у форматі JSON чи YAML, використовуйте  <code>application/apply-patch+yaml</code> як значення заголовка <code>Content-Type</code>.</p>
<p>Усі документи JSON є дійсними документами YAML. Однак, у Kubernetes є помилка, яка полягає в тому, що він використовує парсер YAML, який не повністю реалізує специфікацію YAML. Деякі JSON екранування можуть не бути розпізнаними.</p>
</div>


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

Ось приклад тіла повідомлення Server-Side Apply (повністю специфікований намір):

```json
{
  "apiVersion": "v1",
  "kind": "ConfigMap"
}
```

(це зробить оновлення без змін, за умови, що це було надіслано як тіло **patch** запиту до дійсного ресурсу `v1/configmaps`, з відповідним заголовком запиту `Content-Type`).

## Операції з області управління полями {#apply-and-update}

Операції API Kubernetes, де враховується управління полями, включають:

1. Server-Side Apply (HTTP `PATCH`, з типом контенту `application/apply-patch+yaml`)
2. Заміна наявного обʼєкта (**update** для Kubernetes; `PUT` на рівні HTTP)

Обидві операції оновлюють `.metadata.managedFields`, але поводяться трохи по-різному.

Якщо не вказано примусове перезаписування, операція apply, що зустрічає конфлікти на рівні полів, завжди зазнає невдачі; у противагу, якщо зміну здійснено за допомогою **update**, що впливає на кероване поле, конфлікт ніколи не призводить до невдачі операції.

Усі запити Server-Side Apply **patch** повинні ідентифікувати себе, надаючи параметр запиту `fieldManager`, тоді як цей параметр запиту є необовʼязковим для операцій **update**. Нарешті, при використанні операції `Apply` ви не можете визначати `managedFields` у тілі запиту, який ви надсилаєте.

Приклад обʼєкта з декількома менеджерами може виглядати так:

```yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: test-cm
  namespace: default
  labels:
    test-label: test
  managedFields:
  - manager: kubectl
    operation: Apply
    time: '2019-03-30T15:00:00.000Z'
    apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:metadata:
        f:labels:
          f:test-label: {}
  - manager: kube-controller-manager
    operation: Update
    apiVersion: v1
    time: '2019-03-30T16:00:00.000Z'
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        f:key: {}
data:
  key: new value
```

У цьому прикладі друга операція була виконана як **update** менеджером з назвою `kube-controller-manager`. Запит на оновлення був успішним і змінив значення в полі даних, що призвело до зміни управління цим полем на `kube-controller-manager`.

Якби була спроба застосувати це оновлення за допомогою Server-Side Apply, запит зазнав би невдачі через конфлікт управління.

## Стратегія злиття {#merge-strategy}

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

Коли користувач надсилає обʼєкт із повністю специфікованим наміром на точку доступу Server-Side Apply, сервер зʼєднує його з поточним обʼєктом, надаючи перевагу значенню з тіла запиту, якщо воно вказане в обох місцях. Якщо набір елементів, присутніх у застосованій конфігурації, не є надмножиною елементів, застосованих тим самим користувачем минулого разу, кожен відсутній елемент, яким не керують інші аплікатори, видаляється. Для отримання додаткової інформації про те, як схема обʼєкта використовується для прийняття рішень під час злиття, дивіться [sigs.k8s.io/structured-merge-diff](https://sigs.k8s.io/structured-merge-diff).

API Kubernetes (та код Go, який реалізує це API для Kubernetes) дозволяє визначати _маркери стратегії злиття_. Ці маркери описують підтримувану стратегію злиття для полів в обʼєктах Kubernetes. Для <a class='glossary-tooltip' title='Власний код, який визначає ресурс для додавання до сервера API вашого кластера Kubernetes без створення власного сервера.' data-bs-toggle='tooltip' data-bs-placement='top' href='/uk/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/' target='_blank' aria-label='CustomResourceDefinition'>CustomResourceDefinition</a>, ви можете встановити ці маркери під час визначення власного ресурсу.

| Маркер Golang | Розширення OpenAPI | Можливі значення | Опис        |
|---------------|--------------------|------------------|-------------|
| `//+listType` | `x-kubernetes-list-type` | `atomic`/`set`/`map` | Застосовується до списків. `set` застосовується до списків, які включають лише скалярні елементи. Ці елементи повинні бути унікальними. `map` застосовується до списків вкладених типів. Значення ключів (див. `listMapKey`) повинні бути унікальними в списку. `atomic` може застосовуватися до будь-якого списку. Якщо налаштовано як `atomic`, весь список замінюється під час злиття. У будь-який момент часу список належить одному менеджеру. Якщо `set` або `map`, різні менеджери можуть окремо керувати елементами. |
| `//+listMapKey` | `x-kubernetes-list-map-keys` | Список імен полів, наприклад, `["port", "protocol"]` | Застосовується лише при `+listType=map`. Список імен полів, значення яких унікально ідентифікують елементи у списку. Хоча ключів може бути багато, `listMapKey` є одниною, тому що ключі потрібно вказувати індивідуально в типі Go. Поля ключів повинні бути скалярами. |
| `//+mapType` | `x-kubernetes-map-type` | `atomic`/`granular` | Застосовується до map. `atomic` означає, що map можна замінити повністю тільки одним менеджером. `granular` означає, що map підтримує окремих менеджерів, які оновлюють окремі поля. |
| `//+structType` | `x-kubernetes-map-type` | `atomic`/`granular` | Застосовується до структур; інакше те ж використання та анотація OpenAPI, як `//+mapType`.|

Якщо `listType` відсутній, сервер API інтерпретує `patchStrategy=merge` як `listType=map` і відповідний маркер `patchMergeKey` як `listMapKey`.

Тип списку `atomic` є рекурсивним.

(У коді [Go](https://go.dev/) для Kubernetes, ці маркери вказуються як коментарі, і авторам коду не потрібно повторювати їх як теґи полів).

## Власні ресурси та Серверне застосування{#custom-resources-and-server-side-apply}

Стандартно, Server-Side Apply обробляє власні ресурси користувачів як неструктуровані дані. Усі ключі розглядаються як поля структури, а всі списки вважаються атомарними.

Якщо у визначенні CustomResourceDefinition міститься [схема](/docs/reference/generated/kubernetes-api/v1.36#jsonschemaprops-v1-apiextensions-k8s-io), яка містить анотації, визначені у попередньому розділі [Стратегія злиття](#merge-strategy), ці анотації будуть використовуватись під час злиття обʼєктів цього типу.

### Сумісність при зміні топології {#compatibility-accross-topology-changes}

У рідкісних випадках автор CustomResourceDefinition (CRD) або вбудованого ресурсу може захотіти змінити специфічну топологію поля у своєму ресурсі, не збільшуючи його версію API. Зміна топології типів шляхом оновлення кластера або CRD має різні наслідки при оновленні наявних обʼєктів. Є дві категорії змін: коли поле переходить від `map`/`set`/`granular` до `atomic` і навпаки.

Коли `listType`, `mapType` або `structType` змінюються з `map`/`set`/`granular` на `atomic`, весь список, map або структура наявних обʼєктів будуть в підсумку належати акторам, які володіли елементом цих типів. Це означає, що будь-яка подальша зміна цих обʼєктів призведе до конфлікту.

Коли `listType`, `mapType` або `structType` змінюються з `atomic` на `map`/`set`/`granular`, сервер API не може визначити нову власність цих полів. Через це конфлікти не виникатимуть під час оновлення обʼєктів із цими полями. Тому не рекомендується змінювати тип із `atomic` на `map`/`set`/`granular`.

Візьмемо, наприклад, власний ресурс користувача ресурс:

```yaml
---
apiVersion: example.com/v1
kind: Foo
metadata:
  name: foo-sample
  managedFields:
  - manager: "manager-one"
    operation: Apply
    apiVersion: example.com/v1
    fieldsType: FieldsV1
    fieldsV1:
      f:spec:
        f:data: {}
spec:
  data:
    key1: val1
    key2: val2
```

До того, як `spec.data` зміниться з `atomic` на `granular`, `manager-one` володіє полем `spec.data` і всіма полями в ньому (`key1` та `key2`). Коли CRD змінюється, щоб зробити `spec.data` `granular`, `manager-one` продовжує володіти полем верхнього рівня `spec.data` (що означає, що жоден інший менеджер не може видалити map `data` без конфлікту), але він більше не володіє `key1` та `key2`, тому інший менеджер може змінити або видалити ці поля без конфлікту.

## Використання Server-Side Apply в контролер {#using-server-side-apply-in-a-controller}

Як розробник контролера, ви можете використовувати Server-Side Apply як спосіб спростити логіку оновлення вашого контролера. Основні відмінності від кead-modify-write та/або patch наступні:

* застосований обʼєкт повинен містити всі поля, які цікавлять контролер.
* немає способу видалити поля, які не були застосовані контролером раніше (контролер все ще може надіслати **patch** або **update** для цих випадків використання).
* обʼєкт не обовʼязково має бути прочитаним перед тим; `resourceVersion` не потрібно вказувати.

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

## Передача власності {#transferring-ownership}

Окрім контролю конкурентності, забезпеченого [вирішенням конфліктів](#conflicts), Server-Side Apply надає можливості для виконання координованих переходів власності полів від користувачів до контролерів.

Це найкраще пояснюється на прикладі. Розглянемо, як безпечно перевести власність поля `replicas` від користувача до контролера, дозволяючи автоматичне горизонтальне масштабування для Deployment, використовуючи ресурс HorizontalPodAutoscaler та його супровідний контролер.

Скажімо, користувач визначив Deployment з `replicas`, встановленим на бажане значення:


















<div class="highlight code-sample">
    <div class="copy-code-icon">
    <a href="https://raw.githubusercontent.com/kubernetes/website/main/content/uk/examples/application/ssa/nginx-deployment.yaml" download="application/ssa/nginx-deployment.yaml"><code>application/ssa/nginx-deployment.yaml</code>
    </a><img src="/images/copycode.svg" class="icon-copycode" onclick="copyCode('application-ssa-nginx-deployment-yaml')" title="Копіювати application/ssa/nginx-deployment.yaml до буферу обміну"></img></div>
    <div class="includecode" id="application-ssa-nginx-deployment-yaml"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">apps/v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Deployment</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">nginx-deployment</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">labels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l">nginx</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">replicas</span><span class="p">:</span><span class="w"> </span><span class="m">3</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">selector</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">matchLabels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l">nginx</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">template</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">labels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l">nginx</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">containers</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">nginx</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">nginx:1.14.2</span><span class="w">
</span></span></span></code></pre></div></div>
</div>

І користувач створив Deployment, використовуючи Server-Side Apply, наступним чином:

```shell
kubectl apply -f https://k8s.io/examples/application/ssa/nginx-deployment.yaml --server-side
```

Пізніше автоматичне масштабування увімкнено для Deployment; наприклад:

```shell
kubectl autoscale deployment nginx-deployment --cpu=50% --min=1 --max=10
```

Тепер користувач хоче видалити `replicas` з конфігурації, щоб вони випадково не конфліктували з HorizontalPodAutoscaler (HPA) та його контролером. Однак виникають перегони: може пройти деякий час, перш ніж HPA вирішить змінити `.spec.replicas`; якщо користувач видаляє `.spec.replicas` перед тим, як HPA запише в поле і стане його власником, тоді API-сервер встановить `.spec.replicas` на 1 (стандартна кількість реплік для Deployment). Це не те, що хоче користувач, ще й тимчасово — це може погіршити робоче навантаження.

Є два рішення:

* (базовий) Залиште `replicas` в конфігурації; коли HPA нарешті запише в це поле, система сповістить користувачу про конфлікт при спробі зробити це. На цьому етапі безпечно видалити його з конфігурації.

* (більш розширений) Однак, якщо користувач не хоче чекати, наприклад, через те що вони хочуть, щоб кластер був зрозумілим для їх колег, тоді вони можуть виконати наступні кроки, щоб зробити видалення `replicas` з їх конфігурації безпечним:

Спочатку користувач визначає новий маніфест, що містить лише поле `replicas`:

```yaml
# Збережіть цей файл як 'nginx-deployment-replicas-only.yaml'.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
```


<div class="alert alert-info" role="note"><h4 class="alert-heading">Примітка:</h4>Файл YAML для SSA у цьому випадку містить лише поля, які ви хочете змінити. Вам не слід надавати повністю сумісний з Deployment маніфест, якщо ви хочете змінити лише поле <code>spec.replicas</code>, використовуючи SSA.</div>


Користувач застосовує цей маніфест, використовуючи приватне імʼя менеджера полів. У цьому прикладі користувач вибрав `handover-to-hpa`:

```shell
kubectl apply -f nginx-deployment-replicas-only.yaml \
  --server-side --field-manager=handover-to-hpa \
  --validate=false
```

Якщо застосування призводить до конфлікту з контролером HPA, тоді нічого не робіть. Конфлікт вказує на те, що контролер вже вимагає поле на цьому етапі.

На цьому етапі користувач може видалити поле `replicas` з маніфесту:


















<div class="highlight code-sample">
    <div class="copy-code-icon">
    <a href="https://raw.githubusercontent.com/kubernetes/website/main/content/uk/examples/application/ssa/nginx-deployment-no-replicas.yaml" download="application/ssa/nginx-deployment-no-replicas.yaml"><code>application/ssa/nginx-deployment-no-replicas.yaml</code>
    </a><img src="/images/copycode.svg" class="icon-copycode" onclick="copyCode('application-ssa-nginx-deployment-no-replicas-yaml')" title="Копіювати application/ssa/nginx-deployment-no-replicas.yaml до буферу обміну"></img></div>
    <div class="includecode" id="application-ssa-nginx-deployment-no-replicas-yaml"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">apps/v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Deployment</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">nginx-deployment</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">labels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l">nginx</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">selector</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">matchLabels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l">nginx</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">template</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">labels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l">nginx</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">containers</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">nginx</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">nginx:1.14.2</span><span class="w">
</span></span></span></code></pre></div></div>
</div>

Зауважте, що кожного разу, коли контролер HPA встановлює значення поля `replicas` на нове значення, тимчасовий менеджер полів більше не володіє жодними полями й буде автоматично видалений. Додаткового прибирання не потрібно.

### Передача власності між менеджерами {#transferring-ownership-between-managers}

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

## Порівняння з Client-Side Apply {#comparison-with-client-side-apply}

Server-Side Apply призначений як для заміни початкової реалізації команди `kubectl apply` на стороні клієнта, так і для забезпечення простого та ефективного механізму для <a class='glossary-tooltip' title='Контролер — цикл управління, що спостерігає за загальним станом кластера через apiserver і вносить зміни в намаганні наблизити поточний стан до бажаного.' data-bs-toggle='tooltip' data-bs-placement='top' href='/uk/docs/concepts/architecture/controller/' target='_blank' aria-label='контролерів'>контролерів</a>, щоб впроваджувати свої зміни.

Порівняно з анотацією `last-applied`, якою керує `kubectl`, Server-Side Apply використовує більш декларативний підхід, що відстежує управління полями обʼєкта, а не останній стан, застосований користувачем. Це означає, що як побічний ефект використання Server-Side Apply, стає доступною інформація про те, який менеджер полів керує кожним полем в обʼєкті.

Наслідком виявлення та вирішення конфліктів, реалізованих у Server-Side Apply, є те, що аплікатор завжди має актуальні значення полів у своєму локальному стані. Якщо ні, то він отримає конфлікт під час наступного застосування. Будь-який з трьох варіантів розвʼязання конфліктів призводить до того, що застосована конфігурація стає актуальною підмножиною полів обʼєкта на сервері.

Це відрізняється від Client-Side Apply, де застарілі значення, які були перезаписані іншими користувачами, залишаються в локальній конфігурації аплікатора. Ці значення стають точними лише тоді, коли користувач оновлює конкретне поле, якщо взагалі оновлює, і аплікатор не має способу дізнатися, чи наступне застосування перезапише зміни інших користувачів.

Ще однією відмінністю є те, що аплікатор, використовуючи Client-Side Apply, не може змінити версію API, яку він використовує, тоді як Server-Side Apply підтримує цей випадок використання.

## Міграція між client-side і server-side apply {#migration-between-client-side-and-server-side-apply}

### Перехід з client-side apply на server-side apply {#migrating-from-client-side-to-server-side-apply}

Користувачі client-side apply, які керують ресурсом за допомогою `kubectl apply`, можуть почати використовувати server-side apply з наступним прапорцем.

```shell
kubectl apply --server-side [--dry-run=server]
```

Стандартно, управління полями обʼєкта переходить з client-side apply на kubectl server-side apply без виникнення конфліктів.

<div class="alert alert-caution" role="note"><h4 class="alert-heading">Увага:</h4><p>Тримайте анотацію <code>last-applied-configuration</code> в актуальному стані. Анотація визначає поля, якими керує client-side apply. Будь-які поля, якими не керує client-side apply, викликають конфлікти.</p>
<p>Наприклад, якщо ви використовували <code>kubectl scale</code> для оновлення поля replicas після client-side apply, тоді це поле не належить client-side apply і створює конфлікти при <code>kubectl apply --server-side</code>.</p>
</div>


Ця поведінка стосується server-side apply з менеджером полів `kubectl`. Як виняток, ви можете відмовитися від цієї поведінки, вказавши іншого, не стандартного менеджера полів, як показано в наступному прикладі. Стандартним менеджером полів для kubectl server-side apply є `kubectl`.

```shell
kubectl apply --server-side --field-manager=my-manager [--dry-run=server]
```

### Повернення з server-side apply на client-side apply {#downgrading-from-server-side-to-client-side-apply}

Якщо ви керуєте ресурсом за допомогою `kubectl apply --server-side`, ви можете перейти на client-side apply безпосередньо за допомогою `kubectl apply`.

Повернення працює тому, що kubectl Server-Side Apply тримає анотацію `last-applied-configuration` в актуальному стані, якщо ви використовуєте `kubectl apply`.

Ця поведінка стосується Server-Side Apply з менеджером полів kubectl. Як виняток, ви можете відмовитися від цієї поведінки, вказавши іншого, не стандартного менеджера полів, як показано в наступному прикладі. Стандартним менеджером полів для kubectl server-side apply є `kubectl`.

```shell
kubectl apply --server-side --field-manager=my-manager [--dry-run=server]
```

## Реалізація API {#api-implementation}

Дієслово `PATCH` (для обʼєкту, який підтримує Server-Side Apply) може приймати неофіційний тип контенту `application/apply-patch+yaml`. Користувачі Server-Side Apply можуть надіслати частково специфіковані обʼєкти у вигляді YAML як тіло запиту `PATCH` до URI ресурсу. При застосуванні конфігурації слід завжди включати всі поля, які є важливими для результату (наприклад, бажаний стан), який ви хочете визначити.

Всі JSON-повідомлення є дійсними YAML-повідомленнями. Тому, на додачу до використання тіл запитів YAML для запитів Server-Side Apply, ви також можете використовувати тіла запитів JSON, оскільки вони також є дійсними YAML. У будь-якому випадку, використовуйте тип медіа `application/apply-patch+yaml` для HTTP-запиту.

### Контроль доступу і дозволи {#rbac-and-permissions}

Оскільки Server-Side Apply є типом `PATCH`, субʼєкт (такий як Роль для Kubernetes <a class='glossary-tooltip' title='Управління рішеннями з авторизації, яке дозволяє адміністраторам динамічно налаштовувати політики доступу через API Kubernetes.' data-bs-toggle='tooltip' data-bs-placement='top' href='/uk/docs/reference/access-authn-authz/rbac/' target='_blank' aria-label='RBAC'>RBAC</a>) потребує дозволу **patch** для редагування наявних ресурсів, а також дозволу на дієслово **create** для створення нових ресурсів за допомогою Server-Side Apply.

## Очищення `managedFields` {#clearing-managedfields}

Можливо видалити всі `managedFields` з обʼєкта, переписавши їх за допомогою **patch** (JSON Merge Patch, Strategic Merge Patch, JSON Patch) або через **update** (HTTP `PUT`); іншими словами, через будь-яку операцію запису, окрім **apply**. Це можна зробити, переписавши поле `managedFields` порожнім записом. Два приклади:

```console
PATCH /api/v1/namespaces/default/configmaps/example-cm
Accept: application/json
Content-Type: application/merge-patch+json

{
  "metadata": {
    "managedFields": [
      {}
    ]
  }
}
```

```console
PATCH /api/v1/namespaces/default/configmaps/example-cm
Accept: application/json
Content-Type: application/json-patch+json
If-Match: 1234567890123456789

[{"op": "replace", "path": "/metadata/managedFields", "value": [{}]}]
```

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

У випадках, коли операція скидання комбінується зі змінами інших полів, крім `managedFields`, це призведе до того, що спочатку `managedFields` буде скинуто, а інші зміни будуть оброблені пізніше. У результаті аплікатор бере на себе відповідальність за будь-які поля, оновлені в тому ж запиті.


<div class="alert alert-info" role="note"><h4 class="alert-heading">Примітка:</h4>Server-Side Apply не правильно відстежує власність на субресурси, які не отримують тип обʼєкта ресурсу. Якщо ви використовуєте Server-Side Apply з таким субресурсом, змінені поля можуть не відслідковуватися.</div>


## Що далі

Ви можете прочитати про `managedFields` у довіднику API Kubernetes для верхнього рівня поля [`metadata`](/docs/reference/kubernetes-api/common-definitions/object-meta/).
