Fix Kubernetes Namespace Bị Kẹt ở Trạng Thái Terminating (Error from server: namespaces is being deleted)

intermediate☸️ Kubernetes2026-03-18| Kubernetes 1.18+, kubectl, mọi cloud provider (EKS, GKE, AKS) hoặc cluster tự host

Error Message

Error from server: namespaces "my-namespace" is being deleted
#kubernetes#namespace#terminating#finalizer#kubectl

Vấn đề

Bạn chạy kubectl delete namespace my-namespace và namespace cứ... treo mãi. Trạng thái hiển thị Terminating. Bạn chờ. Mười phút sau vẫn còn đó. Khi thử thao tác với nó:

Error from server: namespaces "my-namespace" is being deleted

Bạn không thể tạo lại, không thể deploy vào, không thể động vào bằng bất kỳ cách nào. Hỏi bất kỳ admin Kubernetes nào và họ đều đã gặp tình huống này — thường vào đúng lúc tệ nhất, như giữa quá trình deploy hoặc ngay trước khi demo.

Nguyên nhân

Kubernetes dùng finalizer để kiểm soát thứ tự xóa. Khi bạn xóa một namespace, Kubernetes đặt timestamp xóa và bắt đầu dọn dẹp mọi thứ bên trong. Namespace sẽ không thực sự biến mất cho đến khi mọi finalizer được xử lý xong.

Đây là những gì thường cản trở quá trình này:

  • Một custom resource (CRD) vẫn còn tồn tại nhưng controller của nó đã bị xóa — nên finalizer không bao giờ chạy
  • Một admission webhook không thể truy cập và âm thầm chặn việc xóa
  • Một persistent volume bị kẹt trong vòng lặp dọn dẹp
  • Một operator bên thứ ba (cert-manager, Istio, Prometheus Operator) đã cài finalizer mà không bao giờ được gỡ bỏ

Bắt đầu bằng cách kiểm tra trực tiếp các finalizer của namespace:

kubectl get namespace my-namespace -o yaml

Tìm trường finalizers trong phần spec. Một namespace bị kẹt thường trông như thế này:

spec:
  finalizers:
  - kubernetes
  - some-operator.io/cleanup

Cũng hãy quét các resource bị kẹt bên trong namespace:

kubectl api-resources --verbs=list --namespaced -o name \
  | xargs -I{} kubectl get {} -n my-namespace --ignore-not-found 2>/dev/null

Cách Sửa Nhanh: Xóa Finalizer bằng kubectl patch

Xóa các finalizer và Kubernetes sẽ hoàn tất việc xóa ngay lập tức. Thử cách này trước:

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

Nếu namespace đã vào sâu trạng thái đang xóa, lệnh đó có thể thất bại. Hãy dùng phương pháp API proxy thay thế — cách này bỏ qua vấn đề hoàn toàn.

Phương pháp 2: API Proxy (đáng tin cậy nhất)

Khởi động proxy ở một terminal:

kubectl proxy &

Ở terminal thứ hai, xuất spec của namespace ra file:

kubectl get namespace my-namespace -o json > /tmp/ns.json

Mở /tmp/ns.json, tìm block spec và thay nội dung bằng:

"spec": {
  "finalizers": []
}

Đẩy thay đổi qua endpoint finalize:

curl -s -o /dev/null -w "%{http_code}" \
  -X PUT \
  -H 'Content-Type: application/json' \
  --data-binary @/tmp/ns.json \
  http://127.0.0.1:8001/api/v1/namespaces/my-namespace/finalize

HTTP 200 nghĩa là thành công. Namespace sẽ biến mất trong vòng 5–10 giây.

Tắt proxy khi xong:

kill %1

Từng Bước: Quy Trình Dọn Dẹp Đầy Đủ

Bước 1 — Kiểm tra xem cái gì đang bị kẹt

# Trạng thái và điều kiện của namespace
kubectl describe namespace my-namespace

# Các sự kiện gần đây sắp xếp theo thời gian
kubectl get events -n my-namespace --sort-by='.lastTimestamp'

# Tất cả mọi thứ đang chạy trong namespace
kubectl get all -n my-namespace

Bước 2 — Thử dọn dẹp resource thủ công trước

Xóa cưỡng bức namespace là biện pháp cuối cùng. Hãy dọn sạch từng resource bị kẹt riêng lẻ trước — cách này an toàn hơn và tránh để lại các object mồ côi.

# Xóa cưỡng bức một pod bị kẹt (bỏ qua thời gian grace period 30 giây)
kubectl delete pod stuck-pod-name -n my-namespace --grace-period=0 --force

# Xóa finalizer khỏi một resource cụ thể
kubectl patch pod stuck-pod-name -n my-namespace \
  -p '{"metadata":{"finalizers":null}}' \
  --type=merge

Có custom resource? Tìm chúng trước:

kubectl get crds | grep my-namespace

Patch finalizer của chúng theo cách tương tự:

kubectl patch myresource resource-name -n my-namespace \
  -p '{"metadata":{"finalizers":[]}}' \
  --type=merge

Bước 3 — Xóa cưỡng bức finalizer của namespace

Sau khi đã dọn sạch các resource bị kẹt — hoặc nếu không thể dọn — dùng phương pháp API proxy ở trên để xóa finalizer ở cấp namespace.

Bước 4 — Xác nhận kết quả

# Nên trả về NotFound nếu đã xóa hoàn toàn (đó là kết quả tốt)
kubectl get namespace my-namespace

# Kết quả mong đợi:
# Error from server (NotFound): namespaces "my-namespace" not found

# Kiểm tra thêm để chắc chắn đã biến mất khỏi danh sách
kubectl get namespaces | grep my-namespace

Cần tạo lại ngay?

kubectl create namespace my-namespace

Phòng Tránh Trong Tương Lai

Chín trong mười trường hợp, namespace bị kẹt là do một operator đã cài finalizer rồi bị xóa mà không dọn dẹp. Một vài thói quen giúp phòng tránh điều này:

  • Gỡ cài đặt operator trước khi xóa namespace. Với operator quản lý qua Helm, helm uninstall tự động xử lý dọn dẹp. Với cài đặt thủ công, xem tài liệu operator để biết quy trình gỡ cài đặt.
  • Kiểm tra admission webhook. Webhook khớp với namespace của bạn có thể âm thầm chặn việc xóa. Chạy kubectl get validatingwebhookconfigurations,mutatingwebhookconfigurations và tìm bất kỳ cái nào nhắm vào namespace bạn đang xóa.
  • Thêm script pre-delete vào CI/CD pipeline. Trước khi xóa namespace trong tự động hóa, chạy script patch out các finalizer đã biết. Phát hiện vấn đề trước khi nó trở thành sự cố lúc 2 giờ sáng.
  • Xóa các instance CRD trước khi gỡ operator. Gỡ cài đặt cert-manager hoặc Istio trong khi các object CRD của chúng vẫn còn trong namespace sẽ để lại các object mồ côi với finalizer không bao giờ được xử lý.

Khi Mọi Cách Đều Thất Bại

Vẫn bị kẹt? Kiểm tra xem validating webhook có đang chặn lệnh gọi finalize không:

kubectl get validatingwebhookconfigurations -o yaml | grep -A5 my-namespace

Tạm thời xóa webhook gây ra vấn đề, sau đó thử lại lệnh curl từ Phương pháp 2.

Trên các cluster được quản lý — EKS, GKE, AKS — một số system webhook được control plane tự động cài lại. Bạn không thể an toàn xóa chúng mà không làm hỏng thứ khác. Nếu webhook thuộc về một thành phần do cluster quản lý, hãy mở ticket hỗ trợ với nhà cung cấp cloud. Đó là con đường duy nhất để giải quyết sạch.

Related Error Notes