Kubernetes Operator 개발 중 Conflict Error


참조 링크: https://alenkacz.medium.com/kubernetes-operators-best-practices-understanding-conflict-errors-d05353dff421 ### Kubernetes Operators Best Practices: Conflict Errors 이해하기 Operator를 개발할 때 자주 마주치는 오류 중 하나는 다음과 같습니다.
 the object has been modified; please apply your changes to the latest version and try again 
이 오류를 이해하려면, Kubernetes API 서버가 **낙관적 동시성 제어(Optimistic Concurrency Control)** 를 사용한다는 점을 알아야 합니다. 즉, 두 사용자가 동시에 같은 리소스를 수정할 때 **락(Lock)을 걸지 않고** `resourceVersion` 필드를 활용하여 충돌을 감지합니다. ### `resourceVersion`이란? 모든 Kubernetes 리소스는 `ObjectMeta`에 `resourceVersion` 필드를 포함하고 있으며, - 이 값은 etcd에 저장된 현재 리소스 버전과 매칭됩니다. - etcd에서 각 항목은 `revision`이라는 64비트 정수로 관리되며, 변경될 때마다 증가합니다. - `resourceVersion`은 API 서버가 이를 활용하여 리소스 충돌 여부를 판단합니다. ### 충돌(Conflict) 오류가 발생하는 이유 일반적으로 Operator는 다음과 같은 과정으로 리소스를 관리합니다. 1. `CustomResource`의 `Spec`을 읽고, 이를 반영하여 시스템 상태를 업데이트 2. 현재 상태를 `Status` 필드에 업데이트 이 과정에서 충돌이 발생하는 주요 원인은 다음과 같습니다. **사용자가 새로운 `Spec`을 적용하여 리소스가 변경됨** **다른 컨트롤러가 `Status` 또는 기타 필드를 업데이트함** ## 해결 방법 충돌 오류가 발생했을 때 처리하는 방법은 크게 두 가지입니다. 1. **단순 재시도** → Reconcile Loop에서 오류를 반환하여 다시 시도 2. **`RetryOnConflict` 사용** → `client-go`의 `RetryOnConflict`를 활용하여 자동 재시도 아래는 `RetryOnConflict`를 활용한 구현 예제입니다. ```go err := retry.RetryOnConflict(retry.DefaultRetry, func() error { var res apiv1.MyResource err := r.Get(ctx, types.NamespacedName{ Name: resourceName, Namespace: resourceNamespace, }, &res) if err != nil { return err } res.Status.Replicas = readyReplicas return r.Status().Update(ctx, &res) }) if err != nil { return fmt.Errorf("failed to update resource status: %w", err) } ``` 설명: 1. `retry.RetryOnConflict(retry.DefaultRetry, func() error { ... })`: `RetryOnConflict` 함수는 첫 번째 인자로 재시도 설정을, 두 번째 인자로 실행할 함수를 받습니다. retry.DefaultRetry는 기본 재시도 설정 2. `r.Get(ctx, namespacedName, &res)`: 업데이트할 MyResource 를 가져옵니다. 3. `res.Status.Replicas = readyReplicas` 원하는 값으로 업데이트 4. `r.Update(ctx, &res)`: 업데이트된 ReplicaSet 리소스를 API 서버에 전송합니다. 이 함수가 Conflict Error를 반환하면 RetryOnConflict가 자동으로 재시도를 수행합니다.
되돌아가기 수정