توضیح Finalizers در Kubernetes: چرا Namespaceها در وضعیت Terminating گیر می‌کنند

kubernetes devops debugging

مقدمه

تلاش برای حذف یک Namespace در Kubernetes و مشاهده اینکه به‌طور مداوم در وضعیت «Terminating» گیر کرده است، یکی از آزاردهنده‌ترین مشکلات تکراری در دنیای DevOps است. عامل اصلی معمولاً finalizers هستند — فیلدهای خاص metadata که تا تکمیل عملیات پاک‌سازی، از حذف منبع جلوگیری می‌کنند.

Finalizers در Kubernetes چیستند؟

یک finalizer به‌عنوان یک «لیست وظایف» برای controllerهای Kubernetes عمل می‌کند. قبل از اینکه Kubernetes API Server یک شیء را واقعاً از etcd (پایگاه داده کلاستر) حذف کند، لیست finalizers متصل به آن منبع را بررسی می‌کند.

هر ورودی finalizer نمایانگر یک controller است که مسئول عملیات پاک‌سازی قبل از اجازه حذف واقعی توسط Kubernetes API می‌باشد.

چرا Finalizers وجود دارند

Finalizers پاک‌سازی امن و قابل پیش‌بینی منابع را با جلوگیری از باقی ماندن منابع یتیم — مانند persistent volumes، رابط‌های شبکه، یا IAM roles — پس از حذف، ممکن می‌سازند.

موارد استفاده رایج شامل:

  • PersistentVolumeClaims (PVCs) – اطمینان از جدا شدن PersistentVolumes مرتبط قبل از حذف
  • Namespaces – تضمین حذف تمام منابع زیرمجموعه قبل از حذف namespace
  • Custom Resource Definitions (CRDs) – فعال‌سازی پاک‌سازی operator قبل از حذف نمونه
  • Service Controllers – یکپارچه‌سازی‌های ابری که حذف load balancer را مدیریت می‌کنند

نحوه عملکرد Finalizers

چرخه حیات این مراحل را دنبال می‌کند:

  1. دستور kubectl delete روی یک شیء اجرا می‌شود
  2. Kubernetes یک deletionTimestamp به شیء اضافه می‌کند
  3. Controllerهای مدیریت‌کننده finalizers، timestamp را شناسایی کرده و پاک‌سازی را آغاز می‌کنند
  4. پس از تکمیل پاک‌سازی، controller مربوطه finalizer خود را حذف می‌کند
  5. پس از خالی شدن لیست finalizers، Kubernetes شیء را حذف می‌کند

زمانی که مشکلات رخ می‌دهند

گاهی اوقات controllerها از کار می‌افتند، حذف می‌شوند یا دچار اختلال می‌شوند. وقتی این اتفاق رخ می‌دهد، Kubernetes به‌طور نامحدود منتظر پاک‌سازی‌ای می‌ماند که هرگز انجام نمی‌شود و منابع در وضعیت «Terminating» گیر می‌کنند.

علائم معمول:

  • منبع در وضعیت «Terminating» گیر کرده است
  • دستور kubectl delete هرگز تکمیل نمی‌شود
  • Finalizers همچنان در YAML شیء موجود هستند
  • لاگ‌های controller خطاها یا ارجاعات گم‌شده را نمایش می‌دهند

عیب‌یابی یک Namespace یا منبع گیرکرده

مرحله ۱: بررسی منبع

kubectl get ns my-namespace -o yaml

این دستور فیلد finalizers که مانع حذف شده را نمایان می‌کند.

مرحله ۲: شناسایی Finalizer گیرکرده

لاگ‌های controller مربوطه را بررسی کنید تا بفهمید کدام finalizer مانع حذف شده و چرا پاک‌سازی پیشرفت نمی‌کند.

مرحله ۳: حذف Finalizer

پس از اطمینان از اینکه حذف بی‌خطر است، منبع را patch کنید:

kubectl patch ns my-namespace -p '{"metadata":{"finalizers":[]}}' --type=merge

همچنین می‌توانید مستقیماً از طریق kubectl edit ns my-namespace ویرایش کرده و خطوط finalizer را حذف کنید.

هشدار مهم: finalizers را فقط پس از تأیید عدم نیاز به پاک‌سازی حذف کنید — در غیر این صورت ممکن است منابع ابری یتیم باقی بمانند.

مثال واقعی

فرض کنید یک namespace توسط AWS Load Balancer Controller مدیریت می‌شود. هنگام حذف مشاهده می‌شود:

metadata:
  finalizers:
  - service.kubernetes.io/load-balancer-cleanup

اگر controller در دسترس نباشد یا مجوزهای لازم را نداشته باشد، نمی‌تواند finalizer را حذف کند و namespace به‌طور دائم در حال terminating باقی می‌ماند.

راه‌حل: controller را ری‌استارت کنید یا مجوزها را اصلاح کنید؛ اگر موفق نشدید و مطمئن هستید هیچ منبعی باقی نمانده، finalizer را به‌صورت دستی حذف کنید.

بهترین شیوه‌ها

  1. از حذف دستی finalizer خودداری کنید مگر اینکه ضروری باشد — ابتدا مشکلات controller را برطرف کنید
  2. لاگ‌های controller را برای یافتن دلایل اصلی بررسی کنید
  3. توجه داشته باشید که برخی finalizers پاک‌سازی حیاتی انجام می‌دهند که از نشت منابع جلوگیری می‌کند
  4. در استفاده از اسکریپت‌های پاک‌سازی خودکار احتیاط کنید و حفاظ‌های ایمنی پیاده‌سازی کنید
  5. برای توسعه‌دهندگان CRD: finalizers را با مسئولیت ثبت کنید، پاک‌سازی را در منطق Reconcile انجام دهید و پس از موفقیت حذف کنید

نتیجه‌گیری

Finalizers مکانیزم‌های ظریف اما قدرتمند Kubernetes هستند که پاک‌سازی امن منابع را تضمین می‌کنند. آن‌ها «قراردادهای پاک‌سازی» بین controllerها و API server برقرار می‌کنند. وقتی controllerها دچار اختلال می‌شوند، منابع گیر می‌کنند — اما درک مکانیک finalizers، عیب‌یابی مطمئن و حذف ایمن را ممکن می‌سازد.

$ cat KUBERNETES .md
· 5 دقیقه مطالعه

اپ REDIS_PORT رو می‌خوند. Kubernetes قبلش مقدارش رو عوض کرده بود.

هر view که به cache دست می‌زد 500 برمی‌گردوند، ولی health check سبز بود. مقصر یه Service به اسم redis بود و enableServiceLinks؛ یه پیش‌فرض قدیمی Kubernetes از دوران Docker که متغیرهای محیطی‌ای تزریق می‌کنه که هیچ‌وقت نخواستی.

kubernetes devops debugging django
$ cat DNS .md
· 7 دقیقه مطالعه

یه رکورد DNS رو دوبار پاک کردم. بار سوم پرسیدم چرا.

یه endpoint عمومی توی سه روز دو بار قطع شد، و هر دو بار همون fix پنج‌دقیقه‌ای جواب داد: پاک کردن یه رکورد AAAA یتیم. باگ واقعی یه رکورد ownership توی DNS بود که هیچ‌وقت نمی‌تونه خودش رو صاحب بشه، دقیقاً روی apex یه zone دلگیت‌شده.

dns aws route53 kubernetes devops
$ cat KUBERNETES .md
· 7 دقیقه مطالعه

کلاستر جدید روی هر node تا ۱۱۰ تا pod می‌برد. Production روی ۵۸ گیر کرده بود.

همون instance type، نصف تراکم pod. بالا بردن max pods روی یه کلاستر EKS زنده یعنی: یه launch template که node group هیچ‌وقت نمی‌تونه بگیردش، یه تنظیم CNI که باید اول بشینه، و یه Terraform plan پر از تغییرهایی که هیچ‌کس سفارش نداده بود.

kubernetes aws eks terraform devops