쿠버네티스 오퍼레이터를 개발하면서, 대상 리소스가 변경 되었는지 확인하는 경우가 있습니다. 리소스 내용이 변경되었으면, 어떠한 행위를 하기 위해서입니다.
두 리소스를 비교하기 위한 가장 쉬운 방법은 DeepEqual
을 사용하는 것입니다.
if !reflect.DeepEqual(expected, actual) { // need to update... }
하지만 이 방법은 한계를 가지고 있습니다. 메타데이터나 기본값을 적용될 경우 제대로 된 비교가 안될 수 있기 때문입니다.
예를 들어 다음과 같은 hello-pod
를 생성했다고 가정해보겠습니다.
apiVersion: v1 Kind: Pod metadata: name: hello-pod spec: containers: - name: busybox image: busybox
쿠버네티스 API를 이용하여, hello-pod
의 정보를 조회해오면 다음과 같이 기본값들과 메타데이터 정보가 포함되어 있습니다.
apiVersion: v1 Kind: Pod metadata: creationTimestamp: "2021-01-17T03:00:00Z" namespace: default name: hello-pod uid: 673795dc-595b-11eb-a633-fa163fad3156 spec: containers: - name: busybox image: busybox imagePullPolicy: Always dnsPolicy: ClusterFirst
즉, 두 개의 Pod은 같은 것이지만, DeepEqual
을 이용하여 비교를 하면 다른것으로 판별됩니다.
두 개의 Pod가 진짜 다른것인지를 판별하기 위해서는 다음과 같이 할 수도 있습니다.
if sameName(expected, actual) && sameContainers(expected, actual) && ...
필요한 부분만 직접 비교를 하는 것입니다. 비교할 필드가 1,2개 정도면 이 방법도 사용할 수 있습니다만, 현실세계에서는 대부분 많은 필드를 가지고 있기 때문에 효율적이지 않습니다.
두 리소스를 비교하는 가장 스마트한 방법은 리소스의 Hash값을 이용하는 것입니다. 다음은 HashObject
함수를 이용하여, 리소스의 해시값을 계산한 후 비교하는 코드입니다.
hash := HashObject(expected) expected.Annotations["ResourceHash"] = hash actualHash := actual.Annotations["ResourceHash"] if actualHash != hash { // need to update... }
다음은 HashObject
함수입니다.
// HashObject writes the specified object to a hash using the spew library // which follows pointers and prints actual values of the nested objects // ensuring the hash does not change when a pointer changes. // The returned hash can be used for object comparisons. // // This is inspired by controller revisions in StatefulSets: // <https://github.com/kubernetes/kubernetes/blob/8de1569ddae62e8fab559fe6bd210a5d6100a277/pkg/controller/history/controller_history.go#L89-L101> func HashObject(object interface{}) string { hf := fnv.New32() printer := spew.ConfigState{ Indent: " ", SortKeys: true, DisableMethods: true, SpewKeys: true, } _, _ = printer.Fprintf(hf, "%#v", object) return fmt.Sprint(hf.Sum32()) }
출처 : https://github.com/elastic/cloud-on-k8s/blob/master/pkg/controller/common/hash/hash.go
참고 : https://github.com/kubernetes/kubernetes/blob/master/pkg/util/hash/hash.go