[{"data":1,"prerenderedAt":4482},["ShallowReactive",2],{"content:\u002F07-infrastructure\u002F04-pods-lifecycle":3},{"title":4,"description":5,"path":6,"body":7},"Pods и жизненный цикл","Pod — минимальная единица деплоя в Kubernetes. Не контейнер, а именно pod. Это принципиальный момент: Kubernetes не управляет контейнерами напрямую, он управляет pod-ами. Pod может содержать один или несколько контейнеров, которые разделяют сетевое пространство, хранилище и часть Linux namespaces. Понимание жизненного цикла pod-а — от создания до удаления, включая probes, hooks, и restart policy — необходимо для написания приложений, которые корректно работают в кластере.","\u002F07-infrastructure\u002F04-pods-lifecycle",{"type":8,"value":9,"toc":4438},"minimark",[10,14,17,20,25,30,38,42,45,136,146,149,153,159,165,171,174,176,180,302,308,311,313,317,321,324,327,391,397,401,408,414,417,447,450,483,486,707,711,726,733,1027,1041,1044,1046,1050,1065,1071,1075,1139,1142,1204,1208,1211,1251,1294,1298,1301,1354,1381,1383,1387,1390,1394,1397,1404,1507,1510,1516,1520,1523,1533,1539,1654,1660,1664,1667,1670,1715,1718,1729,1732,1736,1739,1744,1777,1784,1788,1815,1818,1821,1850,1853,1857,1862,1893,1898,1906,1908,1912,1930,1934,1941,1989,2032,2045,2049,2055,2104,2144,2180,2187,2189,2193,2196,2202,2207,2211,2218,2223,2237,2240,2245,2272,2275,2278,2709,2713,2766,2768,2772,2779,2825,2832,2836,2839,2909,2914,2916,2920,3053,3063,3091,3093,3097,3102,3105,3110,3113,3118,3124,3129,3139,3144,3154,3159,3162,3167,3170,3172,3176,3180,3186,3192,3210,3215,3571,3578,3582,3586,3591,3602,3606,3829,3835,3839,3843,3848,3853,3858,3861,4023,4026,4028,4032,4061,4265,4434],[11,12,4],"h1",{"id":13},"pods-и-жизненный-цикл",[15,16,5],"p",{},[18,19],"hr",{},[21,22,24],"h2",{"id":23},"pod-минимальная-единица-деплоя","Pod — минимальная единица деплоя",[26,27,29],"h3",{"id":28},"зачем-pod-а-не-просто-контейнер","Зачем Pod, а не просто контейнер",[15,31,32,33,37],{},"Контейнер по дизайну инкапсулирует ",[34,35,36],"strong",{},"один процесс",". Но приложение часто состоит из нескольких связанных процессов: основной сервис + sidecar-прокси, основной сервис + агент для логирования. Этим процессам нужно общаться через localhost, видеть одни и те же файлы, иметь общий IP. Pod решает эту задачу — группирует контейнеры с общим сетевым стеком.",[26,39,41],{"id":40},"shared-namespaces","Shared namespaces",[15,43,44],{},"Контейнеры внутри одного pod-а разделяют часть Linux namespaces:",[46,47,48,64],"table",{},[49,50,51],"thead",{},[52,53,54,58,61],"tr",{},[55,56,57],"th",{},"Namespace",[55,59,60],{},"Общий?",[55,62,63],{},"Что это значит",[65,66,67,81,93,105,123],"tbody",{},[52,68,69,75,78],{},[70,71,72],"td",{},[34,73,74],{},"net",[70,76,77],{},"Да",[70,79,80],{},"Один IP-адрес, один набор сетевых интерфейсов. Контейнеры общаются через localhost, но не могут занимать один порт",[52,82,83,88,90],{},[70,84,85],{},[34,86,87],{},"UTS",[70,89,77],{},[70,91,92],{},"Один hostname",[52,94,95,100,102],{},[70,96,97],{},[34,98,99],{},"IPC",[70,101,77],{},[70,103,104],{},"Shared memory, message queues",[52,106,107,112,115],{},[70,108,109],{},[34,110,111],{},"PID",[70,113,114],{},"Опционально",[70,116,117,118,122],{},"При ",[119,120,121],"code",{},"shareProcessNamespace: true"," — общее дерево процессов, контейнеры видят процессы друг друга",[52,124,125,130,133],{},[70,126,127],{},[34,128,129],{},"mnt",[70,131,132],{},"Нет",[70,134,135],{},"У каждого контейнера своя файловая система. Для обмена файлами используют shared volume",[137,138,143],"pre",{"className":139,"code":141,"language":142},[140],"language-text","        Pod (один IP: 10.244.2.4)\n    +------------------------------+\n    |  Container A    Container B  |\n    |  :8080          :8443        |\n    |       |              |       |\n    |       +---- lo ------+       |  \u003C-- localhost (127.0.0.1)\n    |            eth0              |  \u003C-- один внешний IP\n    +------------------------------+\n","text",[119,144,141],{"__ignoreMap":145},"",[15,147,148],{},"Ключевое следствие: pod никогда не растягивается на несколько нод. Все контейнеры pod-а всегда запущены на одной физической или виртуальной машине.",[26,150,152],{"id":151},"когда-объединять-в-один-pod-а-когда-разделять","Когда объединять в один Pod, а когда разделять",[15,154,155,158],{},[34,156,157],{},"В один Pod"," — когда процессы тесно связаны, должны работать на одном хосте, масштабируются вместе и дополняют друг друга (основной процесс + sidecar).",[15,160,161,164],{},[34,162,163],{},"В разные Pod-ы"," — когда компоненты независимы, масштабируются по-разному или имеют разный lifecycle (frontend + backend, независимые микросервисы).",[137,166,169],{"className":167,"code":168,"language":142},[140],"Антипаттерн:                     Правильно:\n+---------------------+          +----------+  +----------+\n| Frontend  Backend   |          | Frontend |  | Backend  |\n| container container |          | container|  | container|\n|       Pod           |          |   Pod    |  |   Pod    |\n+---------------------+          +----------+  +----------+\nНельзя скейлить                  Скейлятся независимо:\nпо отдельности                   3x frontend, 1x backend\n",[119,170,168],{"__ignoreMap":145},[15,172,173],{},"Kubernetes масштабирует pod-ы целиком, а не отдельные контейнеры внутри pod-а. Если компоненты масштабируются по-разному — это разные pod-ы.",[18,175],{},[21,177,179],{"id":178},"минимальный-манифест-пода","Минимальный манифест пода",[137,181,185],{"className":182,"code":183,"language":184,"meta":145,"style":145},"language-yaml shiki shiki-themes github-dark","apiVersion: v1\nkind: Pod\nmetadata:\n  name: my-app\nspec:\n  containers:\n  - name: my-app\n    image: myregistry\u002Fmy-app:1.0\n    ports:\n    - containerPort: 8080   # информативно, не влияет на доступность порта\n","yaml",[119,186,187,204,215,224,235,243,251,264,275,283],{"__ignoreMap":145},[188,189,192,196,200],"span",{"class":190,"line":191},"line",1,[188,193,195],{"class":194},"s4JwU","apiVersion",[188,197,199],{"class":198},"s95oV",": ",[188,201,203],{"class":202},"sU2Wk","v1\n",[188,205,207,210,212],{"class":190,"line":206},2,[188,208,209],{"class":194},"kind",[188,211,199],{"class":198},[188,213,214],{"class":202},"Pod\n",[188,216,218,221],{"class":190,"line":217},3,[188,219,220],{"class":194},"metadata",[188,222,223],{"class":198},":\n",[188,225,227,230,232],{"class":190,"line":226},4,[188,228,229],{"class":194},"  name",[188,231,199],{"class":198},[188,233,234],{"class":202},"my-app\n",[188,236,238,241],{"class":190,"line":237},5,[188,239,240],{"class":194},"spec",[188,242,223],{"class":198},[188,244,246,249],{"class":190,"line":245},6,[188,247,248],{"class":194},"  containers",[188,250,223],{"class":198},[188,252,254,257,260,262],{"class":190,"line":253},7,[188,255,256],{"class":198},"  - ",[188,258,259],{"class":194},"name",[188,261,199],{"class":198},[188,263,234],{"class":202},[188,265,267,270,272],{"class":190,"line":266},8,[188,268,269],{"class":194},"    image",[188,271,199],{"class":198},[188,273,274],{"class":202},"myregistry\u002Fmy-app:1.0\n",[188,276,278,281],{"class":190,"line":277},9,[188,279,280],{"class":194},"    ports",[188,282,223],{"class":198},[188,284,286,289,292,294,298],{"class":190,"line":285},10,[188,287,288],{"class":198},"    - ",[188,290,291],{"class":194},"containerPort",[188,293,199],{"class":198},[188,295,297],{"class":296},"sDLfK","8080",[188,299,301],{"class":300},"sAwPA","   # информативно, не влияет на доступность порта\n",[15,303,304,305,307],{},"Поле ",[119,306,291],{}," — чисто информационное. Оно не открывает и не закрывает порты. Но полезно для документации и для именования портов в Service.",[15,309,310],{},"Голый Pod (без Deployment или ReplicaSet) — одноразовый. Если он умрёт, никто его не пересоздаст. В production всегда используют Deployment, который создаёт ReplicaSet, а тот управляет pod-ами.",[18,312],{},[21,314,316],{"id":315},"multi-container-pods","Multi-container Pods",[26,318,320],{"id":319},"sidecar-pattern","Sidecar Pattern",[15,322,323],{},"Sidecar — вспомогательный контейнер, который дополняет основной, не являясь основным процессом. Преимущество: не нужно менять код приложения. Один и тот же sidecar-образ переиспользуется для многих приложений.",[15,325,326],{},"Типичные примеры sidecar-ов:",[46,328,329,339],{},[49,330,331],{},[52,332,333,336],{},[55,334,335],{},"Sidecar",[55,337,338],{},"Что делает",[65,340,341,351,361,371,381],{},[52,342,343,348],{},[70,344,345],{},[34,346,347],{},"HTTPS proxy",[70,349,350],{},"Envoy\u002FNginx перед HTTP-приложением, терминирует TLS",[52,352,353,358],{},[70,354,355],{},[34,356,357],{},"Log collector",[70,359,360],{},"Читает логи из shared volume, шлёт в central logging",[52,362,363,368],{},[70,364,365],{},[34,366,367],{},"Content syncer",[70,369,370],{},"Скачивает контент в shared volume для web-сервера",[52,372,373,378],{},[70,374,375],{},[34,376,377],{},"Auth proxy",[70,379,380],{},"OAuth2 proxy перед приложением",[52,382,383,388],{},[70,384,385],{},[34,386,387],{},"Monitoring agent",[70,389,390],{},"Prometheus exporter, сбор метрик",[137,392,395],{"className":393,"code":394,"language":142},[140],"        +--------------------------------+\n        |  Node.js        Envoy proxy    |\n        |  :8080 (HTTP)   :8443 (HTTPS)  |\n        |       \u003C---- localhost ---->     |\n        |              Pod               |\n        +--------------------------------+\n        Envoy принимает HTTPS, проксирует HTTP на Node.js\n",[119,396,394],{"__ignoreMap":145},[26,398,400],{"id":399},"init-containers","Init Containers",[15,402,403,404,407],{},"Init-контейнеры запускаются ",[34,405,406],{},"последовательно"," перед основными контейнерами. Каждый следующий стартует только после успешного завершения предыдущего. Основные контейнеры стартуют только после всех init-ов.",[137,409,412],{"className":410,"code":411,"language":142},[140],"  Init 1 --> Init 2 --> Init 3 --> [Main A + Main B] (параллельно)\n     |           |           |              |\n   завершился  завершился  завершился     работают\n",[119,413,411],{"__ignoreMap":145},[15,415,416],{},"Правила:",[418,419,420,427,434,437,444],"ul",{},[421,422,423,424,426],"li",{},"Запускаются ",[34,425,406],{},", не параллельно",[421,428,429,430,433],{},"Каждый должен завершиться ",[34,431,432],{},"успешно"," (exit code 0)",[421,435,436],{},"Если init-контейнер упал — pod перезапускает его (согласно restartPolicy)",[421,438,439,440,443],{},"Основные контейнеры стартуют ",[34,441,442],{},"только"," после всех init-ов",[421,445,446],{},"Имена контейнеров уникальны в пределах pod-а (init + regular вместе)",[15,448,449],{},"Типичные use cases:",[451,452,453,459,465,471,477],"ol",{},[421,454,455,458],{},[34,456,457],{},"Загрузка конфигурации \u002F сертификатов"," — скачать из vault, записать в shared volume",[421,460,461,464],{},[34,462,463],{},"Ожидание зависимости"," — curl\u002Fping до тех пор, пока база данных или другой сервис не станет доступен",[421,466,467,470],{},[34,468,469],{},"Миграция БД"," — запустить миграции перед стартом приложения",[421,472,473,476],{},[34,474,475],{},"Инициализация сети"," — настройка iptables, маршрутов (Istio sidecar injection)",[421,478,479,482],{},[34,480,481],{},"Уведомление внешней системы"," — \"pod скоро запустится\"",[15,484,485],{},"Безопасность: после завершения init-контейнера его filesystem недоступен основным контейнерам — это уменьшает attack surface.",[137,487,489],{"className":182,"code":488,"language":184,"meta":145,"style":145},"apiVersion: v1\nkind: Pod\nmetadata:\n  name: app-with-init\nspec:\n  initContainers:\n  - name: wait-for-db\n    image: busybox:1.36\n    command: ['sh', '-c', 'until nc -z postgres-svc 5432; do echo waiting; sleep 2; done']\n  - name: run-migrations\n    image: myregistry\u002Fmigrator:1.0\n    env:\n    - name: DATABASE_URL\n      valueFrom:\n        secretKeyRef:\n          name: db-credentials\n          key: url\n  containers:\n  - name: app\n    image: myregistry\u002Fmy-go-app:1.0\n    ports:\n    - containerPort: 8080\n",[119,490,491,499,507,513,522,528,535,546,555,580,591,601,609,621,629,637,648,659,666,678,688,695],{"__ignoreMap":145},[188,492,493,495,497],{"class":190,"line":191},[188,494,195],{"class":194},[188,496,199],{"class":198},[188,498,203],{"class":202},[188,500,501,503,505],{"class":190,"line":206},[188,502,209],{"class":194},[188,504,199],{"class":198},[188,506,214],{"class":202},[188,508,509,511],{"class":190,"line":217},[188,510,220],{"class":194},[188,512,223],{"class":198},[188,514,515,517,519],{"class":190,"line":226},[188,516,229],{"class":194},[188,518,199],{"class":198},[188,520,521],{"class":202},"app-with-init\n",[188,523,524,526],{"class":190,"line":237},[188,525,240],{"class":194},[188,527,223],{"class":198},[188,529,530,533],{"class":190,"line":245},[188,531,532],{"class":194},"  initContainers",[188,534,223],{"class":198},[188,536,537,539,541,543],{"class":190,"line":253},[188,538,256],{"class":198},[188,540,259],{"class":194},[188,542,199],{"class":198},[188,544,545],{"class":202},"wait-for-db\n",[188,547,548,550,552],{"class":190,"line":266},[188,549,269],{"class":194},[188,551,199],{"class":198},[188,553,554],{"class":202},"busybox:1.36\n",[188,556,557,560,563,566,569,572,574,577],{"class":190,"line":277},[188,558,559],{"class":194},"    command",[188,561,562],{"class":198},": [",[188,564,565],{"class":202},"'sh'",[188,567,568],{"class":198},", ",[188,570,571],{"class":202},"'-c'",[188,573,568],{"class":198},[188,575,576],{"class":202},"'until nc -z postgres-svc 5432; do echo waiting; sleep 2; done'",[188,578,579],{"class":198},"]\n",[188,581,582,584,586,588],{"class":190,"line":285},[188,583,256],{"class":198},[188,585,259],{"class":194},[188,587,199],{"class":198},[188,589,590],{"class":202},"run-migrations\n",[188,592,594,596,598],{"class":190,"line":593},11,[188,595,269],{"class":194},[188,597,199],{"class":198},[188,599,600],{"class":202},"myregistry\u002Fmigrator:1.0\n",[188,602,604,607],{"class":190,"line":603},12,[188,605,606],{"class":194},"    env",[188,608,223],{"class":198},[188,610,612,614,616,618],{"class":190,"line":611},13,[188,613,288],{"class":198},[188,615,259],{"class":194},[188,617,199],{"class":198},[188,619,620],{"class":202},"DATABASE_URL\n",[188,622,624,627],{"class":190,"line":623},14,[188,625,626],{"class":194},"      valueFrom",[188,628,223],{"class":198},[188,630,632,635],{"class":190,"line":631},15,[188,633,634],{"class":194},"        secretKeyRef",[188,636,223],{"class":198},[188,638,640,643,645],{"class":190,"line":639},16,[188,641,642],{"class":194},"          name",[188,644,199],{"class":198},[188,646,647],{"class":202},"db-credentials\n",[188,649,651,654,656],{"class":190,"line":650},17,[188,652,653],{"class":194},"          key",[188,655,199],{"class":198},[188,657,658],{"class":202},"url\n",[188,660,662,664],{"class":190,"line":661},18,[188,663,248],{"class":194},[188,665,223],{"class":198},[188,667,669,671,673,675],{"class":190,"line":668},19,[188,670,256],{"class":198},[188,672,259],{"class":194},[188,674,199],{"class":198},[188,676,677],{"class":202},"app\n",[188,679,681,683,685],{"class":190,"line":680},20,[188,682,269],{"class":194},[188,684,199],{"class":198},[188,686,687],{"class":202},"myregistry\u002Fmy-go-app:1.0\n",[188,689,691,693],{"class":190,"line":690},21,[188,692,280],{"class":194},[188,694,223],{"class":198},[188,696,698,700,702,704],{"class":190,"line":697},22,[188,699,288],{"class":198},[188,701,291],{"class":194},[188,703,199],{"class":198},[188,705,706],{"class":296},"8080\n",[26,708,710],{"id":709},"native-sidecar-containers-k8s-128","Native Sidecar Containers (K8s 1.28+)",[15,712,713,714,717,718,721,722,725],{},"Обычный sidecar (в секции ",[119,715,716],{},"containers",") стартует параллельно с основным контейнером. Это создаёт проблемы: нет гарантии, что sidecar запустится ",[34,719,720],{},"до"," основного контейнера; при shutdown sidecar может завершиться ",[34,723,724],{},"раньше"," основного; init-контейнеры не могут использовать sidecar (он ещё не запущен).",[15,727,728,729,732],{},"Native sidecar решает все эти проблемы. Определяется как init-контейнер с ",[119,730,731],{},"restartPolicy: Always",":",[137,734,736],{"className":182,"code":735,"language":184,"meta":145,"style":145},"apiVersion: v1\nkind: Pod\nmetadata:\n  name: app-with-native-sidecar\nspec:\n  initContainers:\n  - name: init-config                     # обычный init container\n    image: busybox:1.36\n    command: ['sh', '-c', 'echo \"config loaded\"']\n  - name: log-collector                   # native sidecar\n    image: fluent\u002Ffluent-bit:latest\n    restartPolicy: Always                 # \u003C-- это делает его native sidecar\n    volumeMounts:\n    - name: logs\n      mountPath: \u002Fvar\u002Flog\u002Fapp\n  - name: check-dependencies              # обычный init, стартует ПОСЛЕ sidecar\n    image: busybox:1.36\n    command: ['sh', '-c', 'echo \"deps ok\"']\n  containers:\n  - name: app                             # основной контейнер\n    image: myregistry\u002Fmy-go-app:1.0\n    ports:\n    - containerPort: 8080\n    volumeMounts:\n    - name: logs\n      mountPath: \u002Fvar\u002Flog\u002Fapp\n  volumes:\n  - name: logs\n    emptyDir: {}\n",[119,737,738,746,754,760,769,775,781,795,803,822,836,845,858,865,876,886,900,908,927,933,947,955,961,972,979,990,999,1007,1018],{"__ignoreMap":145},[188,739,740,742,744],{"class":190,"line":191},[188,741,195],{"class":194},[188,743,199],{"class":198},[188,745,203],{"class":202},[188,747,748,750,752],{"class":190,"line":206},[188,749,209],{"class":194},[188,751,199],{"class":198},[188,753,214],{"class":202},[188,755,756,758],{"class":190,"line":217},[188,757,220],{"class":194},[188,759,223],{"class":198},[188,761,762,764,766],{"class":190,"line":226},[188,763,229],{"class":194},[188,765,199],{"class":198},[188,767,768],{"class":202},"app-with-native-sidecar\n",[188,770,771,773],{"class":190,"line":237},[188,772,240],{"class":194},[188,774,223],{"class":198},[188,776,777,779],{"class":190,"line":245},[188,778,532],{"class":194},[188,780,223],{"class":198},[188,782,783,785,787,789,792],{"class":190,"line":253},[188,784,256],{"class":198},[188,786,259],{"class":194},[188,788,199],{"class":198},[188,790,791],{"class":202},"init-config",[188,793,794],{"class":300},"                     # обычный init container\n",[188,796,797,799,801],{"class":190,"line":266},[188,798,269],{"class":194},[188,800,199],{"class":198},[188,802,554],{"class":202},[188,804,805,807,809,811,813,815,817,820],{"class":190,"line":277},[188,806,559],{"class":194},[188,808,562],{"class":198},[188,810,565],{"class":202},[188,812,568],{"class":198},[188,814,571],{"class":202},[188,816,568],{"class":198},[188,818,819],{"class":202},"'echo \"config loaded\"'",[188,821,579],{"class":198},[188,823,824,826,828,830,833],{"class":190,"line":285},[188,825,256],{"class":198},[188,827,259],{"class":194},[188,829,199],{"class":198},[188,831,832],{"class":202},"log-collector",[188,834,835],{"class":300},"                   # native sidecar\n",[188,837,838,840,842],{"class":190,"line":593},[188,839,269],{"class":194},[188,841,199],{"class":198},[188,843,844],{"class":202},"fluent\u002Ffluent-bit:latest\n",[188,846,847,850,852,855],{"class":190,"line":603},[188,848,849],{"class":194},"    restartPolicy",[188,851,199],{"class":198},[188,853,854],{"class":202},"Always",[188,856,857],{"class":300},"                 # \u003C-- это делает его native sidecar\n",[188,859,860,863],{"class":190,"line":611},[188,861,862],{"class":194},"    volumeMounts",[188,864,223],{"class":198},[188,866,867,869,871,873],{"class":190,"line":623},[188,868,288],{"class":198},[188,870,259],{"class":194},[188,872,199],{"class":198},[188,874,875],{"class":202},"logs\n",[188,877,878,881,883],{"class":190,"line":631},[188,879,880],{"class":194},"      mountPath",[188,882,199],{"class":198},[188,884,885],{"class":202},"\u002Fvar\u002Flog\u002Fapp\n",[188,887,888,890,892,894,897],{"class":190,"line":639},[188,889,256],{"class":198},[188,891,259],{"class":194},[188,893,199],{"class":198},[188,895,896],{"class":202},"check-dependencies",[188,898,899],{"class":300},"              # обычный init, стартует ПОСЛЕ sidecar\n",[188,901,902,904,906],{"class":190,"line":650},[188,903,269],{"class":194},[188,905,199],{"class":198},[188,907,554],{"class":202},[188,909,910,912,914,916,918,920,922,925],{"class":190,"line":661},[188,911,559],{"class":194},[188,913,562],{"class":198},[188,915,565],{"class":202},[188,917,568],{"class":198},[188,919,571],{"class":202},[188,921,568],{"class":198},[188,923,924],{"class":202},"'echo \"deps ok\"'",[188,926,579],{"class":198},[188,928,929,931],{"class":190,"line":668},[188,930,248],{"class":194},[188,932,223],{"class":198},[188,934,935,937,939,941,944],{"class":190,"line":680},[188,936,256],{"class":198},[188,938,259],{"class":194},[188,940,199],{"class":198},[188,942,943],{"class":202},"app",[188,945,946],{"class":300},"                             # основной контейнер\n",[188,948,949,951,953],{"class":190,"line":690},[188,950,269],{"class":194},[188,952,199],{"class":198},[188,954,687],{"class":202},[188,956,957,959],{"class":190,"line":697},[188,958,280],{"class":194},[188,960,223],{"class":198},[188,962,964,966,968,970],{"class":190,"line":963},23,[188,965,288],{"class":198},[188,967,291],{"class":194},[188,969,199],{"class":198},[188,971,706],{"class":296},[188,973,975,977],{"class":190,"line":974},24,[188,976,862],{"class":194},[188,978,223],{"class":198},[188,980,982,984,986,988],{"class":190,"line":981},25,[188,983,288],{"class":198},[188,985,259],{"class":194},[188,987,199],{"class":198},[188,989,875],{"class":202},[188,991,993,995,997],{"class":190,"line":992},26,[188,994,880],{"class":194},[188,996,199],{"class":198},[188,998,885],{"class":202},[188,1000,1002,1005],{"class":190,"line":1001},27,[188,1003,1004],{"class":194},"  volumes",[188,1006,223],{"class":198},[188,1008,1010,1012,1014,1016],{"class":190,"line":1009},28,[188,1011,256],{"class":198},[188,1013,259],{"class":194},[188,1015,199],{"class":198},[188,1017,875],{"class":202},[188,1019,1021,1024],{"class":190,"line":1020},29,[188,1022,1023],{"class":194},"    emptyDir",[188,1025,1026],{"class":198},": {}\n",[15,1028,1029,1030,1032,1033,1035,1036,1032,1038,1040],{},"Порядок запуска: ",[119,1031,791],{}," -> ",[119,1034,832],{}," (native sidecar, не ждёт завершения) -> ",[119,1037,896],{},[119,1039,943],{},". Порядок остановки: SIGTERM основным -> ждём завершения -> SIGTERM native sidecar-ам в обратном порядке. Sidecar гарантированно живёт дольше основных контейнеров.",[15,1042,1043],{},"Когда использовать native sidecar: sidecar критичен для работы pod-а (service mesh), init-контейнеры зависят от sidecar, sidecar должен пережить основные контейнеры (log collector), или batch Jobs где sidecar не должен блокировать завершение.",[18,1045],{},[21,1047,1049],{"id":1048},"pod-lifecycle-фазы","Pod Lifecycle: фазы",[15,1051,1052,1053,1056,1057,1060,1061,1064],{},"Жизненный цикл pod-а проходит три стадии: ",[34,1054,1055],{},"Initialization"," (init-контейнеры последовательно) -> ",[34,1058,1059],{},"Run"," (основные контейнеры параллельно) -> ",[34,1062,1063],{},"Termination"," (graceful shutdown).",[137,1066,1069],{"className":1067,"code":1068,"language":142},[140],"+------------------+  +----------------------+  +-----------------+\n|  Initialization  |  |        Run           |  |  Termination    |\n|                  |  |                      |  |                 |\n| Init 1 -> Init 2 |->| [Container A + B]    |->| SIGTERM -> KILL |\n| -> ... -> Init N |  |  параллельно         |  | параллельно     |\n|  последовательно |  |  + probes + hooks    |  | для всех cont.  |\n+------------------+  +----------------------+  +-----------------+\n",[119,1070,1068],{"__ignoreMap":145},[26,1072,1074],{"id":1073},"pod-phases","Pod Phases",[46,1076,1077,1087],{},[49,1078,1079],{},[52,1080,1081,1084],{},[55,1082,1083],{},"Phase",[55,1085,1086],{},"Описание",[65,1088,1089,1099,1109,1119,1129],{},[52,1090,1091,1096],{},[70,1092,1093],{},[34,1094,1095],{},"Pending",[70,1097,1098],{},"Pod создан, ожидает scheduling, pull images, или init-контейнеры ещё работают",[52,1100,1101,1106],{},[70,1102,1103],{},[34,1104,1105],{},"Running",[70,1107,1108],{},"Хотя бы один контейнер запущен",[52,1110,1111,1116],{},[70,1112,1113],{},[34,1114,1115],{},"Succeeded",[70,1117,1118],{},"Все контейнеры завершились с exit code 0 (типично для Jobs)",[52,1120,1121,1126],{},[70,1122,1123],{},[34,1124,1125],{},"Failed",[70,1127,1128],{},"Хотя бы один контейнер завершился с ненулевым exit code",[52,1130,1131,1136],{},[70,1132,1133],{},[34,1134,1135],{},"Unknown",[70,1137,1138],{},"Kubelet не отвечает (нода упала или проблемы с сетью)",[15,1140,1141],{},"При запуске pod-а с init-контейнерами статус меняется так:",[46,1143,1144,1154],{},[49,1145,1146],{},[52,1147,1148,1151],{},[55,1149,1150],{},"STATUS",[55,1152,1153],{},"Что происходит",[65,1155,1156,1165,1175,1185,1195],{},[52,1157,1158,1162],{},[70,1159,1160],{},[34,1161,1095],{},[70,1163,1164],{},"Pod создан, ожидает scheduling",[52,1166,1167,1172],{},[70,1168,1169],{},[34,1170,1171],{},"Init:0\u002F2",[70,1173,1174],{},"Первый init-контейнер запущен",[52,1176,1177,1182],{},[70,1178,1179],{},[34,1180,1181],{},"Init:1\u002F2",[70,1183,1184],{},"Второй init-контейнер запущен",[52,1186,1187,1192],{},[70,1188,1189],{},[34,1190,1191],{},"PodInitializing",[70,1193,1194],{},"Все init-ы завершились, pull основных images",[52,1196,1197,1201],{},[70,1198,1199],{},[34,1200,1105],{},[70,1202,1203],{},"Основные контейнеры работают",[26,1205,1207],{"id":1206},"container-states","Container States",[15,1209,1210],{},"Каждый контейнер внутри pod-а имеет своё состояние:",[418,1212,1213,1228,1233],{},[421,1214,1215,1218,1219,568,1222,568,1225],{},[34,1216,1217],{},"Waiting"," — ожидает запуска (pull image, ожидание init). Reason: ",[119,1220,1221],{},"ContainerCreating",[119,1223,1224],{},"CrashLoopBackOff",[119,1226,1227],{},"ErrImagePull",[421,1229,1230,1232],{},[34,1231,1105],{}," — процесс запущен и работает",[421,1234,1235,1238,1239,568,1242,568,1245,568,1248],{},[34,1236,1237],{},"Terminated"," — процесс завершился. Содержит ",[119,1240,1241],{},"exitCode",[119,1243,1244],{},"reason",[119,1246,1247],{},"startedAt",[119,1249,1250],{},"finishedAt",[137,1252,1256],{"className":1253,"code":1254,"language":1255,"meta":145,"style":145},"language-bash shiki shiki-themes github-dark","# Посмотреть состояние контейнеров в pod-е\nkubectl get pod my-app -o jsonpath='{.status.containerStatuses}' | jq .\n","bash",[119,1257,1258,1263],{"__ignoreMap":145},[188,1259,1260],{"class":190,"line":191},[188,1261,1262],{"class":300},"# Посмотреть состояние контейнеров в pod-е\n",[188,1264,1265,1269,1272,1275,1278,1281,1284,1288,1291],{"class":190,"line":206},[188,1266,1268],{"class":1267},"svObZ","kubectl",[188,1270,1271],{"class":202}," get",[188,1273,1274],{"class":202}," pod",[188,1276,1277],{"class":202}," my-app",[188,1279,1280],{"class":296}," -o",[188,1282,1283],{"class":202}," jsonpath='{.status.containerStatuses}'",[188,1285,1287],{"class":1286},"snl16"," |",[188,1289,1290],{"class":1267}," jq",[188,1292,1293],{"class":202}," .\n",[26,1295,1297],{"id":1296},"pod-conditions","Pod Conditions",[15,1299,1300],{},"Условия (conditions) pod-а описывают его состояние с разных сторон:",[46,1302,1303,1312],{},[49,1304,1305],{},[52,1306,1307,1310],{},[55,1308,1309],{},"Condition",[55,1311,1086],{},[65,1313,1314,1324,1334,1344],{},[52,1315,1316,1321],{},[70,1317,1318],{},[34,1319,1320],{},"PodScheduled",[70,1322,1323],{},"Pod назначен на ноду",[52,1325,1326,1331],{},[70,1327,1328],{},[34,1329,1330],{},"Initialized",[70,1332,1333],{},"Все init-контейнеры завершились успешно",[52,1335,1336,1341],{},[70,1337,1338],{},[34,1339,1340],{},"ContainersReady",[70,1342,1343],{},"Все контейнеры ready",[52,1345,1346,1351],{},[70,1347,1348],{},[34,1349,1350],{},"Ready",[70,1352,1353],{},"Pod готов обслуживать клиентов (ContainersReady + readiness gates)",[15,1355,1356,1357,568,1360,1363,1364,568,1366,1369,1370,1372,1373,1375,1376,1372,1378,1380],{},"Каждая condition содержит: ",[119,1358,1359],{},"type",[119,1361,1362],{},"status"," (True\u002FFalse\u002FUnknown), ",[119,1365,1244],{},[119,1367,1368],{},"message",". Conditions ",[34,1371,1320],{}," и ",[34,1374,1330],{}," переходят в True и остаются; ",[34,1377,1350],{},[34,1379,1340],{}," могут переключаться туда-сюда в процессе работы.",[18,1382],{},[21,1384,1386],{"id":1385},"probes-liveness-readiness-startup","Probes: Liveness, Readiness, Startup",[15,1388,1389],{},"Probes — механизм, через который Kubelet проверяет состояние контейнеров. Без probes Kubernetes знает только одно: процесс упал (exit code != 0). Но процесс может зависнуть (deadlock, infinite loop, OOM без crash) — pod будет показывать Running, но не отвечать на запросы.",[26,1391,1393],{"id":1392},"liveness-probe","Liveness Probe",[15,1395,1396],{},"Отвечает на вопрос: \"контейнер ещё жив и работает?\"",[15,1398,1399,1400,1403],{},"Без liveness probe: приложение зависло, K8s не знает об этом, pod показывает Running. С liveness probe: K8s периодически проверяет здоровье; если probe fails ",[119,1401,1402],{},"failureThreshold"," раз подряд — контейнер перезапускается.",[137,1405,1407],{"className":182,"code":1406,"language":184,"meta":145,"style":145},"livenessProbe:\n  httpGet:\n    path: \u002Fhealthz\n    port: 8080\n  initialDelaySeconds: 10    # первая проверка через 10s после старта\n  periodSeconds: 5           # проверять каждые 5s\n  timeoutSeconds: 2          # ответ должен прийти за 2s\n  failureThreshold: 3        # 3 фейла подряд -> restart\n  successThreshold: 1        # 1 успех -> считать здоровым (default)\n",[119,1408,1409,1416,1423,1433,1442,1455,1468,1481,1494],{"__ignoreMap":145},[188,1410,1411,1414],{"class":190,"line":191},[188,1412,1413],{"class":194},"livenessProbe",[188,1415,223],{"class":198},[188,1417,1418,1421],{"class":190,"line":206},[188,1419,1420],{"class":194},"  httpGet",[188,1422,223],{"class":198},[188,1424,1425,1428,1430],{"class":190,"line":217},[188,1426,1427],{"class":194},"    path",[188,1429,199],{"class":198},[188,1431,1432],{"class":202},"\u002Fhealthz\n",[188,1434,1435,1438,1440],{"class":190,"line":226},[188,1436,1437],{"class":194},"    port",[188,1439,199],{"class":198},[188,1441,706],{"class":296},[188,1443,1444,1447,1449,1452],{"class":190,"line":237},[188,1445,1446],{"class":194},"  initialDelaySeconds",[188,1448,199],{"class":198},[188,1450,1451],{"class":296},"10",[188,1453,1454],{"class":300},"    # первая проверка через 10s после старта\n",[188,1456,1457,1460,1462,1465],{"class":190,"line":245},[188,1458,1459],{"class":194},"  periodSeconds",[188,1461,199],{"class":198},[188,1463,1464],{"class":296},"5",[188,1466,1467],{"class":300},"           # проверять каждые 5s\n",[188,1469,1470,1473,1475,1478],{"class":190,"line":253},[188,1471,1472],{"class":194},"  timeoutSeconds",[188,1474,199],{"class":198},[188,1476,1477],{"class":296},"2",[188,1479,1480],{"class":300},"          # ответ должен прийти за 2s\n",[188,1482,1483,1486,1488,1491],{"class":190,"line":266},[188,1484,1485],{"class":194},"  failureThreshold",[188,1487,199],{"class":198},[188,1489,1490],{"class":296},"3",[188,1492,1493],{"class":300},"        # 3 фейла подряд -> restart\n",[188,1495,1496,1499,1501,1504],{"class":190,"line":277},[188,1497,1498],{"class":194},"  successThreshold",[188,1500,199],{"class":198},[188,1502,1503],{"class":296},"1",[188,1505,1506],{"class":300},"        # 1 успех -> считать здоровым (default)\n",[15,1508,1509],{},"Временная шкала:",[137,1511,1514],{"className":1512,"code":1513,"language":142},[140],"Container started\n    |\n    +-- 10s (initialDelaySeconds)\n    |\n    v\n  Probe ok --- 5s --> Probe ok --- 5s --> Probe FAIL\n                                            |\n                                         5s v\n                                        Probe FAIL\n                                            |\n                                         5s v\n                                        Probe FAIL  \u003C-- 3 fails (failureThreshold)\n                                            |\n                                            v\n                                      RESTART container\n",[119,1515,1513],{"__ignoreMap":145},[26,1517,1519],{"id":1518},"startup-probe","Startup Probe",[15,1521,1522],{},"Отвечает на вопрос: \"контейнер уже запустился?\"",[15,1524,1525,1526,1372,1529,1532],{},"Проблема: приложение стартует 2 минуты (JVM warmup, загрузка данных). Liveness probe с ",[119,1527,1528],{},"periodSeconds=5",[119,1530,1531],{},"failureThreshold=3"," считает приложение мёртвым через 15 секунд — перезапуск — бесконечный цикл.",[15,1534,1535,1536,1538],{},"Решение: startup probe. Пока startup probe не прошла успешно, liveness probe не запускается. Startup probe может иметь больший ",[119,1537,1402],{},", давая приложению время на старт.",[137,1540,1542],{"className":182,"code":1541,"language":184,"meta":145,"style":145},"startupProbe:                    # фаза запуска\n  httpGet:\n    path: \u002Fhealthz\n    port: 8080\n  periodSeconds: 10              # проверять каждые 10s\n  failureThreshold: 12           # до 120s на запуск (10 * 12)\nlivenessProbe:                   # после запуска\n  httpGet:\n    path: \u002Fhealthz\n    port: 8080\n  periodSeconds: 5               # проверять каждые 5s\n  failureThreshold: 2            # 2 фейла -> restart (быстрая реакция)\n",[119,1543,1544,1555,1561,1569,1577,1588,1600,1610,1616,1624,1632,1643],{"__ignoreMap":145},[188,1545,1546,1549,1552],{"class":190,"line":191},[188,1547,1548],{"class":194},"startupProbe",[188,1550,1551],{"class":198},":                    ",[188,1553,1554],{"class":300},"# фаза запуска\n",[188,1556,1557,1559],{"class":190,"line":206},[188,1558,1420],{"class":194},[188,1560,223],{"class":198},[188,1562,1563,1565,1567],{"class":190,"line":217},[188,1564,1427],{"class":194},[188,1566,199],{"class":198},[188,1568,1432],{"class":202},[188,1570,1571,1573,1575],{"class":190,"line":226},[188,1572,1437],{"class":194},[188,1574,199],{"class":198},[188,1576,706],{"class":296},[188,1578,1579,1581,1583,1585],{"class":190,"line":237},[188,1580,1459],{"class":194},[188,1582,199],{"class":198},[188,1584,1451],{"class":296},[188,1586,1587],{"class":300},"              # проверять каждые 10s\n",[188,1589,1590,1592,1594,1597],{"class":190,"line":245},[188,1591,1485],{"class":194},[188,1593,199],{"class":198},[188,1595,1596],{"class":296},"12",[188,1598,1599],{"class":300},"           # до 120s на запуск (10 * 12)\n",[188,1601,1602,1604,1607],{"class":190,"line":253},[188,1603,1413],{"class":194},[188,1605,1606],{"class":198},":                   ",[188,1608,1609],{"class":300},"# после запуска\n",[188,1611,1612,1614],{"class":190,"line":266},[188,1613,1420],{"class":194},[188,1615,223],{"class":198},[188,1617,1618,1620,1622],{"class":190,"line":277},[188,1619,1427],{"class":194},[188,1621,199],{"class":198},[188,1623,1432],{"class":202},[188,1625,1626,1628,1630],{"class":190,"line":285},[188,1627,1437],{"class":194},[188,1629,199],{"class":198},[188,1631,706],{"class":296},[188,1633,1634,1636,1638,1640],{"class":190,"line":593},[188,1635,1459],{"class":194},[188,1637,199],{"class":198},[188,1639,1464],{"class":296},[188,1641,1642],{"class":300},"               # проверять каждые 5s\n",[188,1644,1645,1647,1649,1651],{"class":190,"line":603},[188,1646,1485],{"class":194},[188,1648,199],{"class":198},[188,1650,1477],{"class":296},[188,1652,1653],{"class":300},"            # 2 фейла -> restart (быстрая реакция)\n",[137,1655,1658],{"className":1656,"code":1657,"language":142},[140],"  Startup probe (мягкая)          Liveness probe (строгая)\n  +---------------------+         +----------------------+\n  | period=10s          |   ok    | period=5s            |\n  | failure=12          |-------->| failure=2            |\n  | = до 120s на старт  |         | = быстрая реакция    |\n  +---------------------+         +----------------------+\n  Fail = норма (ещё старт)         Fail = проблема -> restart\n",[119,1659,1657],{"__ignoreMap":145},[26,1661,1663],{"id":1662},"readiness-probe","Readiness Probe",[15,1665,1666],{},"Отвечает на вопрос: \"контейнер готов принимать трафик?\"",[15,1668,1669],{},"Принципиальное отличие от liveness:",[46,1671,1672,1682],{},[49,1673,1674],{},[52,1675,1676,1679],{},[55,1677,1678],{},"Probe",[55,1680,1681],{},"При fail",[65,1683,1684,1697],{},[52,1685,1686,1691],{},[70,1687,1688],{},[34,1689,1690],{},"Liveness",[70,1692,1693,1694],{},"Контейнер ",[34,1695,1696],{},"перезапускается",[52,1698,1699,1704],{},[70,1700,1701],{},[34,1702,1703],{},"Readiness",[70,1705,1706,1707,1710,1711,1714],{},"Pod ",[34,1708,1709],{},"убирается"," из endpoints Service (перестаёт получать трафик), контейнер ",[34,1712,1713],{},"не"," перезапускается",[15,1716,1717],{},"Use cases для readiness probe:",[418,1719,1720,1723,1726],{},[421,1721,1722],{},"Приложение загружает кэш при старте и ещё не готово",[421,1724,1725],{},"Приложение временно перегружено",[421,1727,1728],{},"Зависимость (база данных) временно недоступна",[15,1730,1731],{},"Конфигурация идентична liveness probe. Когда readiness снова проходит — pod возвращается в endpoints и начинает получать трафик.",[26,1733,1735],{"id":1734},"три-типа-probe","Три типа probe",[15,1737,1738],{},"Каждая probe (liveness, readiness, startup) может использовать один из трёх методов проверки:",[1740,1741,1743],"h4",{"id":1742},"httpget","httpGet",[137,1745,1747],{"className":182,"code":1746,"language":184,"meta":145,"style":145},"livenessProbe:\n  httpGet:\n    path: \u002Fhealthz\n    port: 8080\n",[119,1748,1749,1755,1761,1769],{"__ignoreMap":145},[188,1750,1751,1753],{"class":190,"line":191},[188,1752,1413],{"class":194},[188,1754,223],{"class":198},[188,1756,1757,1759],{"class":190,"line":206},[188,1758,1420],{"class":194},[188,1760,223],{"class":198},[188,1762,1763,1765,1767],{"class":190,"line":217},[188,1764,1427],{"class":194},[188,1766,199],{"class":198},[188,1768,1432],{"class":202},[188,1770,1771,1773,1775],{"class":190,"line":226},[188,1772,1437],{"class":194},[188,1774,199],{"class":198},[188,1776,706],{"class":296},[15,1778,1779,1780,1783],{},"HTTP GET запрос. Код ответа 2xx или 3xx — success, всё остальное — fail. Эндпоинт ",[119,1781,1782],{},"\u002Fhealthz"," не должен требовать аутентификацию.",[1740,1785,1787],{"id":1786},"tcpsocket","tcpSocket",[137,1789,1791],{"className":182,"code":1790,"language":184,"meta":145,"style":145},"livenessProbe:\n  tcpSocket:\n    port: 5432\n",[119,1792,1793,1799,1806],{"__ignoreMap":145},[188,1794,1795,1797],{"class":190,"line":191},[188,1796,1413],{"class":194},[188,1798,223],{"class":198},[188,1800,1801,1804],{"class":190,"line":206},[188,1802,1803],{"class":194},"  tcpSocket",[188,1805,223],{"class":198},[188,1807,1808,1810,1812],{"class":190,"line":217},[188,1809,1437],{"class":194},[188,1811,199],{"class":198},[188,1813,1814],{"class":296},"5432\n",[15,1816,1817],{},"TCP-подключение к указанному порту. Порт открыт — success, не открыт — fail. Для non-HTTP приложений: Redis, PostgreSQL, gRPC.",[1740,1819,1820],{"id":1820},"exec",[137,1822,1824],{"className":182,"code":1823,"language":184,"meta":145,"style":145},"livenessProbe:\n  exec:\n    command: [\"\u002Fbin\u002Fhealthcheck\"]\n",[119,1825,1826,1832,1839],{"__ignoreMap":145},[188,1827,1828,1830],{"class":190,"line":191},[188,1829,1413],{"class":194},[188,1831,223],{"class":198},[188,1833,1834,1837],{"class":190,"line":206},[188,1835,1836],{"class":194},"  exec",[188,1838,223],{"class":198},[188,1840,1841,1843,1845,1848],{"class":190,"line":217},[188,1842,559],{"class":194},[188,1844,562],{"class":198},[188,1846,1847],{"class":202},"\"\u002Fbin\u002Fhealthcheck\"",[188,1849,579],{"class":198},[15,1851,1852],{},"Запуск команды внутри контейнера. Exit code 0 — success, всё остальное — fail. Для приложений без сети (batch processing). Учитывай, что exec запускает процесс внутри контейнера и потребляет его ресурсы.",[26,1854,1856],{"id":1855},"best-practices-для-probes","Best Practices для Probes",[15,1858,1859],{},[34,1860,1861],{},"Рекомендуется:",[418,1863,1864,1867,1872,1875,1878,1884],{},[421,1865,1866],{},"Определяй liveness probe для всех pod-ов",[421,1868,1869,1871],{},[119,1870,1782],{}," должен проверять только внутреннее здоровье приложения",[421,1873,1874],{},"Не проверяй внешние зависимости (БД, другие сервисы) в liveness probe — иначе: backend упал -> frontend restart -> каскадный отказ всей системы",[421,1876,1877],{},"Probe handler должен быть лёгким и быстрым",[421,1879,1880,1881,1883],{},"Используй ",[119,1882,1402],{}," вместо retry-логики внутри handler-а",[421,1885,1886,1887,1889,1890,1892],{},"Для Java: ",[119,1888,1743],{}," лучше ",[119,1891,1820],{}," (exec каждый раз запускает JVM-процесс)",[15,1894,1895],{},[34,1896,1897],{},"Не рекомендуется:",[418,1899,1900,1903],{},[421,1901,1902],{},"Проверять connectivity к другим сервисам в liveness",[421,1904,1905],{},"Делать тяжёлые операции (запросы к БД, обработка данных) в probe handler",[18,1907],{},[21,1909,1911],{"id":1910},"lifecycle-hooks-poststart-и-prestop","Lifecycle Hooks: postStart и preStop",[15,1913,1914,1915,1372,1918,1921,1922,1372,1924,1926,1927,1929],{},"Lifecycle hooks позволяют выполнить действия при создании и перед удалением контейнера. Доступны два типа: ",[119,1916,1917],{},"postStart",[119,1919,1920],{},"preStop",". Оба поддерживают ",[119,1923,1820],{},[119,1925,1743],{}," (но не ",[119,1928,1787],{},").",[26,1931,1933],{"id":1932},"poststart-hook","postStart Hook",[15,1935,1936,1937,1940],{},"Выполняется ",[34,1938,1939],{},"параллельно"," со стартом основного процесса — не \"после старта\", а \"при старте\".",[137,1942,1944],{"className":182,"code":1943,"language":184,"meta":145,"style":145},"lifecycle:\n  postStart:\n    exec:\n      command: [\"sh\", \"-c\", \"echo started > \u002Ftmp\u002Fstarted\"]\n",[119,1945,1946,1953,1960,1967],{"__ignoreMap":145},[188,1947,1948,1951],{"class":190,"line":191},[188,1949,1950],{"class":194},"lifecycle",[188,1952,223],{"class":198},[188,1954,1955,1958],{"class":190,"line":206},[188,1956,1957],{"class":194},"  postStart",[188,1959,223],{"class":198},[188,1961,1962,1965],{"class":190,"line":217},[188,1963,1964],{"class":194},"    exec",[188,1966,223],{"class":198},[188,1968,1969,1972,1974,1977,1979,1982,1984,1987],{"class":190,"line":226},[188,1970,1971],{"class":194},"      command",[188,1973,562],{"class":198},[188,1975,1976],{"class":202},"\"sh\"",[188,1978,568],{"class":198},[188,1980,1981],{"class":202},"\"-c\"",[188,1983,568],{"class":198},[188,1985,1986],{"class":202},"\"echo started > \u002Ftmp\u002Fstarted\"",[188,1988,579],{"class":198},[137,1990,1992],{"className":182,"code":1991,"language":184,"meta":145,"style":145},"lifecycle:\n  postStart:\n    httpGet:\n      path: \u002Fwarm-up\n      port: 8080\n",[119,1993,1994,2000,2006,2013,2023],{"__ignoreMap":145},[188,1995,1996,1998],{"class":190,"line":191},[188,1997,1950],{"class":194},[188,1999,223],{"class":198},[188,2001,2002,2004],{"class":190,"line":206},[188,2003,1957],{"class":194},[188,2005,223],{"class":198},[188,2007,2008,2011],{"class":190,"line":217},[188,2009,2010],{"class":194},"    httpGet",[188,2012,223],{"class":198},[188,2014,2015,2018,2020],{"class":190,"line":226},[188,2016,2017],{"class":194},"      path",[188,2019,199],{"class":198},[188,2021,2022],{"class":202},"\u002Fwarm-up\n",[188,2024,2025,2028,2030],{"class":190,"line":237},[188,2026,2027],{"class":194},"      port",[188,2029,199],{"class":198},[188,2031,706],{"class":296},[15,2033,2034,2035,1372,2038,2041,2042,2044],{},"Поведение: пока hook не завершится, контейнер в статусе Waiting; ",[119,2036,2037],{},"kubectl logs",[119,2039,2040],{},"port-forward"," не работают; fail hook приводит к рестарту контейнера; блокирует создание следующего контейнера в pod-е. Важно: ",[119,2043,1743],{}," postStart к своему контейнеру может вызвать бесконечный restart loop (приложение ещё не готово).",[26,2046,2048],{"id":2047},"prestop-hook","preStop Hook",[15,2050,1936,2051,2054],{},[34,2052,2053],{},"перед"," отправкой SIGTERM. Последовательность: preStop hook -> (завершился) -> SIGTERM -> (grace period) -> SIGKILL.",[137,2056,2058],{"className":182,"code":2057,"language":184,"meta":145,"style":145},"lifecycle:\n  preStop:\n    exec:\n      command: [\"nginx\", \"-s\", \"quit\"]    # graceful shutdown nginx\n",[119,2059,2060,2066,2073,2079],{"__ignoreMap":145},[188,2061,2062,2064],{"class":190,"line":191},[188,2063,1950],{"class":194},[188,2065,223],{"class":198},[188,2067,2068,2071],{"class":190,"line":206},[188,2069,2070],{"class":194},"  preStop",[188,2072,223],{"class":198},[188,2074,2075,2077],{"class":190,"line":217},[188,2076,1964],{"class":194},[188,2078,223],{"class":198},[188,2080,2081,2083,2085,2088,2090,2093,2095,2098,2101],{"class":190,"line":226},[188,2082,1971],{"class":194},[188,2084,562],{"class":198},[188,2086,2087],{"class":202},"\"nginx\"",[188,2089,568],{"class":198},[188,2091,2092],{"class":202},"\"-s\"",[188,2094,568],{"class":198},[188,2096,2097],{"class":202},"\"quit\"",[188,2099,2100],{"class":198},"]    ",[188,2102,2103],{"class":300},"# graceful shutdown nginx\n",[137,2105,2107],{"className":182,"code":2106,"language":184,"meta":145,"style":145},"lifecycle:\n  preStop:\n    httpGet:\n      path: \u002Fshutdown\n      port: 8080\n",[119,2108,2109,2115,2121,2127,2136],{"__ignoreMap":145},[188,2110,2111,2113],{"class":190,"line":191},[188,2112,1950],{"class":194},[188,2114,223],{"class":198},[188,2116,2117,2119],{"class":190,"line":206},[188,2118,2070],{"class":194},[188,2120,223],{"class":198},[188,2122,2123,2125],{"class":190,"line":217},[188,2124,2010],{"class":194},[188,2126,223],{"class":198},[188,2128,2129,2131,2133],{"class":190,"line":226},[188,2130,2017],{"class":194},[188,2132,199],{"class":198},[188,2134,2135],{"class":202},"\u002Fshutdown\n",[188,2137,2138,2140,2142],{"class":190,"line":237},[188,2139,2027],{"class":194},[188,2141,199],{"class":198},[188,2143,706],{"class":296},[137,2145,2147],{"className":182,"code":2146,"language":184,"meta":145,"style":145},"lifecycle:\n  preStop:\n    sleep:\n      seconds: 5     # подождать 5s перед SIGTERM\n",[119,2148,2149,2155,2161,2168],{"__ignoreMap":145},[188,2150,2151,2153],{"class":190,"line":191},[188,2152,1950],{"class":194},[188,2154,223],{"class":198},[188,2156,2157,2159],{"class":190,"line":206},[188,2158,2070],{"class":194},[188,2160,223],{"class":198},[188,2162,2163,2166],{"class":190,"line":217},[188,2164,2165],{"class":194},"    sleep",[188,2167,223],{"class":198},[188,2169,2170,2173,2175,2177],{"class":190,"line":226},[188,2171,2172],{"class":194},"      seconds",[188,2174,199],{"class":198},[188,2176,1464],{"class":296},[188,2178,2179],{"class":300},"     # подождать 5s перед SIGTERM\n",[15,2181,2182,2183,2186],{},"Поведение: ошибка hook не предотвращает termination; время preStop входит в ",[119,2184,2185],{},"terminationGracePeriodSeconds","; вызывается при liveness fail, pod delete, scale down; не вызывается когда процесс завершился сам.",[18,2188],{},[21,2190,2192],{"id":2191},"termination-graceful-shutdown","Termination: graceful shutdown",[15,2194,2195],{},"Когда pod удаляется (kubectl delete, scale down, rolling update), запускается последовательность завершения:",[137,2197,2200],{"className":2198,"code":2199,"language":142},[140],"kubectl delete pod \u003Cname>\n\n        terminationGracePeriodSeconds (default = 30s)\n        |-----------------------------------------------------|\n\n  +----------+    +----------+    +----------+\n  |Container |    |Container |    |Container |\n  |    A     |    |    B     |    |    C     |\n  |          |    |          |    |          |\n  | preStop  |    |  SIGTERM |    | preStop  |    \u003C-- параллельно для всех\n  |  hook    |    |    |     |    |  hook    |\n  |    |     |    | process  |    |    |     |\n  | SIGTERM  |    | exits    |    | SIGTERM  |\n  |    |     |    |          |    |    |     |\n  | process  |    |          |    | SIGKILL  |    \u003C-- если не завершился за grace period\n  | exits    |    |          |    |          |\n  +----------+    +----------+    +----------+\n\nПосле всех основных контейнеров -> terminate native sidecars (обратный порядок)\n",[119,2201,2199],{"__ignoreMap":145},[15,2203,2204,2206],{},[119,2205,2185],{}," — по умолчанию 30 секунд. Этого достаточно для большинства приложений, но может потребоваться увеличение для сервисов с длинными запросами или потоковой обработкой.",[26,2208,2210],{"id":2209},"sigterm-и-dockerfile","SIGTERM и Dockerfile",[15,2212,2213,2214,2217],{},"Критически важно, как написан ",[119,2215,2216],{},"ENTRYPOINT"," в Dockerfile:",[15,2219,2220],{},[34,2221,2222],{},"Shell form — SIGTERM НЕ доходит до приложения:",[137,2224,2228],{"className":2225,"code":2226,"language":2227,"meta":145,"style":145},"language-dockerfile shiki shiki-themes github-dark","ENTRYPOINT \u002Fmyapp arg1 arg2\n","dockerfile",[119,2229,2230],{"__ignoreMap":145},[188,2231,2232,2234],{"class":190,"line":191},[188,2233,2216],{"class":1286},[188,2235,2236],{"class":198}," \u002Fmyapp arg1 arg2\n",[15,2238,2239],{},"Shell запускается как PID 1, myapp как дочерний процесс. SIGTERM отправляется shell-у, который его не передаёт дальше. Приложение не получает сигнал и будет убито через SIGKILL.",[15,2241,2242],{},[34,2243,2244],{},"Exec form — SIGTERM доходит:",[137,2246,2248],{"className":2225,"code":2247,"language":2227,"meta":145,"style":145},"ENTRYPOINT [\"\u002Fmyapp\", \"arg1\", \"arg2\"]\n",[119,2249,2250],{"__ignoreMap":145},[188,2251,2252,2254,2257,2260,2262,2265,2267,2270],{"class":190,"line":191},[188,2253,2216],{"class":1286},[188,2255,2256],{"class":198}," [",[188,2258,2259],{"class":202},"\"\u002Fmyapp\"",[188,2261,568],{"class":198},[188,2263,2264],{"class":202},"\"arg1\"",[188,2266,568],{"class":198},[188,2268,2269],{"class":202},"\"arg2\"",[188,2271,579],{"class":198},[15,2273,2274],{},"myapp запускается как PID 1 и получает SIGTERM напрямую.",[15,2276,2277],{},"Пример обработки SIGTERM в Go:",[137,2279,2284],{"className":2280,"code":2281,"language":2282,"meta":2283,"style":145},"language-go shiki shiki-themes github-dark","package main\n\nimport (\n    \"context\"\n    \"log\"\n    \"net\u002Fhttp\"\n    \"os\"\n    \"os\u002Fsignal\"\n    \"syscall\"\n    \"time\"\n)\n\nfunc main() {\n    srv := &http.Server{Addr: \":8080\"}\n\n    \u002F\u002F Запускаем сервер в горутине\n    go func() {\n        if err := srv.ListenAndServe(); err != http.ErrServerClosed {\n            log.Fatalf(\"HTTP server error: %v\", err)\n        }\n    }()\n\n    \u002F\u002F Ждём SIGTERM или SIGINT\n    quit := make(chan os.Signal, 1)\n    signal.Notify(quit, syscall.SIGTERM, syscall.SIGINT)\n    \u003C-quit\n\n    log.Println(\"Shutting down server...\")\n\n    \u002F\u002F Graceful shutdown с таймаутом\n    ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)\n    defer cancel()\n\n    if err := srv.Shutdown(ctx); err != nil {\n        log.Fatalf(\"Server forced to shutdown: %v\", err)\n    }\n\n    log.Println(\"Server exited\")\n}\n","go","no-run",[119,2285,2286,2294,2300,2308,2319,2328,2337,2346,2355,2364,2373,2378,2382,2393,2422,2426,2431,2441,2466,2489,2494,2499,2503,2508,2537,2548,2556,2560,2575,2579,2585,2617,2629,2634,2660,2679,2685,2690,2704],{"__ignoreMap":145},[188,2287,2288,2291],{"class":190,"line":191},[188,2289,2290],{"class":1286},"package",[188,2292,2293],{"class":1267}," main\n",[188,2295,2296],{"class":190,"line":206},[188,2297,2299],{"emptyLinePlaceholder":2298},true,"\n",[188,2301,2302,2305],{"class":190,"line":217},[188,2303,2304],{"class":1286},"import",[188,2306,2307],{"class":198}," (\n",[188,2309,2310,2313,2316],{"class":190,"line":226},[188,2311,2312],{"class":202},"    \"",[188,2314,2315],{"class":1267},"context",[188,2317,2318],{"class":202},"\"\n",[188,2320,2321,2323,2326],{"class":190,"line":237},[188,2322,2312],{"class":202},[188,2324,2325],{"class":1267},"log",[188,2327,2318],{"class":202},[188,2329,2330,2332,2335],{"class":190,"line":245},[188,2331,2312],{"class":202},[188,2333,2334],{"class":1267},"net\u002Fhttp",[188,2336,2318],{"class":202},[188,2338,2339,2341,2344],{"class":190,"line":253},[188,2340,2312],{"class":202},[188,2342,2343],{"class":1267},"os",[188,2345,2318],{"class":202},[188,2347,2348,2350,2353],{"class":190,"line":266},[188,2349,2312],{"class":202},[188,2351,2352],{"class":1267},"os\u002Fsignal",[188,2354,2318],{"class":202},[188,2356,2357,2359,2362],{"class":190,"line":277},[188,2358,2312],{"class":202},[188,2360,2361],{"class":1267},"syscall",[188,2363,2318],{"class":202},[188,2365,2366,2368,2371],{"class":190,"line":285},[188,2367,2312],{"class":202},[188,2369,2370],{"class":1267},"time",[188,2372,2318],{"class":202},[188,2374,2375],{"class":190,"line":593},[188,2376,2377],{"class":198},")\n",[188,2379,2380],{"class":190,"line":603},[188,2381,2299],{"emptyLinePlaceholder":2298},[188,2383,2384,2387,2390],{"class":190,"line":611},[188,2385,2386],{"class":1286},"func",[188,2388,2389],{"class":1267}," main",[188,2391,2392],{"class":198},"() {\n",[188,2394,2395,2398,2401,2404,2407,2410,2413,2416,2419],{"class":190,"line":623},[188,2396,2397],{"class":198},"    srv ",[188,2399,2400],{"class":1286},":=",[188,2402,2403],{"class":1286}," &",[188,2405,2406],{"class":1267},"http",[188,2408,2409],{"class":198},".",[188,2411,2412],{"class":1267},"Server",[188,2414,2415],{"class":198},"{Addr: ",[188,2417,2418],{"class":202},"\":8080\"",[188,2420,2421],{"class":198},"}\n",[188,2423,2424],{"class":190,"line":631},[188,2425,2299],{"emptyLinePlaceholder":2298},[188,2427,2428],{"class":190,"line":639},[188,2429,2430],{"class":300},"    \u002F\u002F Запускаем сервер в горутине\n",[188,2432,2433,2436,2439],{"class":190,"line":650},[188,2434,2435],{"class":1286},"    go",[188,2437,2438],{"class":1286}," func",[188,2440,2392],{"class":198},[188,2442,2443,2446,2449,2451,2454,2457,2460,2463],{"class":190,"line":661},[188,2444,2445],{"class":1286},"        if",[188,2447,2448],{"class":198}," err ",[188,2450,2400],{"class":1286},[188,2452,2453],{"class":198}," srv.",[188,2455,2456],{"class":1267},"ListenAndServe",[188,2458,2459],{"class":198},"(); err ",[188,2461,2462],{"class":1286},"!=",[188,2464,2465],{"class":198}," http.ErrServerClosed {\n",[188,2467,2468,2471,2474,2477,2480,2483,2486],{"class":190,"line":668},[188,2469,2470],{"class":198},"            log.",[188,2472,2473],{"class":1267},"Fatalf",[188,2475,2476],{"class":198},"(",[188,2478,2479],{"class":202},"\"HTTP server error: ",[188,2481,2482],{"class":296},"%v",[188,2484,2485],{"class":202},"\"",[188,2487,2488],{"class":198},", err)\n",[188,2490,2491],{"class":190,"line":680},[188,2492,2493],{"class":198},"        }\n",[188,2495,2496],{"class":190,"line":690},[188,2497,2498],{"class":198},"    }()\n",[188,2500,2501],{"class":190,"line":697},[188,2502,2299],{"emptyLinePlaceholder":2298},[188,2504,2505],{"class":190,"line":963},[188,2506,2507],{"class":300},"    \u002F\u002F Ждём SIGTERM или SIGINT\n",[188,2509,2510,2513,2515,2518,2520,2523,2526,2528,2531,2533,2535],{"class":190,"line":974},[188,2511,2512],{"class":198},"    quit ",[188,2514,2400],{"class":1286},[188,2516,2517],{"class":1267}," make",[188,2519,2476],{"class":198},[188,2521,2522],{"class":1286},"chan",[188,2524,2525],{"class":1267}," os",[188,2527,2409],{"class":198},[188,2529,2530],{"class":1267},"Signal",[188,2532,568],{"class":198},[188,2534,1503],{"class":296},[188,2536,2377],{"class":198},[188,2538,2539,2542,2545],{"class":190,"line":981},[188,2540,2541],{"class":198},"    signal.",[188,2543,2544],{"class":1267},"Notify",[188,2546,2547],{"class":198},"(quit, syscall.SIGTERM, syscall.SIGINT)\n",[188,2549,2550,2553],{"class":190,"line":992},[188,2551,2552],{"class":1286},"    \u003C-",[188,2554,2555],{"class":198},"quit\n",[188,2557,2558],{"class":190,"line":1001},[188,2559,2299],{"emptyLinePlaceholder":2298},[188,2561,2562,2565,2568,2570,2573],{"class":190,"line":1009},[188,2563,2564],{"class":198},"    log.",[188,2566,2567],{"class":1267},"Println",[188,2569,2476],{"class":198},[188,2571,2572],{"class":202},"\"Shutting down server...\"",[188,2574,2377],{"class":198},[188,2576,2577],{"class":190,"line":1020},[188,2578,2299],{"emptyLinePlaceholder":2298},[188,2580,2582],{"class":190,"line":2581},30,[188,2583,2584],{"class":300},"    \u002F\u002F Graceful shutdown с таймаутом\n",[188,2586,2588,2591,2593,2596,2599,2602,2605,2608,2611,2614],{"class":190,"line":2587},31,[188,2589,2590],{"class":198},"    ctx, cancel ",[188,2592,2400],{"class":1286},[188,2594,2595],{"class":198}," context.",[188,2597,2598],{"class":1267},"WithTimeout",[188,2600,2601],{"class":198},"(context.",[188,2603,2604],{"class":1267},"Background",[188,2606,2607],{"class":198},"(), ",[188,2609,2610],{"class":296},"15",[188,2612,2613],{"class":1286},"*",[188,2615,2616],{"class":198},"time.Second)\n",[188,2618,2620,2623,2626],{"class":190,"line":2619},32,[188,2621,2622],{"class":1286},"    defer",[188,2624,2625],{"class":1267}," cancel",[188,2627,2628],{"class":198},"()\n",[188,2630,2632],{"class":190,"line":2631},33,[188,2633,2299],{"emptyLinePlaceholder":2298},[188,2635,2637,2640,2642,2644,2646,2649,2652,2654,2657],{"class":190,"line":2636},34,[188,2638,2639],{"class":1286},"    if",[188,2641,2448],{"class":198},[188,2643,2400],{"class":1286},[188,2645,2453],{"class":198},[188,2647,2648],{"class":1267},"Shutdown",[188,2650,2651],{"class":198},"(ctx); err ",[188,2653,2462],{"class":1286},[188,2655,2656],{"class":296}," nil",[188,2658,2659],{"class":198}," {\n",[188,2661,2663,2666,2668,2670,2673,2675,2677],{"class":190,"line":2662},35,[188,2664,2665],{"class":198},"        log.",[188,2667,2473],{"class":1267},[188,2669,2476],{"class":198},[188,2671,2672],{"class":202},"\"Server forced to shutdown: ",[188,2674,2482],{"class":296},[188,2676,2485],{"class":202},[188,2678,2488],{"class":198},[188,2680,2682],{"class":190,"line":2681},36,[188,2683,2684],{"class":198},"    }\n",[188,2686,2688],{"class":190,"line":2687},37,[188,2689,2299],{"emptyLinePlaceholder":2298},[188,2691,2693,2695,2697,2699,2702],{"class":190,"line":2692},38,[188,2694,2564],{"class":198},[188,2696,2567],{"class":1267},[188,2698,2476],{"class":198},[188,2700,2701],{"class":202},"\"Server exited\"",[188,2703,2377],{"class":198},[188,2705,2707],{"class":190,"line":2706},39,[188,2708,2421],{"class":198},[26,2710,2712],{"id":2711},"exit-codes","Exit Codes",[46,2714,2715,2725],{},[49,2716,2717],{},[52,2718,2719,2722],{},[55,2720,2721],{},"Code",[55,2723,2724],{},"Значение",[65,2726,2727,2737,2746,2756],{},[52,2728,2729,2734],{},[70,2730,2731],{},[34,2732,2733],{},"0",[70,2735,2736],{},"Успешное завершение",[52,2738,2739,2743],{},[70,2740,2741],{},[34,2742,1503],{},[70,2744,2745],{},"Ошибка приложения (generic)",[52,2747,2748,2753],{},[70,2749,2750],{},[34,2751,2752],{},"137",[70,2754,2755],{},"128 + 9 (SIGKILL) — контейнер убит принудительно (не уложился в grace period или OOMKilled)",[52,2757,2758,2763],{},[70,2759,2760],{},[34,2761,2762],{},"143",[70,2764,2765],{},"128 + 15 (SIGTERM) — контейнер завершился по SIGTERM",[18,2767],{},[21,2769,2771],{"id":2770},"restartpolicy-и-exponential-backoff","restartPolicy и exponential backoff",[15,2773,2774,2775,2778],{},"restartPolicy задаётся на уровне pod-а и применяется ко ",[34,2776,2777],{},"всем"," контейнерам:",[46,2780,2781,2791],{},[49,2782,2783],{},[52,2784,2785,2788],{},[55,2786,2787],{},"Policy",[55,2789,2790],{},"Поведение",[65,2792,2793,2805,2815],{},[52,2794,2795,2799],{},[70,2796,2797],{},[34,2798,854],{},[70,2800,2801,2802],{},"Перезапуск при любом exit code ",[34,2803,2804],{},"(default)",[52,2806,2807,2812],{},[70,2808,2809],{},[34,2810,2811],{},"OnFailure",[70,2813,2814],{},"Перезапуск только при exit code != 0",[52,2816,2817,2822],{},[70,2818,2819],{},[34,2820,2821],{},"Never",[70,2823,2824],{},"Никогда не перезапускать",[15,2826,2827,2828,2831],{},"Важно: \"restart\" в Kubernetes — это не перезапуск процесса, а ",[34,2829,2830],{},"пересоздание контейнера",". Старый контейнер уничтожается, новый создаётся. Данные на файловой системе контейнера теряются (если нет volume).",[26,2833,2835],{"id":2834},"exponential-backoff","Exponential Backoff",[15,2837,2838],{},"При повторных падениях Kubernetes увеличивает задержку перед перезапуском:",[46,2840,2841,2851],{},[49,2842,2843],{},[52,2844,2845,2848],{},[55,2846,2847],{},"Restart",[55,2849,2850],{},"Задержка",[65,2852,2853,2861,2869,2877,2885,2893,2901],{},[52,2854,2855,2858],{},[70,2856,2857],{},"1-й",[70,2859,2860],{},"0s (сразу)",[52,2862,2863,2866],{},[70,2864,2865],{},"2-й",[70,2867,2868],{},"10s",[52,2870,2871,2874],{},[70,2872,2873],{},"3-й",[70,2875,2876],{},"20s",[52,2878,2879,2882],{},[70,2880,2881],{},"4-й",[70,2883,2884],{},"40s",[52,2886,2887,2890],{},[70,2888,2889],{},"5-й",[70,2891,2892],{},"80s",[52,2894,2895,2898],{},[70,2896,2897],{},"6-й",[70,2899,2900],{},"160s",[52,2902,2903,2906],{},[70,2904,2905],{},"7+",[70,2907,2908],{},"300s (cap, 5 минут)",[15,2910,2911,2912,2409],{},"Если контейнер проработал 10+ минут без падений — backoff сбрасывается до 0. Пока контейнер ожидает перезапуска, его статус — ",[34,2913,1224],{},[18,2915],{},[21,2917,2919],{"id":2918},"kubectl-команды-для-работы-с-pod-ами","kubectl — команды для работы с pod-ами",[46,2921,2922,2931],{},[49,2923,2924],{},[52,2925,2926,2929],{},[55,2927,2928],{},"Команда",[55,2930,338],{},[65,2932,2933,2943,2953,2963,2973,2983,2993,3003,3013,3023,3033,3043],{},[52,2934,2935,2940],{},[70,2936,2937],{},[119,2938,2939],{},"kubectl get pods",[70,2941,2942],{},"Список pod-ов",[52,2944,2945,2950],{},[70,2946,2947],{},[119,2948,2949],{},"kubectl get pods -w",[70,2951,2952],{},"Watch — обновления в реальном времени",[52,2954,2955,2960],{},[70,2956,2957],{},[119,2958,2959],{},"kubectl describe pod \u003Cname>",[70,2961,2962],{},"Подробная информация + events",[52,2964,2965,2970],{},[70,2966,2967],{},[119,2968,2969],{},"kubectl logs \u003Cpod>",[70,2971,2972],{},"Логи контейнера (stdout\u002Fstderr)",[52,2974,2975,2980],{},[70,2976,2977],{},[119,2978,2979],{},"kubectl logs \u003Cpod> -f",[70,2981,2982],{},"Стриминг логов",[52,2984,2985,2990],{},[70,2986,2987],{},[119,2988,2989],{},"kubectl logs \u003Cpod> -c \u003Ccontainer>",[70,2991,2992],{},"Логи конкретного контейнера",[52,2994,2995,3000],{},[70,2996,2997],{},[119,2998,2999],{},"kubectl logs \u003Cpod> --previous",[70,3001,3002],{},"Логи предыдущего контейнера (после restart)",[52,3004,3005,3010],{},[70,3006,3007],{},[119,3008,3009],{},"kubectl exec -it \u003Cpod> -- bash",[70,3011,3012],{},"Shell внутри контейнера",[52,3014,3015,3020],{},[70,3016,3017],{},[119,3018,3019],{},"kubectl exec \u003Cpod> -c \u003Ccont> -- cmd",[70,3021,3022],{},"Команда в конкретном контейнере",[52,3024,3025,3030],{},[70,3026,3027],{},[119,3028,3029],{},"kubectl port-forward \u003Cpod> 8080:8080",[70,3031,3032],{},"Проксирование порта на localhost",[52,3034,3035,3040],{},[70,3036,3037],{},[119,3038,3039],{},"kubectl cp \u003Cpod>:path localpath",[70,3041,3042],{},"Копировать файл из контейнера",[52,3044,3045,3050],{},[70,3046,3047],{},[119,3048,3049],{},"kubectl debug \u003Cpod> -it --image=nicolaka\u002Fnetshoot",[70,3051,3052],{},"Ephemeral debug container",[15,3054,3055,3056,3059,3060,3062],{},"Для distroless-контейнеров без debug-утилит: ",[119,3057,3058],{},"kubectl debug"," добавляет временный контейнер к существующему pod-у без пересоздания. С ",[119,3061,121],{}," debug-контейнер видит процессы всех контейнеров.",[137,3064,3066],{"className":1253,"code":3065,"language":1255,"meta":145,"style":145},"kubectl debug my-app -it --image nicolaka\u002Fnetshoot\n# netshoot содержит: tcpdump, curl, dig, strace, ip, ss...\n",[119,3067,3068,3086],{"__ignoreMap":145},[188,3069,3070,3072,3075,3077,3080,3083],{"class":190,"line":191},[188,3071,1268],{"class":1267},[188,3073,3074],{"class":202}," debug",[188,3076,1277],{"class":202},[188,3078,3079],{"class":296}," -it",[188,3081,3082],{"class":296}," --image",[188,3084,3085],{"class":202}," nicolaka\u002Fnetshoot\n",[188,3087,3088],{"class":190,"line":206},[188,3089,3090],{"class":300},"# netshoot содержит: tcpdump, curl, dig, strace, ip, ss...\n",[18,3092],{},[21,3094,3096],{"id":3095},"вопросы-на-собеседовании","Вопросы на собеседовании",[15,3098,3099],{},[34,3100,3101],{},"Что такое Pod и почему это не просто контейнер?",[15,3103,3104],{},"Pod — минимальная единица деплоя в Kubernetes, которая может содержать один или несколько контейнеров. Контейнеры в pod-е разделяют сетевое пространство (один IP, один hostname, общаются через localhost), IPC namespace и могут шарить volumes. Pod нужен потому, что контейнер по дизайну — один процесс, а приложению часто нужны вспомогательные процессы (sidecar proxy, log collector), которые должны работать на одном хосте и иметь общую сеть. Kubernetes масштабирует pod-ы целиком, а не отдельные контейнеры.",[15,3106,3107],{},[34,3108,3109],{},"В чём разница между liveness, readiness и startup probes?",[15,3111,3112],{},"Liveness probe проверяет, жив ли контейнер. При fail — контейнер перезапускается. Нужна для обнаружения deadlock-ов и зависаний, которые не приводят к crash-у процесса. Readiness probe проверяет, готов ли контейнер принимать трафик. При fail — pod убирается из endpoints Service (перестаёт получать запросы), но контейнер не перезапускается. Нужна при загрузке кэша, временной перегрузке, недоступности зависимости. Startup probe проверяет, завершился ли запуск приложения. Пока startup probe не прошла — liveness probe не запускается. Нужна для медленно стартующих приложений, чтобы liveness не убила контейнер, который ещё инициализируется.",[15,3114,3115],{},[34,3116,3117],{},"Что такое init-контейнеры и чем они отличаются от обычных?",[15,3119,3120,3121,3123],{},"Init-контейнеры запускаются последовательно перед основными. Используются для ожидания зависимостей, миграции БД, загрузки конфигурации. После завершения init-контейнера его filesystem недоступен основным контейнерам. Native sidecar (K8s 1.28+) — init-контейнер с ",[119,3122,731],{},", стартует в init-фазе, живёт всё время работы pod-а, завершается после основных контейнеров.",[15,3125,3126],{},[34,3127,3128],{},"Что происходит при удалении pod-а?",[15,3130,3131,3132,3134,3135,3138],{},"Termination sequence: (1) preStop hook для каждого контейнера параллельно; (2) SIGTERM; (3) ожидание ",[119,3133,2185],{}," (default 30s); (4) SIGKILL если не завершился. Время preStop входит в grace period. Native sidecar-ы завершаются после основных контейнеров. Важно: exec form в ENTRYPOINT (",[119,3136,3137],{},"ENTRYPOINT [\"\u002Fapp\"]",") чтобы SIGTERM дошёл до приложения.",[15,3140,3141],{},[34,3142,3143],{},"Что такое CrashLoopBackOff и как с ним разбираться?",[15,3145,3146,3147,1372,3150,3153],{},"CrashLoopBackOff — статус контейнера, который повторно падает с exponential backoff (0s, 10s, 20s...300s cap). Диагностика: ",[119,3148,3149],{},"kubectl logs --previous",[119,3151,3152],{},"kubectl describe pod",". Частые причины: OOMKilled (exit 137), неверные env vars, недоступность зависимости, ошибка в ENTRYPOINT\u002FCMD, panic при инициализации.",[15,3155,3156],{},[34,3157,3158],{},"Почему не стоит проверять зависимости (БД) в liveness probe?",[15,3160,3161],{},"При недоступности БД все pod-ы начнут перезапускаться одновременно — каскадный отказ. После восстановления — thundering herd. Liveness должна проверять только внутреннее здоровье (deadlock, процесс отвечает). Для зависимостей — readiness probe: pod убирается из endpoints, но не перезапускается.",[15,3163,3164],{},[34,3165,3166],{},"В чём разница между restartPolicy: Always, OnFailure и Never?",[15,3168,3169],{},"Always (default) — перезапуск при любом exit code, для long-running сервисов. OnFailure — перезапуск только при exit code != 0, для Jobs. Never — без перезапуска, для одноразовых задач. Применяется ко всем контейнерам в pod-е. \"Restart\" — это пересоздание контейнера (данные на filesystem теряются без volume).",[18,3171],{},[21,3173,3175],{"id":3174},"задачи","Задачи",[26,3177,3179],{"id":3178},"задача-1-проектирование-pod-а-с-init-контейнерами","Задача 1. Проектирование pod-а с init-контейнерами",[15,3181,3182,3185],{},[34,3183,3184],{},"Уровень:"," Средняя",[15,3187,3188,3191],{},[34,3189,3190],{},"Что проверяет:"," понимание init-контейнеров, shared volumes, порядка запуска",[15,3193,3194,3197,3198,3201,3202,3205,3206,3209],{},[34,3195,3196],{},"Условие:"," Напиши манифест pod-а для Go-приложения, которое перед стартом должно: (1) дождаться доступности Redis на ",[119,3199,3200],{},"redis-svc:6379",", (2) загрузить конфигурацию из URL ",[119,3203,3204],{},"http:\u002F\u002Fconfig-server\u002Fapi\u002Fconfig"," в файл ",[119,3207,3208],{},"\u002Fetc\u002Fapp\u002Fconfig.json",". Основное приложение читает конфигурацию из этого файла.",[15,3211,3212],{},[34,3213,3214],{},"Решение:",[137,3216,3218],{"className":182,"code":3217,"language":184,"meta":145,"style":145},"apiVersion: v1\nkind: Pod\nmetadata:\n  name: my-go-app\n  labels:\n    app: my-go-app\nspec:\n  initContainers:\n  - name: wait-for-redis\n    image: busybox:1.36\n    command: ['sh', '-c', 'until nc -z redis-svc 6379; do echo \"waiting for redis...\"; sleep 2; done; echo \"redis is ready\"']\n  - name: load-config\n    image: curlimages\u002Fcurl:8.5.0\n    command: ['sh', '-c', 'curl -f -o \u002Fconfig\u002Fconfig.json http:\u002F\u002Fconfig-server\u002Fapi\u002Fconfig']\n    volumeMounts:\n    - name: app-config\n      mountPath: \u002Fconfig\n  containers:\n  - name: app\n    image: myregistry\u002Fmy-go-app:1.0\n    ports:\n    - containerPort: 8080\n    volumeMounts:\n    - name: app-config\n      mountPath: \u002Fetc\u002Fapp\n      readOnly: true\n    livenessProbe:\n      httpGet:\n        path: \u002Fhealthz\n        port: 8080\n      periodSeconds: 10\n      failureThreshold: 3\n    readinessProbe:\n      httpGet:\n        path: \u002Freadyz\n        port: 8080\n      periodSeconds: 5\n  volumes:\n  - name: app-config\n    emptyDir: {}\n",[119,3219,3220,3228,3236,3242,3251,3258,3267,3273,3279,3290,3298,3317,3328,3337,3356,3362,3373,3382,3388,3398,3406,3412,3422,3428,3438,3447,3457,3464,3471,3480,3489,3499,3509,3516,3522,3531,3539,3548,3554,3564],{"__ignoreMap":145},[188,3221,3222,3224,3226],{"class":190,"line":191},[188,3223,195],{"class":194},[188,3225,199],{"class":198},[188,3227,203],{"class":202},[188,3229,3230,3232,3234],{"class":190,"line":206},[188,3231,209],{"class":194},[188,3233,199],{"class":198},[188,3235,214],{"class":202},[188,3237,3238,3240],{"class":190,"line":217},[188,3239,220],{"class":194},[188,3241,223],{"class":198},[188,3243,3244,3246,3248],{"class":190,"line":226},[188,3245,229],{"class":194},[188,3247,199],{"class":198},[188,3249,3250],{"class":202},"my-go-app\n",[188,3252,3253,3256],{"class":190,"line":237},[188,3254,3255],{"class":194},"  labels",[188,3257,223],{"class":198},[188,3259,3260,3263,3265],{"class":190,"line":245},[188,3261,3262],{"class":194},"    app",[188,3264,199],{"class":198},[188,3266,3250],{"class":202},[188,3268,3269,3271],{"class":190,"line":253},[188,3270,240],{"class":194},[188,3272,223],{"class":198},[188,3274,3275,3277],{"class":190,"line":266},[188,3276,532],{"class":194},[188,3278,223],{"class":198},[188,3280,3281,3283,3285,3287],{"class":190,"line":277},[188,3282,256],{"class":198},[188,3284,259],{"class":194},[188,3286,199],{"class":198},[188,3288,3289],{"class":202},"wait-for-redis\n",[188,3291,3292,3294,3296],{"class":190,"line":285},[188,3293,269],{"class":194},[188,3295,199],{"class":198},[188,3297,554],{"class":202},[188,3299,3300,3302,3304,3306,3308,3310,3312,3315],{"class":190,"line":593},[188,3301,559],{"class":194},[188,3303,562],{"class":198},[188,3305,565],{"class":202},[188,3307,568],{"class":198},[188,3309,571],{"class":202},[188,3311,568],{"class":198},[188,3313,3314],{"class":202},"'until nc -z redis-svc 6379; do echo \"waiting for redis...\"; sleep 2; done; echo \"redis is ready\"'",[188,3316,579],{"class":198},[188,3318,3319,3321,3323,3325],{"class":190,"line":603},[188,3320,256],{"class":198},[188,3322,259],{"class":194},[188,3324,199],{"class":198},[188,3326,3327],{"class":202},"load-config\n",[188,3329,3330,3332,3334],{"class":190,"line":611},[188,3331,269],{"class":194},[188,3333,199],{"class":198},[188,3335,3336],{"class":202},"curlimages\u002Fcurl:8.5.0\n",[188,3338,3339,3341,3343,3345,3347,3349,3351,3354],{"class":190,"line":623},[188,3340,559],{"class":194},[188,3342,562],{"class":198},[188,3344,565],{"class":202},[188,3346,568],{"class":198},[188,3348,571],{"class":202},[188,3350,568],{"class":198},[188,3352,3353],{"class":202},"'curl -f -o \u002Fconfig\u002Fconfig.json http:\u002F\u002Fconfig-server\u002Fapi\u002Fconfig'",[188,3355,579],{"class":198},[188,3357,3358,3360],{"class":190,"line":631},[188,3359,862],{"class":194},[188,3361,223],{"class":198},[188,3363,3364,3366,3368,3370],{"class":190,"line":639},[188,3365,288],{"class":198},[188,3367,259],{"class":194},[188,3369,199],{"class":198},[188,3371,3372],{"class":202},"app-config\n",[188,3374,3375,3377,3379],{"class":190,"line":650},[188,3376,880],{"class":194},[188,3378,199],{"class":198},[188,3380,3381],{"class":202},"\u002Fconfig\n",[188,3383,3384,3386],{"class":190,"line":661},[188,3385,248],{"class":194},[188,3387,223],{"class":198},[188,3389,3390,3392,3394,3396],{"class":190,"line":668},[188,3391,256],{"class":198},[188,3393,259],{"class":194},[188,3395,199],{"class":198},[188,3397,677],{"class":202},[188,3399,3400,3402,3404],{"class":190,"line":680},[188,3401,269],{"class":194},[188,3403,199],{"class":198},[188,3405,687],{"class":202},[188,3407,3408,3410],{"class":190,"line":690},[188,3409,280],{"class":194},[188,3411,223],{"class":198},[188,3413,3414,3416,3418,3420],{"class":190,"line":697},[188,3415,288],{"class":198},[188,3417,291],{"class":194},[188,3419,199],{"class":198},[188,3421,706],{"class":296},[188,3423,3424,3426],{"class":190,"line":963},[188,3425,862],{"class":194},[188,3427,223],{"class":198},[188,3429,3430,3432,3434,3436],{"class":190,"line":974},[188,3431,288],{"class":198},[188,3433,259],{"class":194},[188,3435,199],{"class":198},[188,3437,3372],{"class":202},[188,3439,3440,3442,3444],{"class":190,"line":981},[188,3441,880],{"class":194},[188,3443,199],{"class":198},[188,3445,3446],{"class":202},"\u002Fetc\u002Fapp\n",[188,3448,3449,3452,3454],{"class":190,"line":992},[188,3450,3451],{"class":194},"      readOnly",[188,3453,199],{"class":198},[188,3455,3456],{"class":296},"true\n",[188,3458,3459,3462],{"class":190,"line":1001},[188,3460,3461],{"class":194},"    livenessProbe",[188,3463,223],{"class":198},[188,3465,3466,3469],{"class":190,"line":1009},[188,3467,3468],{"class":194},"      httpGet",[188,3470,223],{"class":198},[188,3472,3473,3476,3478],{"class":190,"line":1020},[188,3474,3475],{"class":194},"        path",[188,3477,199],{"class":198},[188,3479,1432],{"class":202},[188,3481,3482,3485,3487],{"class":190,"line":2581},[188,3483,3484],{"class":194},"        port",[188,3486,199],{"class":198},[188,3488,706],{"class":296},[188,3490,3491,3494,3496],{"class":190,"line":2587},[188,3492,3493],{"class":194},"      periodSeconds",[188,3495,199],{"class":198},[188,3497,3498],{"class":296},"10\n",[188,3500,3501,3504,3506],{"class":190,"line":2619},[188,3502,3503],{"class":194},"      failureThreshold",[188,3505,199],{"class":198},[188,3507,3508],{"class":296},"3\n",[188,3510,3511,3514],{"class":190,"line":2631},[188,3512,3513],{"class":194},"    readinessProbe",[188,3515,223],{"class":198},[188,3517,3518,3520],{"class":190,"line":2636},[188,3519,3468],{"class":194},[188,3521,223],{"class":198},[188,3523,3524,3526,3528],{"class":190,"line":2662},[188,3525,3475],{"class":194},[188,3527,199],{"class":198},[188,3529,3530],{"class":202},"\u002Freadyz\n",[188,3532,3533,3535,3537],{"class":190,"line":2681},[188,3534,3484],{"class":194},[188,3536,199],{"class":198},[188,3538,706],{"class":296},[188,3540,3541,3543,3545],{"class":190,"line":2687},[188,3542,3493],{"class":194},[188,3544,199],{"class":198},[188,3546,3547],{"class":296},"5\n",[188,3549,3550,3552],{"class":190,"line":2692},[188,3551,1004],{"class":194},[188,3553,223],{"class":198},[188,3555,3556,3558,3560,3562],{"class":190,"line":2706},[188,3557,256],{"class":198},[188,3559,259],{"class":194},[188,3561,199],{"class":198},[188,3563,3372],{"class":202},[188,3565,3567,3569],{"class":190,"line":3566},40,[188,3568,1023],{"class":194},[188,3570,1026],{"class":198},[15,3572,3573,3574,3577],{},"Порядок: wait-for-redis (ждёт TCP-подключения к Redis) -> load-config (скачивает JSON в shared volume) -> app (читает конфиг из \u002Fetc\u002Fapp\u002Fconfig.json). Shared volume ",[119,3575,3576],{},"app-config"," связывает init-контейнер и основной контейнер.",[26,3579,3581],{"id":3580},"задача-2-настройка-probes-для-go-сервиса","Задача 2. Настройка probes для Go-сервиса",[15,3583,3584,3185],{},[34,3585,3184],{},[15,3587,3588,3590],{},[34,3589,3190],{}," выбор типов probes и правильная конфигурация",[15,3592,3593,3595,3596,1372,3598,3601],{},[34,3594,3196],{}," У тебя есть Go HTTP-сервис, который при старте загружает данные из PostgreSQL в in-memory кэш (занимает до 60 секунд). После загрузки сервис отвечает на ",[119,3597,1782],{},[119,3599,3600],{},"\u002Freadyz",". Напиши секцию probes в манифесте, учитывая: (1) медленный старт, (2) быструю реакцию на зависание, (3) временную недоступность не должна приводить к рестарту.",[15,3603,3604],{},[34,3605,3214],{},[137,3607,3609],{"className":182,"code":3608,"language":184,"meta":145,"style":145},"containers:\n- name: cache-service\n  image: myregistry\u002Fcache-service:1.0\n  ports:\n  - containerPort: 8080\n  startupProbe:\n    httpGet:\n      path: \u002Fhealthz\n      port: 8080\n    periodSeconds: 5\n    failureThreshold: 15           # до 75 секунд на старт (5 * 15)\n  livenessProbe:\n    httpGet:\n      path: \u002Fhealthz\n      port: 8080\n    periodSeconds: 5\n    failureThreshold: 2            # 2 фейла (10s) -> restart\n    timeoutSeconds: 2\n  readinessProbe:\n    httpGet:\n      path: \u002Freadyz\n      port: 8080\n    periodSeconds: 3\n    failureThreshold: 2\n    successThreshold: 2            # 2 успеха подряд, чтобы вернуть в endpoints\n    timeoutSeconds: 2\n",[119,3610,3611,3617,3629,3639,3646,3656,3663,3669,3677,3685,3694,3706,3713,3719,3727,3735,3743,3754,3764,3771,3777,3785,3793,3801,3809,3821],{"__ignoreMap":145},[188,3612,3613,3615],{"class":190,"line":191},[188,3614,716],{"class":194},[188,3616,223],{"class":198},[188,3618,3619,3622,3624,3626],{"class":190,"line":206},[188,3620,3621],{"class":198},"- ",[188,3623,259],{"class":194},[188,3625,199],{"class":198},[188,3627,3628],{"class":202},"cache-service\n",[188,3630,3631,3634,3636],{"class":190,"line":217},[188,3632,3633],{"class":194},"  image",[188,3635,199],{"class":198},[188,3637,3638],{"class":202},"myregistry\u002Fcache-service:1.0\n",[188,3640,3641,3644],{"class":190,"line":226},[188,3642,3643],{"class":194},"  ports",[188,3645,223],{"class":198},[188,3647,3648,3650,3652,3654],{"class":190,"line":237},[188,3649,256],{"class":198},[188,3651,291],{"class":194},[188,3653,199],{"class":198},[188,3655,706],{"class":296},[188,3657,3658,3661],{"class":190,"line":245},[188,3659,3660],{"class":194},"  startupProbe",[188,3662,223],{"class":198},[188,3664,3665,3667],{"class":190,"line":253},[188,3666,2010],{"class":194},[188,3668,223],{"class":198},[188,3670,3671,3673,3675],{"class":190,"line":266},[188,3672,2017],{"class":194},[188,3674,199],{"class":198},[188,3676,1432],{"class":202},[188,3678,3679,3681,3683],{"class":190,"line":277},[188,3680,2027],{"class":194},[188,3682,199],{"class":198},[188,3684,706],{"class":296},[188,3686,3687,3690,3692],{"class":190,"line":285},[188,3688,3689],{"class":194},"    periodSeconds",[188,3691,199],{"class":198},[188,3693,3547],{"class":296},[188,3695,3696,3699,3701,3703],{"class":190,"line":593},[188,3697,3698],{"class":194},"    failureThreshold",[188,3700,199],{"class":198},[188,3702,2610],{"class":296},[188,3704,3705],{"class":300},"           # до 75 секунд на старт (5 * 15)\n",[188,3707,3708,3711],{"class":190,"line":603},[188,3709,3710],{"class":194},"  livenessProbe",[188,3712,223],{"class":198},[188,3714,3715,3717],{"class":190,"line":611},[188,3716,2010],{"class":194},[188,3718,223],{"class":198},[188,3720,3721,3723,3725],{"class":190,"line":623},[188,3722,2017],{"class":194},[188,3724,199],{"class":198},[188,3726,1432],{"class":202},[188,3728,3729,3731,3733],{"class":190,"line":631},[188,3730,2027],{"class":194},[188,3732,199],{"class":198},[188,3734,706],{"class":296},[188,3736,3737,3739,3741],{"class":190,"line":639},[188,3738,3689],{"class":194},[188,3740,199],{"class":198},[188,3742,3547],{"class":296},[188,3744,3745,3747,3749,3751],{"class":190,"line":650},[188,3746,3698],{"class":194},[188,3748,199],{"class":198},[188,3750,1477],{"class":296},[188,3752,3753],{"class":300},"            # 2 фейла (10s) -> restart\n",[188,3755,3756,3759,3761],{"class":190,"line":661},[188,3757,3758],{"class":194},"    timeoutSeconds",[188,3760,199],{"class":198},[188,3762,3763],{"class":296},"2\n",[188,3765,3766,3769],{"class":190,"line":668},[188,3767,3768],{"class":194},"  readinessProbe",[188,3770,223],{"class":198},[188,3772,3773,3775],{"class":190,"line":680},[188,3774,2010],{"class":194},[188,3776,223],{"class":198},[188,3778,3779,3781,3783],{"class":190,"line":690},[188,3780,2017],{"class":194},[188,3782,199],{"class":198},[188,3784,3530],{"class":202},[188,3786,3787,3789,3791],{"class":190,"line":697},[188,3788,2027],{"class":194},[188,3790,199],{"class":198},[188,3792,706],{"class":296},[188,3794,3795,3797,3799],{"class":190,"line":963},[188,3796,3689],{"class":194},[188,3798,199],{"class":198},[188,3800,3508],{"class":296},[188,3802,3803,3805,3807],{"class":190,"line":974},[188,3804,3698],{"class":194},[188,3806,199],{"class":198},[188,3808,3763],{"class":296},[188,3810,3811,3814,3816,3818],{"class":190,"line":981},[188,3812,3813],{"class":194},"    successThreshold",[188,3815,199],{"class":198},[188,3817,1477],{"class":296},[188,3819,3820],{"class":300},"            # 2 успеха подряд, чтобы вернуть в endpoints\n",[188,3822,3823,3825,3827],{"class":190,"line":992},[188,3824,3758],{"class":194},[188,3826,199],{"class":198},[188,3828,3763],{"class":296},[15,3830,3831,3832,3834],{},"startupProbe даёт до 75 секунд на загрузку кэша — liveness не запускается пока старт не завершён. livenessProbe с failureThreshold: 2 быстро обнаруживает зависание (10 секунд). readinessProbe на отдельном эндпоинте ",[119,3833,3600],{}," — если кэш перезагружается или сервис временно перегружен, pod убирается из endpoints, но не перезапускается. successThreshold: 2 предотвращает flapping (попеременное добавление\u002Fудаление из endpoints).",[26,3836,3838],{"id":3837},"задача-3-диагностика-crashloopbackoff","Задача 3. Диагностика CrashLoopBackOff",[15,3840,3841,3185],{},[34,3842,3184],{},[15,3844,3845,3847],{},[34,3846,3190],{}," практические навыки отладки pod-ов",[15,3849,3850,3852],{},[34,3851,3196],{}," После деплоя Go-приложения pod показывает статус CrashLoopBackOff. Опиши пошагово процесс диагностики: какие команды kubectl ты выполнишь и что будешь искать в выводе каждой команды. Назови 5 возможных причин CrashLoopBackOff.",[15,3854,3855],{},[34,3856,3857],{},"Ответ:",[15,3859,3860],{},"Шаги диагностики:",[137,3862,3864],{"className":1253,"code":3863,"language":1255,"meta":145,"style":145},"# 1. Смотрим текущий статус и количество рестартов\nkubectl get pod \u003Cname> -o wide\n\n# 2. Смотрим events — причины рестартов, ошибки scheduling\nkubectl describe pod \u003Cname>\n# Ищем: exit code, reason (OOMKilled, Error), events (FailedMount, FailedScheduling)\n\n# 3. Логи текущего (падающего) контейнера\nkubectl logs \u003Cname>\n# Ищем: panic, fatal error, ошибки подключения, невалидный конфиг\n\n# 4. Логи предыдущего контейнера (до рестарта)\nkubectl logs \u003Cname> --previous\n# Часто текущий контейнер ещё не успел ничего записать\n\n# 5. Проверяем exit code\nkubectl get pod \u003Cname> -o jsonpath='{.status.containerStatuses[0].lastState}'\n# 137 = OOMKilled, 1 = ошибка приложения, 2 = bash error\n",[119,3865,3866,3871,3896,3900,3905,3923,3928,3932,3937,3952,3957,3961,3966,3983,3988,3992,3997,4018],{"__ignoreMap":145},[188,3867,3868],{"class":190,"line":191},[188,3869,3870],{"class":300},"# 1. Смотрим текущий статус и количество рестартов\n",[188,3872,3873,3875,3877,3879,3882,3885,3888,3891,3893],{"class":190,"line":206},[188,3874,1268],{"class":1267},[188,3876,1271],{"class":202},[188,3878,1274],{"class":202},[188,3880,3881],{"class":1286}," \u003C",[188,3883,3884],{"class":202},"nam",[188,3886,3887],{"class":198},"e",[188,3889,3890],{"class":1286},">",[188,3892,1280],{"class":296},[188,3894,3895],{"class":202}," wide\n",[188,3897,3898],{"class":190,"line":217},[188,3899,2299],{"emptyLinePlaceholder":2298},[188,3901,3902],{"class":190,"line":226},[188,3903,3904],{"class":300},"# 2. Смотрим events — причины рестартов, ошибки scheduling\n",[188,3906,3907,3909,3912,3914,3916,3918,3920],{"class":190,"line":237},[188,3908,1268],{"class":1267},[188,3910,3911],{"class":202}," describe",[188,3913,1274],{"class":202},[188,3915,3881],{"class":1286},[188,3917,3884],{"class":202},[188,3919,3887],{"class":198},[188,3921,3922],{"class":1286},">\n",[188,3924,3925],{"class":190,"line":245},[188,3926,3927],{"class":300},"# Ищем: exit code, reason (OOMKilled, Error), events (FailedMount, FailedScheduling)\n",[188,3929,3930],{"class":190,"line":253},[188,3931,2299],{"emptyLinePlaceholder":2298},[188,3933,3934],{"class":190,"line":266},[188,3935,3936],{"class":300},"# 3. Логи текущего (падающего) контейнера\n",[188,3938,3939,3941,3944,3946,3948,3950],{"class":190,"line":277},[188,3940,1268],{"class":1267},[188,3942,3943],{"class":202}," logs",[188,3945,3881],{"class":1286},[188,3947,3884],{"class":202},[188,3949,3887],{"class":198},[188,3951,3922],{"class":1286},[188,3953,3954],{"class":190,"line":285},[188,3955,3956],{"class":300},"# Ищем: panic, fatal error, ошибки подключения, невалидный конфиг\n",[188,3958,3959],{"class":190,"line":593},[188,3960,2299],{"emptyLinePlaceholder":2298},[188,3962,3963],{"class":190,"line":603},[188,3964,3965],{"class":300},"# 4. Логи предыдущего контейнера (до рестарта)\n",[188,3967,3968,3970,3972,3974,3976,3978,3980],{"class":190,"line":611},[188,3969,1268],{"class":1267},[188,3971,3943],{"class":202},[188,3973,3881],{"class":1286},[188,3975,3884],{"class":202},[188,3977,3887],{"class":198},[188,3979,3890],{"class":1286},[188,3981,3982],{"class":296}," --previous\n",[188,3984,3985],{"class":190,"line":623},[188,3986,3987],{"class":300},"# Часто текущий контейнер ещё не успел ничего записать\n",[188,3989,3990],{"class":190,"line":631},[188,3991,2299],{"emptyLinePlaceholder":2298},[188,3993,3994],{"class":190,"line":639},[188,3995,3996],{"class":300},"# 5. Проверяем exit code\n",[188,3998,3999,4001,4003,4005,4007,4009,4011,4013,4015],{"class":190,"line":650},[188,4000,1268],{"class":1267},[188,4002,1271],{"class":202},[188,4004,1274],{"class":202},[188,4006,3881],{"class":1286},[188,4008,3884],{"class":202},[188,4010,3887],{"class":198},[188,4012,3890],{"class":1286},[188,4014,1280],{"class":296},[188,4016,4017],{"class":202}," jsonpath='{.status.containerStatuses[0].lastState}'\n",[188,4019,4020],{"class":190,"line":661},[188,4021,4022],{"class":300},"# 137 = OOMKilled, 1 = ошибка приложения, 2 = bash error\n",[15,4024,4025],{},"Пять возможных причин: (1) OOMKilled (exit code 137) — приложение потребляет больше памяти, чем указано в limits; (2) неверная конфигурация — переменные окружения отсутствуют или содержат неправильные значения; (3) недоступность зависимости — приложение падает при невозможности подключиться к БД (нужны retry и init-контейнеры); (4) ошибка в ENTRYPOINT\u002FCMD — бинарник не найден или не является исполняемым; (5) panic в приложении — необработанная ошибка при инициализации (nil pointer dereference, отсутствующий файл).",[18,4027],{},[21,4029,4031],{"id":4030},"интерактивная-практика","Интерактивная практика",[4033,4034,4036,4039,4056],"quiz",{"answer":1477,"id":4035,"xp":1451},"infra-pods-q1",[15,4037,4038],{},"Что происходит, когда readiness probe начинает падать, но liveness probe остаётся успешной?",[4040,4041,4042],"template",{"v-slot:options":145},[418,4043,4044,4047,4050,4053],{},[421,4045,4046],{},"Kubernetes немедленно перезапускает контейнер",[421,4048,4049],{},"Pod убирается из endpoints Service, но контейнер продолжает работать",[421,4051,4052],{},"Pod удаляется навсегда и больше не создаётся",[421,4054,4055],{},"Scheduler переносит pod на другую ноду",[4040,4057,4058],{"v-slot:explanation":145},[15,4059,4060],{},"Readiness отвечает за приём трафика. Если она падает, pod временно исключается из балансировки Service, но restart делает liveness probe, а не readiness.",[4062,4063,4066,4069,4260],"predict",{"answer":4064,"id":4065,"xp":2610},"restart\\nremove-from-service\\nwait-startup","infra-pods-p1",[15,4067,4068],{},"Что выведет программа?",[4040,4070,4071],{"v-slot:code":145},[137,4072,4074],{"className":2280,"code":4073,"language":2282,"meta":145,"style":145},"package main\n\nimport \"fmt\"\n\nfunc probeAction(probe string) string {\n    switch probe {\n    case \"liveness\":\n        return \"restart\"\n    case \"readiness\":\n        return \"remove-from-service\"\n    default:\n        return \"wait-startup\"\n    }\n}\n\nfunc main() {\n    fmt.Println(probeAction(\"liveness\"))\n    fmt.Println(probeAction(\"readiness\"))\n    fmt.Println(probeAction(\"startup\"))\n}\n",[119,4075,4076,4082,4086,4098,4102,4126,4134,4144,4152,4161,4168,4175,4182,4186,4190,4194,4202,4222,4239,4256],{"__ignoreMap":145},[188,4077,4078,4080],{"class":190,"line":191},[188,4079,2290],{"class":1286},[188,4081,2293],{"class":1267},[188,4083,4084],{"class":190,"line":206},[188,4085,2299],{"emptyLinePlaceholder":2298},[188,4087,4088,4090,4093,4096],{"class":190,"line":217},[188,4089,2304],{"class":1286},[188,4091,4092],{"class":202}," \"",[188,4094,4095],{"class":1267},"fmt",[188,4097,2318],{"class":202},[188,4099,4100],{"class":190,"line":226},[188,4101,2299],{"emptyLinePlaceholder":2298},[188,4103,4104,4106,4109,4111,4115,4118,4121,4124],{"class":190,"line":237},[188,4105,2386],{"class":1286},[188,4107,4108],{"class":1267}," probeAction",[188,4110,2476],{"class":198},[188,4112,4114],{"class":4113},"s9osk","probe",[188,4116,4117],{"class":1286}," string",[188,4119,4120],{"class":198},") ",[188,4122,4123],{"class":1286},"string",[188,4125,2659],{"class":198},[188,4127,4128,4131],{"class":190,"line":245},[188,4129,4130],{"class":1286},"    switch",[188,4132,4133],{"class":198}," probe {\n",[188,4135,4136,4139,4142],{"class":190,"line":253},[188,4137,4138],{"class":1286},"    case",[188,4140,4141],{"class":202}," \"liveness\"",[188,4143,223],{"class":198},[188,4145,4146,4149],{"class":190,"line":266},[188,4147,4148],{"class":1286},"        return",[188,4150,4151],{"class":202}," \"restart\"\n",[188,4153,4154,4156,4159],{"class":190,"line":277},[188,4155,4138],{"class":1286},[188,4157,4158],{"class":202}," \"readiness\"",[188,4160,223],{"class":198},[188,4162,4163,4165],{"class":190,"line":285},[188,4164,4148],{"class":1286},[188,4166,4167],{"class":202}," \"remove-from-service\"\n",[188,4169,4170,4173],{"class":190,"line":593},[188,4171,4172],{"class":1286},"    default",[188,4174,223],{"class":198},[188,4176,4177,4179],{"class":190,"line":603},[188,4178,4148],{"class":1286},[188,4180,4181],{"class":202}," \"wait-startup\"\n",[188,4183,4184],{"class":190,"line":611},[188,4185,2684],{"class":198},[188,4187,4188],{"class":190,"line":623},[188,4189,2421],{"class":198},[188,4191,4192],{"class":190,"line":631},[188,4193,2299],{"emptyLinePlaceholder":2298},[188,4195,4196,4198,4200],{"class":190,"line":639},[188,4197,2386],{"class":1286},[188,4199,2389],{"class":1267},[188,4201,2392],{"class":198},[188,4203,4204,4207,4209,4211,4214,4216,4219],{"class":190,"line":650},[188,4205,4206],{"class":198},"    fmt.",[188,4208,2567],{"class":1267},[188,4210,2476],{"class":198},[188,4212,4213],{"class":1267},"probeAction",[188,4215,2476],{"class":198},[188,4217,4218],{"class":202},"\"liveness\"",[188,4220,4221],{"class":198},"))\n",[188,4223,4224,4226,4228,4230,4232,4234,4237],{"class":190,"line":661},[188,4225,4206],{"class":198},[188,4227,2567],{"class":1267},[188,4229,2476],{"class":198},[188,4231,4213],{"class":1267},[188,4233,2476],{"class":198},[188,4235,4236],{"class":202},"\"readiness\"",[188,4238,4221],{"class":198},[188,4240,4241,4243,4245,4247,4249,4251,4254],{"class":190,"line":668},[188,4242,4206],{"class":198},[188,4244,2567],{"class":1267},[188,4246,2476],{"class":198},[188,4248,4213],{"class":1267},[188,4250,2476],{"class":198},[188,4252,4253],{"class":202},"\"startup\"",[188,4255,4221],{"class":198},[188,4257,4258],{"class":190,"line":680},[188,4259,2421],{"class":198},[4040,4261,4262],{"v-slot:hint":145},[15,4263,4264],{},"Liveness лечит зависший процесс, readiness управляет трафиком, startup даёт приложению время на долгий старт.",[4266,4267,4271,4288,4415],"code-task",{"expected":4268,"id":4269,"xp":4270},"OOMKilled\\nError\\nUnknown","infra-pods-ct1","20",[15,4272,4273,4274,4277,4278,4280,4281,4284,4285,4287],{},"Реализуй ",[119,4275,4276],{},"ExitReason",": код ",[119,4279,2752],{}," означает ",[119,4282,4283],{},"OOMKilled",", код ",[119,4286,1503],{}," — обычную ошибку приложения, остальные причины пока считай неизвестными.",[4040,4289,4290],{"v-slot:template":145},[137,4291,4293],{"className":2280,"code":4292,"language":2282,"meta":145,"style":145},"package main\n\nimport \"fmt\"\n\nfunc ExitReason(code int) string {\n    return \"todo\"\n}\n\nfunc main() {\n    fmt.Println(ExitReason(137))\n    fmt.Println(ExitReason(1))\n    fmt.Println(ExitReason(2))\n}\n",[119,4294,4295,4301,4305,4315,4319,4339,4347,4351,4355,4363,4379,4395,4411],{"__ignoreMap":145},[188,4296,4297,4299],{"class":190,"line":191},[188,4298,2290],{"class":1286},[188,4300,2293],{"class":1267},[188,4302,4303],{"class":190,"line":206},[188,4304,2299],{"emptyLinePlaceholder":2298},[188,4306,4307,4309,4311,4313],{"class":190,"line":217},[188,4308,2304],{"class":1286},[188,4310,4092],{"class":202},[188,4312,4095],{"class":1267},[188,4314,2318],{"class":202},[188,4316,4317],{"class":190,"line":226},[188,4318,2299],{"emptyLinePlaceholder":2298},[188,4320,4321,4323,4326,4328,4330,4333,4335,4337],{"class":190,"line":237},[188,4322,2386],{"class":1286},[188,4324,4325],{"class":1267}," ExitReason",[188,4327,2476],{"class":198},[188,4329,119],{"class":4113},[188,4331,4332],{"class":1286}," int",[188,4334,4120],{"class":198},[188,4336,4123],{"class":1286},[188,4338,2659],{"class":198},[188,4340,4341,4344],{"class":190,"line":245},[188,4342,4343],{"class":1286},"    return",[188,4345,4346],{"class":202}," \"todo\"\n",[188,4348,4349],{"class":190,"line":253},[188,4350,2421],{"class":198},[188,4352,4353],{"class":190,"line":266},[188,4354,2299],{"emptyLinePlaceholder":2298},[188,4356,4357,4359,4361],{"class":190,"line":277},[188,4358,2386],{"class":1286},[188,4360,2389],{"class":1267},[188,4362,2392],{"class":198},[188,4364,4365,4367,4369,4371,4373,4375,4377],{"class":190,"line":285},[188,4366,4206],{"class":198},[188,4368,2567],{"class":1267},[188,4370,2476],{"class":198},[188,4372,4276],{"class":1267},[188,4374,2476],{"class":198},[188,4376,2752],{"class":296},[188,4378,4221],{"class":198},[188,4380,4381,4383,4385,4387,4389,4391,4393],{"class":190,"line":593},[188,4382,4206],{"class":198},[188,4384,2567],{"class":1267},[188,4386,2476],{"class":198},[188,4388,4276],{"class":1267},[188,4390,2476],{"class":198},[188,4392,1503],{"class":296},[188,4394,4221],{"class":198},[188,4396,4397,4399,4401,4403,4405,4407,4409],{"class":190,"line":603},[188,4398,4206],{"class":198},[188,4400,2567],{"class":1267},[188,4402,2476],{"class":198},[188,4404,4276],{"class":1267},[188,4406,2476],{"class":198},[188,4408,1477],{"class":296},[188,4410,4221],{"class":198},[188,4412,4413],{"class":190,"line":611},[188,4414,2421],{"class":198},[4040,4416,4417],{"v-slot:hints":145},[418,4418,4419,4424,4429],{},[421,4420,4421,4423],{},[119,4422,2752],{}," часто означает, что процесс получил SIGKILL после превышения memory limit.",[421,4425,4426,4428],{},[119,4427,1503],{}," обычно говорит о неуспешном завершении приложения.",[421,4430,4431,4432,2409],{},"Для неизвестных кодов верни ",[119,4433,1135],{},[4435,4436,4437],"style",{},"html pre.shiki code .s4JwU, html code.shiki .s4JwU{--shiki-default:#85E89D}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}",{"title":145,"searchDepth":206,"depth":206,"links":4439},[4440,4445,4446,4451,4456,4463,4467,4471,4474,4475,4476,4481],{"id":23,"depth":206,"text":24,"children":4441},[4442,4443,4444],{"id":28,"depth":217,"text":29},{"id":40,"depth":217,"text":41},{"id":151,"depth":217,"text":152},{"id":178,"depth":206,"text":179},{"id":315,"depth":206,"text":316,"children":4447},[4448,4449,4450],{"id":319,"depth":217,"text":320},{"id":399,"depth":217,"text":400},{"id":709,"depth":217,"text":710},{"id":1048,"depth":206,"text":1049,"children":4452},[4453,4454,4455],{"id":1073,"depth":217,"text":1074},{"id":1206,"depth":217,"text":1207},{"id":1296,"depth":217,"text":1297},{"id":1385,"depth":206,"text":1386,"children":4457},[4458,4459,4460,4461,4462],{"id":1392,"depth":217,"text":1393},{"id":1518,"depth":217,"text":1519},{"id":1662,"depth":217,"text":1663},{"id":1734,"depth":217,"text":1735},{"id":1855,"depth":217,"text":1856},{"id":1910,"depth":206,"text":1911,"children":4464},[4465,4466],{"id":1932,"depth":217,"text":1933},{"id":2047,"depth":217,"text":2048},{"id":2191,"depth":206,"text":2192,"children":4468},[4469,4470],{"id":2209,"depth":217,"text":2210},{"id":2711,"depth":217,"text":2712},{"id":2770,"depth":206,"text":2771,"children":4472},[4473],{"id":2834,"depth":217,"text":2835},{"id":2918,"depth":206,"text":2919},{"id":3095,"depth":206,"text":3096},{"id":3174,"depth":206,"text":3175,"children":4477},[4478,4479,4480],{"id":3178,"depth":217,"text":3179},{"id":3580,"depth":217,"text":3581},{"id":3837,"depth":217,"text":3838},{"id":4030,"depth":206,"text":4031},1781022065196]