kubectl delete deployment checkout-api를 실행했는데, Deployment는 사라졌는데도 Pod가 잠깐 남아 있는 경우가 있다. 반대로 Deployment가 한동안 Terminating 상태에서 사라지지 않을 때도 있다.
이 차이는 단순히 삭제 속도 때문에 생기지 않는다. Kubernetes는 리소스 사이의 소유 관계를 보고, 상위 리소스(owner)와 하위 리소스(dependent)를 어떤 순서로 지울지 결정한다. 이 삭제 방식을 propagation policy라고 한다.
이 글에서는 가장 흔한 Deployment → ReplicaSet → Pod 관계를 기준으로 Background, Foreground, Orphan이 실제로 어떻게 다른지 살펴본다.
여기서 garbage collection은 Node의 이미지나 컨테이너를 정리하는 작업이 아니다.
ownerReferences를 따라 더 이상 필요 없는 Kubernetes API 리소스를 지우는 작업을 뜻한다.
리소스의 소유 관계 확인하기
Kubernetes의 controller는 자신이 만든 리소스에 metadata.ownerReferences를 남긴다. Deployment가 ReplicaSet을 만들고, ReplicaSet이 Pod를 만든다면 소유 관계는 다음처럼 이어진다.
label이 같다고 소유 관계가 생기는 것은 아니다. label은 조회와 선택에 쓰이고, garbage collector가 따라가는 연결은 ownerReferences다. 그래서 삭제를 이해할 때는 “이 리소스와 같은 label을 가진 것이 무엇인가?”보다 “누가 이 리소스를 owner로 참조하는가?”를 먼저 보는 편이 정확하다.
세 가지 삭제 방식 비교하기
| 정책 | owner가 API에서 사라지는 시점 | dependent 처리 | 잘 맞는 상황 |
|---|---|---|---|
Background | 먼저 사라진다 | garbage collector가 뒤에서 비동기로 정리한다 | 일반적인 삭제, 빠르게 다음 작업을 진행해도 되는 경우 |
Foreground | dependent 정리가 끝난 뒤 사라진다 | dependent부터 삭제한다 | owner의 삭제 완료가 하위 리소스 정리 완료를 뜻해야 하는 경우 |
Orphan | 먼저 사라진다 | dependent를 남긴다 | 남은 리소스를 의도적으로 이어서 관리할 경우 |
kubectl delete의 기본 --cascade 값은 background다. 옵션을 생략하면 Deployment는 먼저 삭제되고, ReplicaSet과 Pod 정리는 뒤에서 진행된다. 이는 kubectl delete 레퍼런스와 Cascading Deletion 문서에 명시되어 있다.
Background는 상위 리소스를 먼저 지운다
가장 흔한 방식이다.
kubectl delete deployment checkout-api --cascade=background
삭제 요청이 성공하면 Deployment는 API에서 빠르게 보이지 않게 된다. 그 뒤 Kubernetes garbage collector가 owner reference를 따라 ReplicaSet과 Pod를 정리한다. 즉, 명령이 성공했다고 해서 모든 Pod가 이미 종료됐다는 뜻은 아니다.
임시 환경을 빠르게 정리하기
PR마다 잠깐 띄우는 테스트 환경이 있다고 해 보자. 테스트가 끝나면 Deployment를 지우고 namespace 정리나 다음 작업으로 넘어가도 된다. Pod가 수 초 더 실행되는 동안 별도 작업에 문제가 없다면 Background가 자연스럽다.
다만 자동화에서 “Deployment 삭제 성공”을 곧바로 “모든 프로세스 종료”로 해석하면 안 된다. 예를 들어 같은 이름의 외부 리소스를 바로 만들거나, 비용이 드는 워커가 완전히 멈췄는지 확인해야 한다면 Pod 종료 상태를 따로 기다려야 한다.
Foreground는 하위 리소스부터 지운다
kubectl delete deployment checkout-api --cascade=foreground
Foreground 삭제를 요청하면 Deployment에는 deletionTimestamp가 찍히고, 관련 dependent가 정리되는 동안 API에서 계속 보인다. 보통은 Terminating으로 보인다. Kubernetes는 dependent 정리가 끝난 뒤에야 owner를 완전히 삭제한다.
삭제가 끝날 때까지 기다리기
오래된 API 버전을 내리면서, 이 버전이 만든 Pod가 남아 있지 않은 것을 확인한 뒤에만 다음 정리 단계로 넘어가야 한다고 해 보자. 예를 들어 같은 Node에 남은 워커가 외부 시스템에 요청을 계속 보내면 안 되는 상황이다.
Foreground를 쓰면 Deployment가 사라졌다는 사실 자체를 “그 하위 리소스도 처리됐다”는 확인 지점으로 삼을 수 있다. 운영자가 kubectl get deployment checkout-api를 보며 삭제가 끝날 때까지 관찰하기도 쉽다.
다만 Foreground가 모든 삭제 문제를 해결하는 것은 아니다. finalizer나 dependent 정리 문제 때문에 진행이 막히면 owner도 오래 Terminating에 남는다. 이럴 때는 owner만 보지 말고 연결된 ReplicaSet, Pod와 이벤트를 함께 확인해야 한다.
kubectl get deployment checkout-api -o yaml
kubectl get rs,pods -l app.kubernetes.io/name=checkout-api
kubectl get events --sort-by=.lastTimestamp
Kubernetes garbage collector는 owner의 foregroundDeletion finalizer와 ownership 관계를 이용해 이 순서를 관리한다. 세부적으로는 dependent의 blockOwnerDeletion 설정과 garbage collector의 관측 상태도 owner 삭제를 막는 조건에 관여한다. Garbage Collection 공식 문서에 이 동작이 정리되어 있다.
Orphan은 하위 리소스를 남긴다
kubectl delete deployment checkout-api --cascade=orphan
Orphan은 의도적으로 하위 리소스를 남기는 선택이다. Deployment를 대상으로 실행하면 Deployment는 사라지지만, 그 아래 ReplicaSet과 기존 Pod는 남는다. ReplicaSet이 계속 Pod를 관리하므로 실행 중인 Pod도 그대로 동작한다. Kubernetes의 공식 예시도 orphan 삭제 뒤 Deployment가 관리하던 Pod가 계속 실행되는 모습을 보여 준다.
Controller만 지우고 Pod는 잠시 유지하기
배포 controller 구성을 교체하는 작업 중에 기존 Pod를 한꺼번에 내리면 안 되는 상황을 생각해 보자. 아주 짧은 전환 구간에서 기존 Deployment를 orphan으로 삭제하면, 남은 ReplicaSet과 Pod를 유지한 채 다음 조치를 할 시간을 벌 수 있다.
하지만 이것은 임시 조치에 가깝다. Deployment의 rollout·revision 관리 기능은 사라진다. 남은 ReplicaSet은 기존 replica 수를 유지하려 할 수 있지만, 새 이미지로 rollout하거나 원하는 상태를 Deployment 수준에서 바꾸는 일은 더 이상 할 수 없다. 누가 남은 ReplicaSet과 Pod를 정리하거나 새 owner 아래로 전환할지까지 계획해야 한다.
그래서 Orphan은 Pod를 자동으로 안전하게 옮겨 주는 기능이 아니다. 남겨 둔 하위 리소스의 관리 책임을 직접 맡는 선택으로 이해해야 한다.
삭제 방식에 따라 결과 확인하기
아래 명령은 같은 Deployment를 지우지만, 운영에서 확인할 질문은 정책마다 다르다.
# 기본값: Deployment가 먼저 사라져도 Pod 정리는 진행 중일 수 있다.
kubectl delete deployment checkout-api --cascade=background
# Deployment가 사라질 때까지 dependent 정리를 기다린다.
kubectl delete deployment checkout-api --cascade=foreground
# Deployment만 없애고 ReplicaSet과 기존 Pod는 남긴다.
kubectl delete deployment checkout-api --cascade=orphan
| 삭제 뒤 확인할 것 | 이유 |
|---|---|
| Background에서 Pod가 모두 종료됐는가 | owner 삭제와 dependent 종료는 같은 시점이 아니다. |
Foreground에서 어떤 리소스가 Terminating을 붙잡고 있는가 | finalizer 또는 dependent 정리가 막혔을 수 있다. |
| Orphan에서 남은 ReplicaSet과 Pod를 누가 관리·정리할 것인가 | Deployment는 더 이상 rollout과 revision 관리를 하지 않는다. |
--force는 propagation policy와 다른 문제다. force deletion은 graceful deletion을 건너뛸 수 있어 상태 불일치나 데이터 손실 위험이 있다. 삭제 순서를 정하고 싶다는 이유만으로 함께 쓰지 않는 편이 좋다. 관련 경고는 kubectl delete 레퍼런스에도 나와 있다.
핵심 정리
propagation policy는 “삭제할지 말지”보다 삭제가 완료됐다고 무엇을 보장할지를 정하는 선택이다.
Background는 기본값이다. owner는 먼저 사라지고 dependent는 비동기로 정리된다.Foreground는 dependent 정리를 기다린다. owner가 사라졌다는 사실을 정리 완료 신호로 쓰고 싶을 때 맞다.Orphan은 dependent를 남긴다. 편리하지만, 남은 리소스를 관리할 책임도 함께 남긴다.
삭제 자동화를 만들 때는 kubectl delete의 성공 여부만 기록하지 말고, 워크로드가 정말 멈췄는지와 남은 리소스의 owner가 누구인지까지 확인해 두는 것이 안전하다.