Khi Helm đi vào ngõ cụt
Bạn đang đẩy một bản cập nhật thông thường lên môi trường production và mong đợi một dấu tích xanh từ luồng CI/CD của mình. Thay vào đó, việc triển khai dừng lại đột ngột. Helm báo một lỗi cụ thể và gây ức chế: rendered manifests contain a resource that already exists. Bản phát hành của bạn bị kẹt, và cluster rơi vào trạng thái lơ lửng.
Error: UPGRADE FAILED: rendered manifests contain a resource that already exists. Unable to continue with update: existing resource conflict
Xung đột này xảy ra khi Helm cố gắng tạo một tài nguyên—chẳng hạn như ConfigMap, Secret hoặc Service—đã tồn tại trong namespace của bạn nhưng không thuộc bản phát hành Helm hiện tại. Thông thường, điều này xảy ra do ai đó đã chỉnh sửa cluster thủ công bằng kubectl hoặc một nỗ lực cài đặt trước đó bị thất bại và để lại các tài nguyên "mồ côi".
Tại sao Helm từ chối tiếp tục
Helm được thiết kế để bảo vệ hệ thống một cách tối đa. Khi bạn chạy helm upgrade, nó sẽ tạo ra các manifest YAML và so sánh chúng với cluster thực tế. Nếu nó tìm thấy một tài nguyên có tên và loại (kind) trùng khớp nhưng thiếu các metadata cụ thể (label và annotation) của bản phát hành hiện tại, Helm sẽ dừng lại. Nó giả định tài nguyên đó thuộc về một thực thể khác và từ chối ghi đè để ngăn chặn việc mất dữ liệu ngoài ý muốn.
Bạn sẽ thường thấy lỗi này trong ba tình huống sau:
- Một thành viên trong nhóm đã chạy
kubectl applythủ công để sửa lỗi nhanh. - Một lệnh
helm installtrước đó đã bị timeout ở mốc 5 phút và bị treo. - Bạn đang di chuyển các tài nguyên từ một chart nguyên khối cũ sang một sub-chart mới.
Bước 1: Xác định "thủ phạm"
Thông báo lỗi thường chỉ ra chính xác tài nguyên nào đang gây ra vấn đề. Nó có thể trông như thế này:
Existing resource conflict: kind: Secret, namespace: production, name: app-credentials
Kiểm tra trạng thái hiện tại của tài nguyên đó để xem nó có thực sự được quản lý bởi bất kỳ thứ gì không:
kubectl get secret app-credentials -n production -o yaml
Kiểm tra phần metadata. Nếu bạn không thấy annotation app.kubernetes.io/managed-by: Helm và meta.helm.sh/release-name, nghĩa là Helm không "sở hữu" nó. Đó là một tài nguyên mồ côi.
Tùy chọn A: Reset nhanh (Xóa và Tạo lại)
Nếu tài nguyên đó là stateless—như Service hoặc ConfigMap không chứa dữ liệu quan trọng—cách khắc phục nhanh nhất là xóa nó đi. Helm sẽ đơn giản là tạo lại nó trong lần thử nâng cấp tiếp theo.
# Xóa tài nguyên gây xung đột
kubectl delete secret app-credentials -n production
# Thử nâng cấp lại
helm upgrade --install my-app ./charts/my-app -n production
Cảnh báo: Đừng bao giờ làm điều này với PersistentVolumeClaims hoặc Secrets chứa các mã khóa production quan trọng (như mật khẩu RDS) trừ khi bạn đã có bản sao lưu được xác thực.
Tùy chọn B: Chuyển quyền quản lý tài nguyên cho Helm
Đôi khi bạn không thể chấp nhận dù chỉ một giây downtime. Trong trường hợp này, bạn cần "dạy" cho Helm biết rằng nó sở hữu tài nguyên hiện có. Bạn thực hiện việc này bằng cách thêm thủ công các label và annotation mà Helm mong đợi.
Chạy các lệnh sau để gắn thẻ cho tài nguyên hiện có của bạn:
# Định nghĩa các biến của bạn
RELEASE_NAME="my-app"
NAMESPACE="production"
RESOURCE_KIND="secret"
RESOURCE_NAME="app-credentials"
# Thêm các annotation bắt buộc
kubectl annotate $RESOURCE_KIND $RESOURCE_NAME -n $NAMESPACE meta.helm.sh/release-name=$RELEASE_NAME
kubectl annotate $RESOURCE_KIND $RESOURCE_NAME -n $NAMESPACE meta.helm.sh/release-namespace=$NAMESPACE
# Thêm label bắt buộc
kubectl label $RESOURCE_KIND $RESOURCE_NAME -n $NAMESPACE app.kubernetes.io/managed-by=Helm
Sau khi đã gắn thẻ, hãy chạy lại helm upgrade. Helm sẽ nhận diện tài nguyên đó là của mình và cập nhật nó một cách mượt mà.
Khắc phục lỗi "Another Operation in Progress"
Nếu nỗ lực trước đó của bạn bị gián đoạn (có lẽ một CI runner đã bị timeout sau 300 giây), bạn có thể thấy một lỗi phụ: another operation is in progress. Helm nghĩ rằng một quá trình triển khai vẫn đang chạy và khóa trạng thái bản phát hành ở mức pending-upgrade.
Để phá khóa này, bạn phải tìm và xóa Secret mà Helm sử dụng để theo dõi lần thử thất bại cụ thể đó. Những Secret này thường có tên là sh.helm.release.v1.[RELEASE_NAME].v[VERSION].
# Liệt kê tất cả các phiên bản release để tìm số hiệu cao nhất
kubectl get secrets -n production | grep sh.helm.release.v1.my-app
# Xóa secret cho phiên bản đang ở trạng thái 'pending' (ví dụ: v15)
kubectl delete secret sh.helm.release.v1.my-app.v15 -n production
Sau khi secret đó bị xóa, Helm sẽ quay trở lại phiên bản thành công gần nhất (ví dụ: v14), và bạn có thể thử nâng cấp lại.
Kiểm tra và Phòng ngừa
Sau khi khắc phục, hãy xác nhận bản phát hành đã ổn định:
- Chạy
helm status my-app -n production. Tìm dòngSTATUS: deployed. - Xác minh metadata:
kubectl get secret app-credentials -n production -o jsonpath='{.metadata.labels}'. Nó sẽ hiển thị label quản lý của Helm.
Để tránh điều này trong tương lai, hãy luôn sử dụng cờ --atomic trong các luồng pipeline của bạn. Điều này đảm bảo rằng nếu việc triển khai thất bại, Helm sẽ tự động rollback về trạng thái ổn định trước đó, ngăn bản phát hành của bạn bị kẹt trong vòng lặp pending.

