- Базовый стиль — **прагматичная краткая техническая речь**. Она следует уровню автора в конкретном году: ранний автор объясняет через собственную задачу, поздний — через измеримый компромисс и воспроизводимый процесс.
- Пишем коротко и предметно: **симптом → причина → проверка → действие**. Предпочитаем глаголы и наблюдаемые факты: «запрос вернул 403», «фильтр исключает запись», «метрика выросла на 18%».
- Пишем коротко и предметно: **симптом → причина → проверка → действие**. Предпочитаем глаголы и наблюдаемые факты: «запрос вернул 403», «фильтр исключает запись», «метрика выросла на 18%».
- Один абзац — одна мысль; одно предложение не пытается одновременно описать проблему, историю команды и решение.
- Один абзац — одна мысль; одно предложение не пытается одновременно описать проблему, историю команды и решение.
- Термин используется только там, где он точнее обычного слова. После первого появления даём расшифровку или пример.
- Термин используется только там, где он точнее обычного слова. После первого появления даём расшифровку или пример.
На 31 июля 2026 года строгий аудит проходит 229 из 358 созданных материалов. Остальные 129 не считаются «почти готовыми»: их нужно заменить, а не косметически удлинить.
На 31 июля 2026 года строгий аудит проходит 232 из 358 созданных материалов. Остальные 126 не считаются «почти готовыми»: их нужно заменить, а не косметически удлинить.
- Голос: M7, июнь 2024. Три материала начинают с конкретной ситуации и её цены, затем проходят «симптом → причина → проверка → действие». Каждый текст сопоставляет declaration, профиль управляемой нагрузки и смысл наблюдаемого поведения Pod, а не объявляет один YAML field универсальным ответом.
- Созданы ровно пять sidecar-файлов: этот review, import-safe script и три локальные SVG. Overlay, README, очередь, <code>articles.json</code>, Git и чужие файлы не менялись; commit и push не выполнялись.
- Fixture содержит только versioned fixed synthetic JS-объекты в памяти. Она не читает files, manifest, cluster, CI, network, HTTP, trace, telemetry или production и не изменяет их. Поле <code>syntheticObservedPodBehavior</code> явно помечено как <code>embedded-fixed-js-object-not-telemetry</code>; оно не является и не имитирует <code>kubectl</code>, CI output, metrics или production observation.
## Проход 1 — источники, техника и модель
- Историческая граница проверена 31.07.2026 по первичным Kubernetes материалам, доступным до июня 2024. [Kubernetes v1.30: Uwubernetes, 17.04.2024](https://kubernetes.io/blog/2024/04/17/kubernetes-v1-30-release/) фиксирует публичный выпуск v1.30 до нужного месяца, но не подменяет версию или настройки чужой среды.
- [Resource Management for Pods and Containers, snapshot 07.03.2024](https://github.com/kubernetes/website/blob/ab0631a407aa6bcf6241818d7dd55aa164dc806f/content/en/docs/concepts/configuration/manage-resources-containers.md) использован узко: scheduler опирается на request при размещении, kubelet и runtime применяют limit, а limit без request может стать request. Статьи не выдают limit за гарантированный throughput или фиксированное capacity number.
- [Horizontal Pod Autoscaling, snapshot 26.03.2024](https://github.com/kubernetes/website/blob/0568c8af60bf24624f1ac5275969cebf672e874e/content/en/docs/tasks/run-application/horizontal-pod-autoscale.md) подтверждает, что CPU utilization считается относительно request; если relevant request отсутствует, HPA не действует по этой метрике. В P76 это оформлено отдельной отрицательной веткой <code>fixed-warmup-request-missing-v1</code>, а не утверждением о поведении реального controller.
- [Pod Lifecycle and readiness gates, snapshot 24.05.2024](https://github.com/kubernetes/website/blob/77407a728ac7d93e1601a767f52b3c8a53b0fd79/content/en/docs/concepts/workloads/pods/pod-lifecycle.md) задаёт границу <code>ContainersReady</code>, <code>Ready</code> и custom readiness gate: для Ready нужны ready containers и все declared gates True. P76 не придумывает producer condition, feature gate, owner или recovery path для внешней системы.
- [Configure Liveness, Readiness and Startup Probes, snapshot 13.04.2024](https://github.com/kubernetes/website/blob/2a6ec81df0a8b7e89dfc8af0e2651d56f4e11b28/content/en/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes.md) использован для traffic semantics readiness и отделения startup от liveness/readiness. Текст не превращает readiness в root-cause diagnosis, telemetry, latency probe или dependency SLO.
- Модель имеет один version marker <code>synthetic-container-load-profile-v1</code>, закрытый input contract и ровно три named fixed cases. Каждый case хранит <code>declaredManifest</code>, <code>managedLoad</code> и <code>syntheticObservedPodBehavior</code> как frozen literals. Plan повторно строит canonical report и сравнивает весь object; подмена verdict, observation или добавление внешнего поля отвергаются.
- Самостоятельный model review проверяет отрицательные ветки для manifest file, cluster, CI, network, HTTP, trace и production fields; их нельзя передать как скрытый input. Rollback принимает только canonical synthetic review draft и возвращает явное отсутствие операций над manifest, cluster, CI, сетью, trace, telemetry и production.
## Проход 2 — стиль, объём и голос
- Основной текст без раздела источников по <code>audit:draft</code>: practice — **11 931** знак, mechanism — **11 997**, field — **11 608**. Все три значения находятся в целевом коридоре 9–12 тыс. и обязательном диапазоне 5 000–15 000 знаков.
- Первые два абзаца practice разбирают цену copied request/limit/HPA values; mechanism — цену путаницы HPA signal и traffic eligibility и процент без denominator; field — цену трактовки Unready или CPU как немедленного scale action. Это конкретные учебные ситуации, не истории о реальном кластере.
- Во всех статьях есть содержательная figure с alt и caption, рабочая table, исполнимый JS example, ordered route, ограничения, rollback и следующий проверяемый шаг. Код не содержит YAML, <code>kubectl</code>, HTTP request, CI command или telemetry fixture: только import-safe functions и fixed in-memory object literals.
- M7 выдержан: короткие технические утверждения привязаны к request, limit, readiness, gate, metric, owner или evidence boundary. Нет обещаний, что HPA устраняет очередь, что readiness доказывает capacity, что limit даёт throughput, или что fixture подтверждает behaviour реальной среды.
- После сокращения финальных редакторских проходов capacity curve не используется как прогноз: она прямо подписана fixed synthetic teaching data. Полевой материал называет blocker там, где отсутствует request или смысл readiness, вместо предложения «масштабировать на всякий случай».
## Проход 3 — mobile visual, SVG safety и проверки
- Три SVG отвечают на разные вопросы: <code>pod-lifecycle</code> отделяет profile, declaration и traffic eligibility; <code>capacity-curve</code> различает request-relative HPA target и CPU limit; <code>readiness-gate</code> отделяет Ready от отдельного CPU metric. Во всех подписях сказано, что это teaching model, а не cluster, CI или telemetry data.
- <code>xmllint --noout</code> принял все три SVG. Safety scan не нашёл <code>script</code>, <code>foreignObject</code>, <code>href</code>/<code>src</code>, event-handler attributes, external URL, <code>data:</code> или <code>javascript:</code>. Изображения статичны, не принимают input и не загружают external resource.
- Sharp реально отрендерил SVG на ширине 375 px: pod lifecycle — **375×552**, capacity curve — **375×547**, readiness gate — **375×547**. Все три render просмотрены: заголовки, cards, arrows, labels и footer читаются; в capacity curve длинная mobile callout была разбита на две строки до финальной проверки.
- Фактические финальные результаты: <code>node --check web/scripts/upgrade-2024-06.mjs</code> — PASS; <code>node web/scripts/upgrade-2024-06.mjs --verify-fixture</code> — <code>PASS fixture: 32/32 assertions</code>; <code>cd web && npm run audit:draft -- scripts/upgrade-2024-06.mjs</code> — PASS для трёх slug и import-safe CLI/export comparison.
- <code>npm run audit:draft</code> вывела три non-fatal предупреждения существующей user npm config: <code>store-dir</code>, <code>cache-dir</code> и <code>public-hoist-pattern</code>. Команда завершилась с code 0; эти предупреждения не относятся к P76 и не менялись.
- Sidecar намеренно не интегрирован в overlay или archive: P76 не выполняет deploy, cluster analysis, CI, HTTP, trace collection или production change. Реальная проверка требует отдельного разрешения, изолированной scope, owner-а, evidence source, stop condition и rollback plan.
## Выпуск после трёх независимых проходов
1.**Факты и техника.** Редактор повторно проверил неизменяемые первичные snapshots через raw GitHub: resource request используется scheduler при выборе Node, limit применяется kubelet/runtime, а limit без request копируется как request; HPA определяет CPU utilization относительно request и не действует по этой метрике без relevant request; readiness/readiness gates и startup probe имеют описанные в статье границы. Публичный релиз Kubernetes v1.30 от 17.04.2024 дополнительно подтвердил историческую границу. Проверены `node --check`, fixture — **PASS 32/32**.
2.**Редактура и голос.** Повторный проход удалил из публичной прозы служебное имя партии `P76`: теперь читатель видит «учебную модель» и «учебный набор», а не внутреннюю маркировку. Цепочка «симптом → причина → проверка → действие», стоимость ошибки и ограничения сохранены. После правки `audit:draft` подтвердил объёмы: practice — **11 953**, mechanism — **12 023**, field — **11 662** знака.
3.**Визуал и выпуск.** Все три SVG прошли XML и safety scan, затем были заново отрендерены Sharp на ширине 375 px и просмотрены: подписи, стрелки, таблицы и контраст читаемы. После подключения overlay `audit:articles` подтвердил для каждого slug один figure, одну table и один code example; registry содержит **223** уникальные ревизии. `npm run build` завершился успешно: **374** статические страницы.
В выпуск включены только пять файлов июня, обновления registry/production README и редакционный стандарт. Изменения пользователя, черновики других месяцев и исходный `articles.json` в этот пакет не входят.
<titleid="title">Синтетическая кривая CPU относительно request</title>
<descid="desc">Учебная диаграмма P76 показывает фиксированные синтетические точки CPU как процент declared request, линию HPA target и отдельную линию CPU limit. Она не является метрикой, telemetry или прогнозом capacity.</desc>
<textx="48"y="1007"fill="#cbd5e1"font-family="Arial, sans-serif"font-size="15">Все точки — fixed synthetic teaching data из P76, не metrics server и не production telemetry.</text>
<titleid="title">Профиль приложения, манифест и жизненный цикл Pod</title>
<descid="desc">Учебная схема P76: профиль приложения задаёт вопросы к requests, limits и readiness, после чего Pod проходит состояния Pending, Running, Ready или Unready. Только Ready допускается к Service traffic. Это не данные кластера.</desc>
<textx="48"y="1008"fill="#cbd5e1"font-family="Arial, sans-serif"font-size="16">Схема не измеряет CPU, memory, latency, HPA decision, CI или production state.</text>
<titleid="title">Readiness gate и отдельный autoscaling signal</title>
<descid="desc">Учебная схема P76 показывает, что ContainersReady и синтетическая custom condition должны стать true для Ready и Service traffic. CPU metric HPA остаётся отдельной величиной относительно request. Это не manifest и не данные кластера.</desc>
note:'Первичное объявление Kubernetes Release Team фиксирует доступность v1.30 17 апреля 2024, то есть до июня 2024. Оно помогает задать историческую границу версии, но не говорит, какая версия, feature gate, controller flags или аддоны есть в чужом кластере.',
},
{
title:'Kubernetes documentation: Resource Management for Pods and Containers, snapshot 07.03.2024',
note:'Первичный неизменяемый снимок документации до июня 2024: scheduler использует request при выборе Node, kubelet и runtime применяют limit, а limit без request может стать request. Это описание механизма Kubernetes, не рекомендация конкретных чисел CPU или memory.',
},
{
title:'Kubernetes documentation: Horizontal Pod Autoscaling, snapshot 26.03.2024',
note:'Первичный снимок HPA до июня 2024: CPU utilization считается относительно request; при отсутствии нужного request controller не действует по этой метрике. Документ также описывает обработку missing и not-yet-ready Pod, но не доказывает наличие metrics API либо controller settings в конкретной среде.',
},
{
title:'Kubernetes documentation: Pod Lifecycle and readiness gates, snapshot 24.05.2024',
note:'Первичная документация описывает Ready, ContainersReady и readinessGates: custom condition должна быть True вместе с готовностью контейнеров. Она не задаёт семантику доменной condition, owner-а этой condition или надёжность внешней зависимости.',
},
{
title:'Kubernetes documentation: Configure Liveness, Readiness and Startup Probes, snapshot 13.04.2024',
note:'Первичный снимок probes до июня 2024: readiness определяет допуск к Service traffic, startup probe задерживает запуск liveness и readiness. Это не обещание, что проба измеряет latency, throughput, dependency health или реальную capacity.',
keepsReadinessDistinctFromMemoryCause:memory.syntheticObservedPodBehavior.ready===false&&memory.readinessMeaning.includes('does not identify a root cause'),
excerpt:'Практический маршрут, который связывает resource requests и limits, readiness и HPA с профилем приложения — без выдачи учебной fixture за состояние кластера.',
readingMinutes:12,
},[
p('В манифест нового HTTP-сервиса часто попадает знакомая пара: CPU request 500m, limit 1000m, readiness probe и HPA с целью 70 процентов. В день выпуска это выглядит как законченная настройка. Но у приложения есть прогрев, очередь, память на рабочий набор и момент, когда оно действительно способно отвечать. Если числа пришли из соседнего сервиса, а не из профиля этой работы, scheduler резервирует одно, HPA считает процент от другого, а Service отправляет трафик по третьему сигналу. Цена — неверная граница ресурсов и неверная реакция на false readiness. '),
p('Вторая дорогая ошибка появляется после первой тревоги: limit объявляют запасом производительности, а readiness — универсальной проверкой здоровья. В Kubernetes request участвует в размещении, limit задаёт границу исполнения, а readiness решает допуск к Service traffic. Эти механизмы не заменяют друг друга. CPU target HPA в процентах также имеет конкретный знаменатель — request. Поэтому начальная инженерная схема должна сравнить три записи: что декларация разрешает Pod, какую нагрузку приложение обещает выдерживать как единица работы и что наблюдение должно означать, прежде чем его использовать.'),
h2('Симптом → причина → проверка → действие'),
ol([
'<strong>Симптом.</strong> Pod помещается на Node, но после включения трафика растёт ожидание; либо HPA меняет replica count, а доступных backend не прибавляется.',
'<strong>Причина.</strong> Request, limit, readiness и autoscaling настроены как независимые фрагменты. Профиль приложения — CPU-bound serving, memory-retaining batch или warmup — не назван.',
'<strong>Проверка.</strong> Для каждого container выпишите request и limit отдельно, затем объясните одной фразой, что делает readiness, какую работу отражает metric и от какого request считается percentage target.',
'<strong>Действие.</strong> Сначала зафиксируйте маленький profile contract. Затем отдельно решите, какая проверка допускает трафик, какая граница останавливает ресурс и какие evidence разрешены для изменения значения. Не увеличивайте replicas как ответ на ещё не классифицированный симптом.',
]),
h2('Три слоя одного решения'),
p('Первый слой — декларация. В ней container получает CPU и memory request и limit. Официальная документация Kubernetes для исторического среза v1.30 говорит, что scheduler использует request при выборе Node, а kubelet и runtime применяют limit. Это уже достаточно, чтобы не называть limit «резервом для размещения». У container может оказаться больше свободного ресурса, чем request, если Node позволяет; limit относится к границе, а не к обещанию пропускной способности. Отдельно опасен незаметный случай: если limit задан, а request нет, admission может использовать limit как request. Его нельзя угадывать по шаблону — нужно записать, что именно считается effective request в разрешённой проверке.'),
p('Второй слой — управляемая нагрузка. Для web-сервиса это не строка «CPU 70%», а договор: что считается одной обслуживаемой единицей, как ведут себя startup и steady serving, какой ресурс ограничивает путь первым и где заканчивается область owner-а. Для batch-пути полезнее назвать время жизни рабочего набора, чем копировать CPU target из HTTP-сервиса. Для долгого warmup важно отделить инициализацию от готовности принимать запросы. Profile не обязан предсказывать всю production-кривую; его задача — сделать явным, какое предположение сейчас проверяется и какое наблюдение могло бы его опровергнуть.'),
p('Третий слой — наблюдаемое поведение Pod. Оно должно быть именовано точно: condition Ready, результат readiness probe, полученная метрика, restart, latency или очередь — не взаимозаменяемые слова. В этой статье нет снятых показаний. Учебная fixture ниже хранит значения только как versioned fixed synthetic JS-объекты в памяти и прямо называет их не-telemetry. Такой пример годится для проверки логики сопоставления, но не для вывода о живом Pod, kubectl, CI или HPA. Реальные evidence требуют отдельного разрешённого пути, владельца и временной границы.'),
table('Сопоставление декларации, профиля и результата проверки',['Слой','Рабочий вопрос','Что не доказывает','Следующее решение'],[
['Request','какой ресурс scheduler должен зарезервировать для объявленной единицы работы','не доказывает фактический расход, latency или готовность приложения','сверить с profile и effective admission result в отдельной проверке'],
['Limit','какую верхнюю границу исполнения допускает container','не является target HPA и не обещает, что memory ошибка проявится мгновенно','разделить CPU boundary, memory boundary и recovery policy'],
['Readiness','когда Pod допускается к Service traffic','не измеряет capacity, throughput и не заменяет liveness','определить один обслуживаемый контракт и owner failure semantics'],
['HPA metric','какая измеряемая величина меняет desired replicas','не превращает отсутствующий request в meaningful percentage','зафиксировать denominator, source metric и handling missing data'],
['Observed behavior','какой факт разрешённо собран и что он означает','не может быть заменён fixture, screenshot или случайным логом','связать с гипотезой до действия над manifest'],
]),
figure('/assets/editorial/2024/container-orchestration-2024-pod-lifecycle.svg','Вертикальная схема связывает профиль приложения с CPU и memory requests и limits, затем с состояниями Pod Pending, Running, Ready и Unready. Она отделяет допуск Service traffic от границы ресурсов и не показывает данные реального кластера.','Схема показывает порядок рассуждения: профиль задаёт вопросы к manifest, а Ready отвечает только за допуск к трафику. Это не снимок Pod, Node, HPA, CI или telemetry.'),
h2('Readiness — сигнал допуска, а не диагноз'),
p('Readiness probe сообщает kubelet, когда container готов начать принимать трафик; unready Pod не должен быть backend для Service. Это полезный, но узкий смысл. Проверка может сказать «не обслуживаю» во время прогрева, во время controlled drain или когда приложению нужна обязательная зависимость. Она не обязана сказать, почему это произошло. Если readiness начинает проверять каждую внешнюю систему без принятого failure policy, краткая проблема зависимости способна вынуть сразу все backend из трафика. Если, наоборот, probe отвечает success до завершения прогрева, Service получает Pod, который ещё не держит целевой контракт. В обоих случаях увеличение maxReplicas не исправляет неверный смысл самого сигнала.'),
h2('Requests, limits и autoscaling нельзя читать в одиночку'),
p('CPU request влияет и на размещение, и на resource utilization HPA. Для targetAverageUtilization controller берёт usage относительно relevant CPU request; если у Pod нет требуемого request, utilization не определён и autoscaler не действует по этой метрике. Поэтому target 70 процентов не означает «70 процентов Node» и не означает «70 процентов limit». Это 70 процентов именно выбранного request. Изменение request без пересмотра profile одновременно меняет placement economics и числовой смысл HPA target. Это не аргумент никогда не менять request; это аргумент менять их одной review-карточкой.'),
p('Memory требует ещё большей аккуратности. Request помогает scheduler решить, можно ли разместить Pod; limit задаёт предел container. Но память не всегда сообщает проблему той же формой и тем же временем, что CPU. Нельзя нарисовать универсальный коэффициент «memory limit = request × два» и назвать его безопасным. Сначала надо назвать владельца cache, batch или retained object, способ ограничить рост и действие после превысившего договор события. Autoscaling по CPU может быть полезен для serving workload, но сам по себе не объясняет memory lifetime. Если synthetic observation показывает false readiness и высокую synthetic memory величину, корректный следующий вопрос — о границе памяти и значении readiness, не о немедленном scale-up.'),
h2('Исполнимый учебный пример без доступа к системе'),
p('Следующий код не читает манифест и не выполняет API-вызов. Его вход — только известный case id. После него report хранит fixed declaration, fixed managed load и fixed synthetic observed behavior, а plan создаёт лишь текстовые review-actions. Extra field, похожее на имя файла, cluster, CI, network, HTTP, trace или production, fixture отклоняет. Так пример не становится скрытой заменой разрешённой диагностики.'),
code(fixtureCommand),
p('У case <code>fixed-steady-http-v1</code> synthetic CPU 450m не является usage из metrics server и не разрешает менять request 500m. Он нужен лишь чтобы показать отношения внутри заданного объекта: HPA percentage относится к request, а не к limit. Case <code>fixed-memory-growth-v1</code> намеренно не выдаёт synthetic memory за OOM event. Case <code>fixed-warmup-request-missing-v1</code> отклоняет percentage conclusion, потому что CPU request в object равен null. PASS fixture означает только то, что эти границы не были случайно стёрты кодом.'),
h2('Упорядоченный маршрут для настоящей проверки'),
ol([
'<strong>Назвать workload.</strong> Запишите owner, serving или batch shape, startup work, dominant resource и условие, при котором работа должна перестать принимать трафик.',
'<strong>Разложить manifest.</strong> Выпишите per-container request и limit; не суммируйте их в одно «мощность Pod». Отдельно выясните разрешённым способом admission defaults и effective values.',
'<strong>Определить readiness contract.</strong> Скажите, какой дешёвый факт означает «можно обслуживать», а какой не должен делать Pod permanently unready. Назначьте owner изменения semantic.',
'<strong>Проверить metric contract.</strong> Для HPA укажите metric type, denominator или raw target, scope, min/max и поведение при missing values. Не выводите это из fixture.',
'<strong>Собрать ограниченное evidence.</strong> Выберите разрешённую среду, период и source. Отличите Pod condition, usage, restart, latency и queue, прежде чем сопоставлять их с profile.',
'<strong>Менять одну гипотезу.</strong> Измените request, limit, probe или autoscaling policy только с измеримым вопросом, stop condition и rollback. Затем повторите проверку того же контракта.',
]),
h2('Ограничения, rollback и следующий проверяемый шаг'),
p('Эта схема не назначает CPU и memory для реального сервиса, не читает feature gates, controller flags, metrics API, admission policy, Node allocatable, logs или trace. Она не подтверждает, что Service, EndpointSlice, HPA или конкретная probe настроены в чьей-либо среде. В частности, историческая документация HPA описывает default окна initial readiness delay и CPU initialization period, но они являются cluster-wide controller settings; учебная модель их не предполагает и не подменяет доступом к control plane. Для реального изменения нужны отдельные права, security review, dry run, evidence, owner и rollback plan.'),
p('Rollback здесь должен быть таким же конкретным, как изменение. Для request или limit это не «вернуть числа назад» вслепую: сначала нужно понять, какие Pods уже получили новую декларацию и что считалось успехом. Для readiness изменение может вернуть traffic раньше или позже ожидаемого, поэтому его проверяют отдельно от HPA. Следующий проверяемый шаг — создать одностраничную profile card для одного workload: declaration per container, one serving contract, one dominant resource hypothesis, metric denominator, evidence source и stop condition. Пока карточка не заполнена, это design task, а не настройка capacity.'),
h2('Историческая граница июня 2024'),
p('Материал использует только первичные Kubernetes источники, которые существовали до июня 2024: release v1.30 от 17 апреля и зафиксированные commits документации от марта до мая. Из них взяты ограниченные факты о requests, limits, probes, readiness gates и HPA. Все числа, Pod states и outcomes в учебном наборе — versioned fixed synthetic JS-объекты в памяти. Они не являются манифестом, kubectl, CI result, HTTP response, trace, telemetry или production observation.'),
excerpt:'Модель для связи request и limit с HPA и readiness: почему процент CPU имеет знаменатель, Ready не равен capacity, а кривая без источника не является наблюдением.',
readingMinutes:13,
},[
p('У команды есть Deployment с HPA на средний CPU 70 процентов. После замены container image startup стал тяжелее, Pod коротко переходит Ready, а потом снова становится Unready. В ответ кто-то предлагает увеличить CPU limit и maxReplicas. Цена — спутать HPA signal с traffic eligibility и увеличить число Pod без понимания причины. Если не отделить request от limit и readiness от metric, рост replicas только усложнит разбор.'),
p('Другая ситуация ещё тише: в manifest нет CPU request, но стоит utilization target. Проблема скрыта именно в знакомом проценте, поэтому его считают рабочим. Однако в официальной модели Kubernetes CPU utilization HPA вычисляется относительно request; когда у container нет нужного request, controller не предпринимает действие по этой метрике. Цена — не только отсутствие scale. Команда получает число, которое выглядит как policy, но не имеет declared denominator, а затем ищет объяснение в synthetic или случайном графике вместо контракта.'),
h2('Симптом → причина → проверка → действие'),
ol([
'<strong>Симптом.</strong> HPA target, resource limits и readiness существуют, но разные участники объясняют ими разные события: placement, traffic, CPU saturation и restart.',
'<strong>Причина.</strong> Один Pod воспринимают как одну шкалу capacity. В действительности scheduler, runtime, Service и HPA отвечают на разные входы и в разные моменты.',
'<strong>Проверка.</strong> Постройте четыре связи: profile → request, limit → resource boundary, readiness → traffic eligibility, metric → replica proposal. У каждой связи должны быть source, owner и failure meaning.',
'<strong>Действие.</strong> Оставьте в policy только значения с объявленным смыслом. Если request отсутствует, utilization target не додумывают; если readiness false, не называют это автоматически resource incident; если metric missing, не рисуют real curve из fixture.',
]),
h2('Модель: один manifest, четыре управляющих контура'),
p('Контур размещения начинается с request. Scheduler рассматривает requests при выборе Node, а для Pod общая величина по ресурсу складывается из container requests. Это правило не говорит, что container будет всё время потреблять request; оно описывает reservation contract для scheduling. Поэтому request должен соответствовать объявленной единице работы: например, serving unit и допустимому concurrency, а не просто «значению, после которого Pod когда-то перестал Pending». If sidecar, init или main container имеют разные роли, они требуют отдельных строк и явного общего вывода, а не одного красивого числа в ticket.'),
p('Контур ограничения начинается с limit. Kubelet и runtime применяют CPU и memory limits, но поведение ресурса не следует смешивать. В исторической версии документации описано, что runtime применяет memory limit с OOM error при попытке выделить больше разрешённого; реализация ограничения может быть reactive или enforcement, а детали зависят от runtime. Отсюда практический вывод скромнее популярных советов: CPU limit не является HPA target, memory limit не является прогнозом peak, а изменение обоих не заменяет проверку application lifetime. В учебном наборе нет реального runtime и потому нет утверждения о throttling, OOM, eviction или restart какого-либо Pod.'),
p('Контур traffic использует readiness. Kubelet переводит container в ready по readiness probe; когда Pod не ready, он исключается из Service load balancers. Pod lifecycle добавляет ещё одну границу: readiness gate требует, чтобы containers были ready и все указанные custom conditions стали True. Это удобно, когда приложение действительно нуждается в дополнительном явном соглашении. Но custom condition не даёт автоматической семантики: «feature loaded», «schema usable» и «dependency healthy» должны принадлежать owner-у и иметь failure policy. Gate, который никто не может привести в True при аварии, превращает capacity policy в скрытый single point of delay.'),
p('Контур replica proposal — HPA. Он периодически сопоставляет current metric с desired metric и формирует desired replicas. Для resource utilization CPU значение является процентом от requests контейнеров targeted Pod. Для raw target и custom или external metric интерфейс другой, а metrics API должен существовать отдельно. HPA не проверяет бизнес-готовность и не обещает, что новый Pod уже serving. Поэтому accurate design question звучит не «какой процент поставить», а «какое измерение репрезентирует pressure именно после readiness, с какой задержкой и при каком denominator». Если это неизвестно, placeholder target честнее, чем случайная кривая.'),
table('Четыре контура и их неверные подмены',['Контур','Вход','Выход','Частая неверная подмена'],[
['Placement','CPU и memory request per container','возможность scheduler разместить Pod','request называют фактическим расходом или лимитом'],
['Resource boundary','CPU и memory limit','ограничение runtime для container','limit называют запасом HPA либо гарантийным throughput'],
['Traffic eligibility','readiness probe и readiness gates','допуск Pod к Service traffic','Ready называют доказательством latency или capacity'],
['Replica proposal','metric, target, min/max, HPA algorithm','desired replica count','desired count считают числом ready backend и root-cause diagnosis'],
['Evidence','разрешённый metric, condition или controlled test','подтверждение или опровержение profile','fixture или screenshot выдают за telemetry'],
]),
figure('/assets/editorial/2024/container-orchestration-2024-capacity-curve.svg','Синтетическая кривая показывает CPU как отношение к declared request: target HPA 70 процентов и CPU limit 200 процентов request — разные линии. Подпись отмечает, что значения являются fixed teaching data, а не метриками кластера.','Кривая объясняет единицы измерения. Она намеренно не обещает SLA, throughput, p95 latency, фактический scale-up или capacity какого-либо runtime.'),
h2('Почему процент CPU меняет смысл при изменении request'),
p('Представьте declared request 500m и targetAverageUtilization 70. Это формирует target около 350m usage на Pod в модели utilization, а не 70 процентов Node и не 70 процентов CPU limit 1000m. Если request увеличить до 1000m, то тот же target обозначает уже другую рабочую точку. Параллельно scheduler станет резервировать больше. Если request уменьшить, scale signal станет более чувствительным, но placement станет плотнее; это не автоматически хорошо или плохо. Значение можно менять только вместе с hypothesis о workload, потому что один YAML field служит двум механизмам.'),
p('Тут важна граница источника. Документация говорит, что HPA при missing CPU request не действует по resource utilization, и объясняет, как controller консервативно учитывает missing и not-yet-ready Pod для направления scale. Она не даёт права считать, что в конкретной среде работают default flags, metrics server доступен или metric собран нужного качества. В частности, `initial-readiness-delay` и CPU initialization period — параметры controller manager, а не свойства manifest. Их нельзя захардкодить в статью как универсальную задержку. Вместо этого profile должен открыть вопрос: когда serving metric становится репрезентативной и кто имеет право подтвердить это в выбранной среде.'),
h2('Readiness и HPA встречаются, но не становятся одним сигналом'),
p('HPA учитывает readiness при обработке CPU metrics во время инициализации. Это не превращает readiness probe в autoscaling metric. Probe может быть корректной для traffic и совершенно непригодной для оценки future load: она отвечает только success или failure конкретного check. А CPU metric может быть корректной для replica proposal и не сообщать, что Pod умеет совершить важный доменный шаг. Полезно держать два вопроса рядом: «можно ли отправить запрос?» и «есть ли pressure, которое оправдывает изменение desired replicas?». Они могут получить разные ответы и всё ещё быть здоровой системой.'),
h2('Исполнимый объект вместо вымышленных операционных данных'),
p('В учебном примере механизм проверяется только на закрытом наборе object literals. Input содержит model version, scope, mode fixed-memory-only и case id. Любой file-like, cluster-like, CI-like, network-like, HTTP-like, trace-like или production-like field отклоняется до анализа. Это намеренно уже, чем реальный capacity tool: fixture должна показать отношения между значениями, а не притвориться CLI. Значение <code>syntheticObservedPodBehavior</code> имеет собственный marker <code>embedded-fixed-js-object-not-telemetry</code>.'),
code(fixtureCommand),
p('В case <code>fixed-warmup-request-missing-v1</code> есть synthetic CPU 600m и false readiness. Model verdict не говорит «нужно больше Pod». Он говорит, что CPU percentage target нельзя интерпретировать без declared CPU request и что controller startup settings намеренно не читались. В case <code>fixed-memory-growth-v1</code> false readiness не превращается в OOM event, потому что никаких runtime event не было получено. Это не слабость fixture: отрицание неразрешённого вывода является её главным учебным результатом.'),
h2('Упорядоченный маршрут проектирования механизма'),
ol([
'<strong>Определить application profile.</strong> Назовите serving path, startup path, unit of work, dominant resource, concurrency boundary и owner-а выбора.',
'<strong>Связать profile с request.</strong> Для каждого container объясните, зачем ему CPU и memory request. Проверьте effective defaults отдельным разрешённым способом, а не по предположению о limit.',
'<strong>Сформулировать limits как boundaries.</strong> Укажите, какое поведение ожидается при приближении к CPU и memory границе, кто реагирует и чего rollback не восстановит.',
'<strong>Разделить probes.</strong> Напишите отдельные contracts для startup, readiness и liveness; если есть readiness gate, добавьте producer condition и recovery path.',
'<strong>Выбрать HPA metric.</strong> Укажите metric API, target type, denominator, min/max, behavior window и условия, при которых metric не следует считать evidence.',
'<strong>Проверить одну связь.</strong> В согласованной среде сравните один declared input с одним разрешённым observation. Не меняйте request, readiness и HPA одновременно.',
'<strong>Закрыть change record.</strong> Сохраните observed result, limitation, owner, stop condition и rollback. Только затем решайте, стал ли новый profile default.',
]),
h2('Ограничения и следующий проверяемый шаг'),
p('Этот разбор не выбирает тип metric, values probes, containers count, Node size, CPU/memory ratio или правильный maxReplicas. Он не смотрит в admission controller, resource quota, PodDisruptionBudget, EndpointSlice, runtime cgroups, Metrics Server, custom adapter, dashboard, log, trace или production. Он также не обещает, что autoscaling устраняет queueing, memory retention, downstream saturation или dependency failure. Такой вывод возможен только после разрешённого evidence collection с временной и workload-boundary, а не после чтения historical documentation.'),
p('Следующий проверяемый шаг — взять один уже согласованный workload profile и сформировать matrix из пяти строк: per-container requests, per-container limits, readiness and startup conditions, HPA metric denominator, allowed evidence source. Для каждой строки добавьте «что этот сигнал не доказывает». После этого выберите ровно одну uncertainty для проверки в изолированной среде. Если она касается profile, не меняйте policy; если касается metric, не переписывайте probe. Маленькая изолированная проверка лучше общего scale-up, потому что сохраняет причинную связь.'),
h2('Историческая граница июня 2024'),
p('Материал опирается на Kubernetes v1.30 release и snapshots официальной документации, датированные мартом, апрелем и маем 2024. Они были доступны до июня 2024 и ограничивают утверждения о request, limit, probes, readiness gates и HPA. Синтетическая capacity curve, profile cards и outcomes не описывают cluster state. Это fixed in-memory teaching material: без файлов, кластера, CI, сети, HTTP, trace, telemetry и production.'),
excerpt:'Полевой маршрут для различения request и limit, traffic readiness и HPA signal: три синтетические карточки вместо вымышленных показаний реального кластера.',
readingMinutes:12,
},[
p('На разбор приходит фраза: «Pod стал Unready, увеличим maxReplicas». Она кажется практичной, пока не задать первый вопрос: Unready по какому контракту? Если readiness скрывает Pod от Service traffic во время прогрева, а HPA смотрит на CPU относительно request, то number of replicas и traffic eligibility живут в разных контурах. Цена быстрого решения — новый манифест без понятной гипотезы: один Pod может быть не готов по зависимости, другой ещё стартует, а третьему вообще не определён CPU request. После этого любой график становится поводом спорить, а не доказательством причины.'),
p('Ещё один знакомый вывод звучит так: «CPU высок, значит capacity не хватает». Проблема в том, что в этой статье нельзя делать даже такой учебный вывод без declared denominator. HPA percentage — не число само по себе: для CPU utilization ему нужен resource request. Если в декларации request отсутствует, а в synthetic object есть CPU 600m, это не kubectl top, не CI, не telemetry и не команда увеличить replicas. Цена подмены особенно неприятна в warmup: команда тратит время на scale policy, хотя сначала нужно разделить startup work, serving work и metric contract. Полевой разбор начинается не с команды к кластеру, а с карточки сравнения.'),
h2('Симптом → причина → проверка → действие'),
ol([
'<strong>Симптом.</strong> Один и тот же признак — high CPU, false readiness или memory near limit — хотят использовать как достаточную причину изменить replicas.',
'<strong>Причина.</strong> Manifest, managed load и observed behavior не записаны рядом; слово «Pod» скрывает разные states и разные механизмы Kubernetes.',
'<strong>Проверка.</strong> Для каждого случая сначала определите type signal: declared field, readiness condition, resource metric, restart event, latency или queue. Затем назовите, что signal не доказывает.',
'<strong>Действие.</strong> Выберите одну проверяемую гипотезу и один разрешённый evidence source. Если signal не имеет contract, зафиксируйте blocker вместо изменения limit, probe или HPA.',
]),
h2('Три карточки, не три истории о реальной среде'),
p('Ниже нет incident report. Это три versioned fixed synthetic JS-объекта из учебной fixture. У каждого есть <code>declaredManifest</code>, <code>managedLoad</code> и <code>syntheticObservedPodBehavior</code>. Последний явно помечен как <code>embedded-fixed-js-object-not-telemetry</code>. Его numbers нельзя переносить в capacity calculator, использовать как SLO, называть output kubectl или сравнивать с реальным production. Зато на этих карточках можно проверить дисциплину: сначала прочитать заявленную границу, потом profile, потом смысл synthetic observation и только после этого сформулировать next question.'),
table('Синтетические карточки учебной модели и допустимый verdict',['Case id','Декларация и profile','Synthetic behavior','Допустимый verdict'],[
['fixed-steady-http-v1','CPU request 500m, target 70%, steady HTTP CPU-bound shape','Ready true, synthetic CPU 450m','сверить profile, request и HPA denominator; не делать capacity claim'],
['fixed-memory-growth-v1','memory request 256Mi, limit 512Mi, bounded batch with retention question','Ready false, synthetic memory 470Mi','разделить memory lifetime, readiness semantic и replica action; не называть OOM'],
['fixed-warmup-request-missing-v1','CPU request null, CPU utilization target 65%, warmup before serving','Ready false, synthetic CPU 600m','отклонить percentage conclusion до declared request и startup contract'],
['Любой внешний field','file, cluster, CI, network, HTTP, trace или production','не принимается fixture','отклонить input; fixture не является reader или operator'],
]),
h2('Карточка 1: стабильный serving не делает число автоматически верным'),
p('В <code>fixed-steady-http-v1</code> declaration фиксирует request 500m, limit 1000m и target 70 процентов request. Managed profile называет нагрузку steady HTTP и dominant resource CPU. Synthetic observation — Ready true, CPU 450m, memory 310Mi. Из этих данных нельзя заключить, что сервис реально выдерживает нагрузку или что 500m достаточно. Но можно увидеть правильный порядок: 70 процентов имеет declared denominator 500m, а limit 1000m не меняет этот denominator. Если команда меняет request, она обязана пересмотреть и scheduling contract, и HPA interpretation, а не только нарисовать новый threshold.'),
p('Практическая проверка после согласования прав должна узнать не «какой Pod красивее на графике», а покрывает ли request определённую serving unit и соответствует ли metric именно этой unit. Если CPU usage взят после readiness и во время выбранного сценария, его можно сопоставить с profile. Если usage пришёл из startup, sidecar, stale interval или неизвестного selector, он может не отвечать на вопрос. Фикстура не делает эту проверку, потому что она не читает cluster, network, HTTP, trace или telemetry. Она оставляет owner-у сформулированный вопрос и отказывается открыть данные за него.'),
h2('Карточка 2: false readiness не является именем причины'),
p('В <code>fixed-memory-growth-v1</code> profile подчёркивает memory retention question, а readiness false означает только «приложение объявило, что не может обслуживать». Documentation Kubernetes говорит, что unready Pod не получает Service traffic; это действие routing layer, а не диагноз. Synthetic memory 470Mi при limit 512Mi не говорит, что в реальном runtime уже произошёл OOM, throttling, eviction или restart. Учебный пример специально хранит строку <code>no-real-restart-or-oom-event-is-represented</code>, чтобы не позволить превратить близость к limit в выдуманный incident.'),
p('Рациональная следующая ветка — разложить lifetime памяти: cache, batch buffer, response aggregation, connection pool или другой owner. Затем определить, когда readiness должен false, как он становится true снова и не зависит ли эта condition от traffic, которого Pod уже не получает. Только после этого можно обсуждать request/limit или число replicas. CPU HPA может оставить synthetic memory cause нетронутой: он принимает решение по своему metric, а не собирает memory root cause. Если возникают и memory pressure, и traffic loss, это два сигнала для связи с profile, не приглашение сложить их в одно магическое значение.'),
h2('Карточка 3: warmup без request блокирует процентный вывод'),
p('В <code>fixed-warmup-request-missing-v1</code> заявлен targetAverageUtilization 65, но CPU request null. Historical HPA documentation прямо связывает CPU utilization с request и указывает, что при отсутствии relevant request autoscaler не действует по этому metric. Следовательно, object не должен пройти через «CPU 600m — значит scale up». Synthetic 600m лишь служит проверкой отрицательного пути. Первым вопросом становится: какая serving unit даёт CPU request смысл, а вторым — какие controller startup settings и metric timing реально подтверждены в отдельной среде.'),
figure('/assets/editorial/2024/container-orchestration-2024-readiness-gate.svg','Схема readiness gate: ContainersReady и custom condition True вместе формируют Ready и допуск к Service traffic. Отдельный блок показывает, что HPA CPU metric сравнивается с request и не равен readiness signal; это учебная схема, а не состояние кластера.','Readiness gate добавляет условие к traffic eligibility, но не превращает condition в метрику capacity. Схема не содержит service endpoints, controller flags, logs, trace или production data.'),
h2('Исполнимый пример проверяет отказ от скрытого доступа'),
p('Фикстура легко запускается локально, потому что не требует credentials, namespace, kubeconfig, filesystem, HTTP или CI. Она не вызывает `kubectl`, не создаёт Pod, не читает manifest и не делает HTTP probe. Case id выбирает только заранее записанный object literal. Внешний field отклоняется: поэтому не получится незаметно передать имя deployment.yaml, cluster name, CI URL, network endpoint, trace ID или production marker. Это не ограничение production-инструмента; это честная граница учебного кода.'),
code(fixtureCommand),
p('Проверка сравнивает весь canonical report, а не один verdict. Если подменить <code>syntheticObservedPodBehavior.ready</code>, добавить <code>kubectlOutput</code> или заменить verdict на <code>scale-now</code>, plan отказывает. Rollback принимает только untouched synthetic review draft и возвращает «not read or changed» для manifest и cluster. Такой механизм не доказывает, что реальный rollback безопасен. Он доказывает только, что пример не превратился в канал управления окружением, пока читатель тренирует сравнение трёх слоёв.'),
h2('Упорядоченный маршрут диагностики после получения разрешения'),
ol([
'<strong>Ограничить scope.</strong> Назначьте один workload, owner, изолированную среду, период проверки и разрешённые источники. Не начинайте с массового scan Pod.',
'<strong>Снять declaration.</strong> Зафиксируйте per-container requests и limits, readiness/startup configuration, HPA metric type и target. Отличите written field от effective admission result.',
'<strong>Написать profile.</strong> Назовите serving unit, startup unit, concurrency, dominant resource, dependency policy и meaning Ready/Unready.',
'<strong>Собрать один signal.</strong> Получите по разрешённому маршруту condition либо metric либо controlled test. Не склеивайте их в один verdict до interpretation.',
'<strong>Сравнить с contract.</strong> Скажите, согласуется ли signal с одной declared hypothesis, какие unknown остаются и что signal не доказывает.',
'<strong>Выбрать действие.</strong> Разрешите ровно одно изменение, только если есть owner, expected result, stop condition и rollback. Для missing request или unknown readiness semantics action — blocker.',
'<strong>Повторить тот же вопрос.</strong> После изменения проверьте именно первоначальную hypothesis тем же type evidence; иначе результат нельзя сопоставить.',
]),
h2('Ограничения, rollback и следующий проверяемый шаг'),
p('Материал не подсказывает команду для кластера и не заменяет ручной review production policy. В нём нет наблюдения за actual pod lifecycle, Node pressure, Service endpoints, metrics server, autoscaler behavior, CI job, logs или distributed trace. Там нет утверждения, что range request/limit подходит для чьего-то языка, runtime, image, cache или external dependency. Даже официальный documentation snapshot объясняет generic semantics, но не знает admission webhooks и runtime configuration конкретного владельца. Поэтому нельзя превратить chart, fixture PASS или article table в permission изменить manifest.'),
p('Rollback для реального изменения должен содержать snapshot исходной декларации, owner решения, condition для остановки, временную границу и проверку side effect. Откат HPA не исправляет невнятную readiness condition; возврат limit не рассказывает, что произошло с application memory; изменение probe не восстанавливает evidence. Следующий проверяемый шаг — провести review одной profile card с platform owner и application owner. На выходе нужны: declared request denominator, separate definition of Ready, named allowed metric source и explicit blocker для непроверенной части. Если хотя бы одна строка остаётся «кажется», change не готов.'),
h2('Историческая граница июня 2024'),
p('К июню 2024 уже были опубликованы Kubernetes v1.30 и использованные здесь первичные documentation snapshots. Их положения применены узко: request и limit имеют разные роли; readiness управляет traffic eligibility; readiness gates добавляют named conditions; CPU utilization HPA относится к request и имеет обработку not-yet-ready Pod. Три карточки, values и verdict учебной модели являются только fixed synthetic JS-объектами в памяти. Они не имитируют и не выдают себя за cluster query, kubectl, CI, telemetry, HTTP, trace или production data.'),
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.