Hiểu cơ chế xóa trong Kubernetes với finalizers và owner references
Một hướng dẫn năm 2021 giải thích cách các finalizer ngăn chặn việc xóa tài nguyên và cách các owner reference quản lý quy trình xóa dây chuyền (cascading deletes) trong các cụm Kubernetes.
Được dịch tự động từ bản gốc tiếng Anh.
Trong một bài đăng trên Blog Kubernetes vào tháng 5 năm 2021, Aaron Alpar đã trình bày chi tiết về cơ chế nội bộ của quá trình xóa đối tượng trong Kubernetes. Bài viết làm rõ lý do tại sao một số tài nguyên vẫn tồn tại sau khi lệnh xóa được thực thi và giải thích vai trò của các finalizer cùng owner reference trong việc quản lý trạng thái cụm.
Điều gì đã xảy ra
Kubernetes cung cấp các lệnh tiêu chuẩn để tạo, đọc, cập nhật và xóa đối tượng, nhưng quá trình xóa phức tạp hơn nhiều so với việc chỉ đơn thuần loại bỏ dữ liệu khỏi kho lưu trữ. Khi người dùng phát lệnh kubectl delete, hệ thống không phải lúc nào cũng ngay lập tức gỡ bỏ đối tượng khỏi registry etcd. Thay vào đó, thao tác có thể chuyển sang trạng thái chờ (pending) nếu đáp ứng các điều kiện cụ thể, chẳng hạn như sự hiện diện của các finalizer hoặc mối quan hệ chủ sở hữu phức tạp.
Bài viết chứng minh rằng mặc dù các thao tác xóa cơ bản hoạt động đúng như mong đợi đối với những tài nguyên đơn giản như ConfigMaps không có metadata bổ sung, việc thêm các finalizer sẽ thay đổi hành vi đáng kể. Một finalizer đóng vai trò như một hook trước khi xóa, báo hiệu cho các controller rằng các thao tác dọn dẹp phải hoàn tất trước khi tài nguyên bị loại bỏ hoàn toàn. Nếu các hook này không được xử lý, đối tượng sẽ ở trạng thái đang kết thúc (terminating), hiển thị dấu thời gian xóa (deletion timestamp) nhưng vẫn còn tồn tại trong cụm.
Hơn nữa, mối quan hệ giữa các tài nguyên, được xác định bởi các owner reference, quyết định cách các nhóm đối tượng bị xóa cùng nhau. Việc xóa một đối tượng cha có thể kích hoạt quá trình xóa các đối tượng con, được gọi là xóa dây chuyền (cascading). Tuy nhiên, hành vi này có thể được điều chỉnh bằng các chính sách lan truyền (propagation policies), cho phép các nhà phát triển cô lập (orphan) các đối tượng con hoặc kiểm soát thứ tự xóa. Hiểu rõ các cơ chế này là yếu tố then chốt để gỡ lỗi các namespace bị kẹt hoặc các tài nguyên còn sót lại.
Cách thức hoạt động
Finalizers là các khóa được gắn vào metadata của tài nguyên nhằm ngăn chặn việc thu gom rác (garbage collection) ngay lập tức. Chúng hoạt động tương tự như annotations nhưng mang ý nghĩa ngữ nghĩa đối với các controller. Khi một yêu cầu xóa được gửi cho đối tượng có chứa finalizers, Kubernetes sẽ cập nhật đối tượng với trường deletionTimestamp nhưng chặn việc gỡ bỏ nó khỏi etcd. Đối tượng sẽ duy trì trạng thái này cho đến khi một controller xóa các khóa finalizer, báo hiệu rằng quá trình dọn dẹp đã hoàn tất. Nếu không có controller nào quản lý finalizer đó, nó trở thành một "dead" finalizer, đòi hỏi sự can thiệp thủ công thông qua lệnh patch để xóa khóa và cho phép quá trình xóa tiếp diễn.

Owner references thiết lập mối quan hệ cha-con giữa các tài nguyên trong cùng một namespace. Mỗi reference bao gồm tên và định danh duy nhất (UID) của đối tượng cha. Khi một đối tượng cha bị xóa, Kubernetes kiểm tra các reference này để xác định xem các đối tượng con có nên bị xóa hay không. Quá trình xóa dây chuyền này được kiểm soát bởi một chính sách lan truyền. Chính sách mặc định, đã thay đổi thành background trong kubectl v1.20, cho phép xóa đối tượng cha trước trong khi các đối tượng con được xóa bất đồng bộ. Các tùy chọn khác bao gồm foreground, nơi các đối tượng con bị xóa trước đối tượng cha, và orphan, bỏ qua các owner reference và giữ nguyên các đối tượng con.
Chi tiết quan trọng
- Finalizers là danh sách các khóa trên tài nguyên, báo hiệu cho các controller về các thao tác cần thực hiện trước khi xóa.
- Các đối tượng có chứa finalizers không bị gỡ bỏ ngay lập tức; chúng nhận được trường
deletionTimestampvà vẫn hiển thị cho đến khi các finalizer được xóa sạch. - Owner references liên kết các tài nguyên thông qua tên và UID, cho phép xóa dây chuyền các đối tượng con khi đối tượng cha bị loại bỏ.
- Hành vi xóa dây chuyền mặc định trong kubectl v1.20 trở lên là
background, trong khi các phiên bản cũ hơn mặc định làtrue. - Các chính sách lan truyền (
Foreground,Background,Orphan) kiểm soát thứ tự xóa và chỉ có thể được thiết lập qua các cuộc gọi API trực tiếp, không phải qua các cờ kubectl tiêu chuẩn. - Các namespace bị kẹt có thể được buộc hoàn tất quá trình finalize bằng cách cập nhật subresource
finalizequa API, tuy nhiên điều này tiềm ẩn rủi ro để lại các đối tượng mồ côi (orphaned objects).
Tại sao điều này quan trọng
Đối với các kỹ sư xây dựng và duy trì nền tảng Kubernetes, việc hiểu rõ cơ chế xóa giúp tránh nhầm lẫn khi các tài nguyên không biến mất như mong đợi. Một kịch bản phổ biến là namespace vẫn ở trạng thái Terminating vì một tài nguyên tùy chỉnh hoặc controller của bên thứ ba đã thêm một finalizer mà không còn được xử lý. Nếu không biết cách kiểm tra và vá (patch) các finalizer, các quản trị viên vận hành có thể gặp khó khăn trong việc dọn dẹp cụm, dẫn đến rò rỉ tài nguyên và thất bại trong triển khai.

Ngoài ra, việc quản lý đúng đắn các owner reference đảm bảo rằng quá trình gỡ cài đặt ứng dụng diễn ra sạch sẽ và dự đoán được. Nếu một nhà phát triển xóa một Deployment mà không hiểu rõ các quy tắc xóa dây chuyền, họ có thể vô tình để lại các Pod hoặc Service chiếm dụng tài nguyên. Ngược lại, việc biết cách sử dụng chính sách orphan cho phép áp dụng các chiến lược di trú an toàn, nơi các tài nguyên con cần tồn tại độc lập sau khi đối tượng cha gốc bị xóa. Kiến thức này là thiết yếu để viết các operator và script tự động hóa vững chắc khi tương tác với API Kubernetes.
Bạn có thể làm gì
- Kiểm tra các đối tượng bị kẹt trong quá trình xóa bằng cách xem xét đầu ra YAML của chúng để tìm các trường
finalizersvàdeletionTimestamp. - Xóa thủ công các dead finalizers bằng cách sử dụng
kubectl patchvới một thao tác JSON để loại bỏ khóa finalizer cụ thể khỏi metadata. - Sử dụng
kubectl getkèm theo owner references để hình dung các phụ thuộc giữa các tài nguyên trước khi thực hiện các thao tác xóa hàng loạt. - Kiểm thử hành vi xóa dây chuyền trong môi trường phi sản xuất bằng cách tạo các ConfigMaps cha-con và quan sát tác động của các lệnh xóa khác nhau.
- Sử dụng
kubectl proxyđể thực hiện các cuộc gọi API trực tiếp khi bạn cần chỉ định các chính sách lan truyền nhưForegroundhoặcBackground. - Thận trọng khi buộc hoàn tất quá trình finalize namespace qua API, vì điều này có thể để lại các tài nguyên mồ côi đòi hỏi phải dọn dẹp thủ công.


