DevOps/k8s

K8S server-side apply & managed fields

xlwdn98767 2023. 6. 18. 14:00
728x90

Server-side apply

 

 k8s에서는 기본적으로 명령어 실행 시 클라이언트측에서 매니페스트와의 차이를 계산하여 패치를 요청한다.(Client-side apply) 하지만, 이러한 방식은 여러 사용자(CI/CD, 또는 여러 명의 관리자) 가 동시에 같은 필드를 수정하는 요청을 보낼 경우 경합 현상이 발생할 수 있다. 이를 해결하기 위해 필드를 변경한 manager를 기록하고 서버 측에서 변경 사항을 계산하는 기능이 도입되었다.

 

 

예시

매니페스트 파일 내용(sample-pod.yaml)

apiVersion: v1
kind: Pod
metadata:
  name: sample-pod

spec:
  containers:
    - name: nginx-container
      image: nginx:1.16

 

[user@MacBook-Pro-2 test (⎈|eks-iam@eks-tutorial.ap-northeast-2.eksctl.io:N/A)]$ k apply -f sample-pod.yaml --server-side
pod/sample-pod serverside-applied
[user@MacBook-Pro-2 test (⎈|eks-iam@eks-tutorial.ap-northeast-2.eksctl.io:N/A)]$ k set image pod sample-pod nginx-container=nginx:1.17
pod/sample-pod image updated
[user@MacBook-Pro-2 test (⎈|eks-iam@eks-tutorial.ap-northeast-2.eksctl.io:N/A)]$ k apply -f sample-pod.yaml --server-side
error: Apply failed with 1 conflict: conflict with "kubectl-set" using v1: .spec.containers[name="nginx-container"].image
Please review the fields above--they currently have other managers. Here
are the ways you can resolve this warning:
* If you intend to manage all of these fields, please re-run the apply
  command with the `--force-conflicts` flag.
* If you do not intend to manage all of the fields, please edit your
  manifest to remove references to the fields that should keep their
  current managers.
* You may co-own fields by updating your manifest to match the existing
  value; in this case, you'll become the manager if the other manager(s)
  stop managing the field (remove it from their configuration).
See https://kubernetes.io/docs/reference/using-api/server-side-apply/#conflicts

위와 같이 충돌이 발생한다고 오류를 출력한다.

 

Field Manager

[user@MacBook-Pro-2 test (⎈|eks-iam@eks-tutorial.ap-northeast-2.eksctl.io:N/A)]$ k get pod sample-pod -o yaml --show-managed-fields
apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Pod","metadata":{"name":"sample-pod","namespace":"default"},"spec":{"containers":[{"image":"nginx:1.16","name":"nginx-container"}]}}
  creationTimestamp: "2023-06-17T18:45:20Z"
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:spec:
        f:containers:
          k:{"name":"nginx-container"}:
            .: {}
            f:name: {}
    manager: ci-tool
    operation: Apply
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          f:kubectl.kubernetes.io/last-applied-configuration: {}
    manager: kubectl-last-applied
    operation: Apply
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:spec:
        f:containers:
          k:{"name":"nginx-container"}:
            .: {}
            f:name: {}
    manager: kubectl
    operation: Apply
    time: "2023-06-18T04:43:27Z"
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:spec:
        f:containers:
          k:{"name":"nginx-container"}:
            f:image: {}
    manager: kubectl-set
    operation: Update
    time: "2023-06-18T04:54:15Z"
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:status:
        f:conditions:
          k:{"type":"ContainersReady"}:
            .: {}
            f:lastProbeTime: {}
            f:lastTransitionTime: {}
            f:status: {}
            f:type: {}
          k:{"type":"Initialized"}:
            .: {}
            f:lastProbeTime: {}
            f:lastTransitionTime: {}
            f:status: {}
            f:type: {}
          k:{"type":"Ready"}:
            .: {}
            f:lastProbeTime: {}
            f:lastTransitionTime: {}
            f:status: {}
            f:type: {}
        f:containerStatuses: {}
        f:hostIP: {}
        f:phase: {}
        f:podIP: {}
        f:podIPs:
          .: {}
          k:{"ip":"192.168.6.63"}:
            .: {}
            f:ip: {}
        f:startTime: {}
    manager: kubelet
    operation: Update
    subresource: status
    time: "2023-06-18T04:54:16Z"
  name: sample-pod
  namespace: default
  resourceVersion: "93907"
  uid: 1a34cfab-21f7-4f3a-902f-b7940917e71d
spec:
  containers:
  - image: nginx:1.17
   ....

위와 같이 "k get pod sample-pod -o yaml --show-managed-fields"를 입력하면 매니저에 대한 정보가 포함된 메타데이터가 표시된다. 

이를 활용하여, server-side apply를 활성화한 후 --field-manager옵션을 함께 입력하여 충돌을 감지하고 원인을 파악하는 데에 더욱 효율적이고 안전하게 작업을 수행할 수 있다.

k apply -f sample-pod.yaml --server-side --field-manager ci-tool

 

충돌 발생 시 아래와 같이 manager이름과 함께 출력된다.

error: Apply failed with 1 conflict: conflict with "kubectl-set" using v1: .spec.containers[name="nginx-container"].image