Kubernetes 이야기

Finalizers, ownerReferences 본문

Kubernetes/일반

Finalizers, ownerReferences

kmaster 2022. 8. 30. 21:04
반응형

Helm Chart등으로 Application을 설치 후 삭제 시 일부 pod가 terminating 상태로 삭제안되는 경우가 간혹 발생한다.

사유는 pod가 참조하고 있는 객체가 존재하기 때문일 수 있다. 먼저 Finalizers에 대해 알아보자.

 

우리가 간한단 configmap을 한번 만들어보자.

# echo -n "name=admin" > env.properties
# kubectl create configmap myconfig --from-env-file=env.properties
configmap/myconfig created

생성된 configmap 을 확인해 보자.

# k get cm myconfig -o yaml
apiVersion: v1
data:
  name: admin
kind: ConfigMap
metadata:
  creationTimestamp: "2022-08-30T11:06:20Z"
  name: myconfig
  namespace: default
  resourceVersion: "35680631"
  uid: e0d90b99-bae4-4b2b-a660-0fb6044f0903
  
  
# k get cm myconfig
NAME       DATA   AGE
myconfig   1      72s

이제 생성된 myconfig configmap을 삭제해 보자.

# k delete cm myconfig
configmap "myconfig" deleted
# k get cm myconfig
Error from server (NotFound): configmaps "myconfig" not found

기본적인 생성/삭제가 정상적으로 작동한다.

 

Finalizers

Finalizers는 사전 삭제 작업을 알리는 리소스의 Key 이다. 리소스에 대한 가비지 수집을 제어하고 리소스를 제거하기 전에 수행할 정리 작업을 컨트롤러에 알리도록 설계되어 있다. 

 

가장 흔히 볼수 있는 Finalizer는 kubernetes.io/pvc-protection, kubernetes.io/pv-protection가 있다.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  creationTimestamp: "2022-06-10T11:44:54Z"
  finalizers:
  - kubernetes.io/pvc-protection
...

kubernetes.io/pvc-protection는 PVC가 더 이상 파드에서 적극적으로 사용되지 않을 때까지 PVC 삭제가 연기된다. 

또한 관리자가 PVC에 바인딩된 PV를 삭제하면 PV는 즉시 삭제되지 않는다. PV가 더 이상 PVC에 바인딩되지 않을 때까지 PV 삭제가 연기된다.

 

이제 좀전에 만든 configmap에 finalizer를 설정해 보자.

apiVersion: v1
data:
  name: admin
kind: ConfigMap
metadata:
  name: myconfig
  namespace: default
  finalizers:
  - kubernetes

이제 configmap을 삭제해 보자.

# k delete cm myconfig
configmap "myconfig" deleted
<--------------

deleted라는 메시지가 나오지만 커서는 계속대기 중이고 이 때 다른 터미널에서 configmap 상태를 확인해 보면

# k get cm myconfig
NAME       DATA   AGE
myconfig   1      104s

아직 삭제되지 않은 것을 확인할 수 있다. myconfig configmap을 edit로 확인해 보자.

# k get cm myconfig


# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
  name: admin
kind: ConfigMap
metadata:
  creationTimestamp: "2022-08-30T11:25:17Z"
  deletionGracePeriodSeconds: 0
  deletionTimestamp: "2022-08-30T11:25:38Z"
  finalizers:
  - kubernetes
  name: myconfig
  namespace: default
  resourceVersion: "35686541"
  uid: 022d2743-da6e-4d35-bad6-894e0e7cc315

deletionTimestamp 속성이 추가되어 있다. (개체가 삭제된 것이 아니라 업데이트된 것이다.) finalizer 가 있는 객체를 삭제하면 deletionTimestamp가 리소스 메타데이터에 추가되어 객체를 읽기 전용으로 만듭니다. 그리고 모든 finalizer 가 사라지면 개체가 삭제되도록 대기열에 추가된다.

 

finalizer실행할 코드를 지정하지 않는다. 리소스 컨트롤러에서 추가/제거해야 한다.

 

이제 다음과 같이 finalizer 는 강제로 수정해 보자.

# kubectl patch configmap/myconfig --type json --patch='[ { "op": "remove", "path": "/metadata/finalizers" } ]'

patch가 실행되면 좀 전에 삭제 대기중인던 터미널은 정상 종료되고 실제 configmap은 삭제된다.

# k get cm myconfig
Error from server (NotFound): configmaps "myconfig" not found

 

finalizer가 있는 객체를 삭제하려고 하면 컨트롤러가 종료자 키를 제거하거나 종료자가 Kubectl을 사용하여 제거될 때까지 종료 상태로 유지됩니다.

 

ownerReferences

ownerReference 필드는 Deployment -> ReplicaSet -> Pod와 같은 객체 간의 부모/자식 관계를 지정한다. Deployment 와 같은 객체를 삭제하면 개체의 전체 트리가 삭제될 수 있다. 이 과정은 컨트롤러가 일부 작업을 수행하고 Finalizer 필드를 제거해야 하는 Finalizers 기능과 달리 자동으로 수행된다.

 

ownerReference는 이름과 UID로 구성된다. ownerReference는 동일한 네임스페이스 내의 링크 리소스를 참조하며 해당 참조가 작동하려면 UID도 필요하다.

 

다음과 같은 configmap을 만들어 보자.

apiVersion: v1
data:
  type: user
kind: ConfigMap
metadata:
  name: parent

생성 후 parent라는 configmap의 uid를 확인해 보자.

# k get cm parent -o jsonpath="{.metadata.uid}"
d7f6e3d4-e74f-462c-80c5-31ae7b456f15

이제 다른 child configmap을 아래와 같이 생성한다.

apiVersion: v1
data:
  name: admin
kind: ConfigMap
metadata:
  name: child
  ownerReferences:
  - apiVersion: v1
    kind: ConfigMap
    name: parent
    uid: d7f6e3d4-e74f-462c-80c5-31ae7b456f15

만약 child만 삭제하는 경우에는 parent configmap은 삭제되지 않고 child configmap만 삭제된다. 하지만, parent configmap을 삭제하면 child configmap까지 삭제된다.

 

# k delete cm parent
configmap "parent" deleted
# k get cm child
Error from server (NotFound): configmaps "child" not found

요약하면 자식에서 부모로의 재정의 소유자 참조가 있는 경우 부모를 삭제하면 자식이 자동으로 삭제된다.

이것을 cascade라고 하는데, 기본값은 true이다.  만약 kubectl에서 --cascade=orphan 옵션을 주면 자식 객체가 삭제되지 않도록 할 수 있다.

 

Namespace 강제 삭제

 

가끔 namespace삭제 시 terminating에서 삭제가 안되는 경우가 있다. 이때 finalizer를 강제로 null로 만들어 삭제할 수 있다.

# kubectl proxy
Starting to serve on 127.0.0.1:8001


# cat <<EOF | curl -X PUT \
  http://localhost:8001/api/v1/namespaces/test/finalize \
  -H "Content-Type: application/json" \
  --data-binary @-
{
  "kind": "Namespace",
  "apiVersion": "v1",
  "metadata": {
    "name": "test"
  },
  "spec": {
    "finalizers": null
  }
}
EOF

이것은 네임스페이스만 삭제하고 현재 존재하지 않는 네임스페이스 내에 고아 개체를 남길 수 있으므로 주의해서 수행해야 한다.

 

CRD 강제 삭제

kubectl patch crd/crontabs.stable.example.com -p '{"metadata":{"finalizers":[]}}' --type=merge
반응형
Comments