← На главную

Утечку памяти в kubelet на Kubernetes 1.36 исправили: с 974 до 110 MiB

01.07.2026 02:14 · hackernews

Инженер заметил утечку памяти на маленьком тестовом кластере Kubernetes, который он недавно обновил до v1.36 на DigitalOcean DOKS. Кластер был дешёвым — всего 2 GiB RAM, но эта скупость сыграла на руку: нехватка памяти сразу выявила проблему, которая на более мощной машине проявилась бы гораздо позже.

Сначала подозрение пало на приложения — они перезапускались, но kubectl top pods не показывал аномалий. Инженер зашёл на саму ноду, запустил htop и быстро понял: память жрёт сам процесс kubelet. systemctl restart kubelet временно решил проблему, но утечка явно оставалась.

Тогда он снял heap-профиль через Go-пакет pprof. Данные по количеству объектов и по занятой памяти показали одно и то же: почти миллион контекстов, которые забили 92% кучи и добрую половину всей памяти. В стеке вызовов фигурировали context.(*cancelCtx).propagateCancel, context.WithDeadline, context.WithTimeout, а из кода Kubernetes — Kubelet.SyncPod, volumeManager.WaitForAttachAndMount и особенно podWorkers.startPodSync.

Автор никогда раньше не смотрел в код kubelet, но сразу заподозрил неладное. Он воспользовался ИИ-инструментом Codex, который мгновенно нашёл регрессию — изменение в Kubernetes 1.36 от 19 февраля 2026 года. Всё оказалось до банального просто: в startPodSync заменили код, который создавал новый контекст только при необходимости, на безусловное создание нового контекста через context.WithCancel(parentCtx). При этом новый cancelFn просто перезаписывал старый, не вызывая его. Go-документация прямо предупреждает: если не вызвать CancelFunc, родительский контекст продолжает держать ссылку на дочерний. Так на каждую синхронизацию Pod появлялся новый утечкающий контекст.

Инженер открыл issue, мейнтейнеры быстро приняли его как регрессию. Патч упростили из-за проблем с prober workers (они неправильно использовали контексты), но в итоге изменения вкатили в master (в v1.37) и сделали backport для релизной ветки v1.36. После исправления kubelet стал потреблять 110 MiB вместо 974 MiB.

Читать оригинал →