LabHub
배우기 러닝패스 코스

KCNA — 쿠버네티스·클라우드 네이티브 입문 · 배포·준비 실패·롤백의 증거 읽기 · 이론

배포 명령의 성공과 새 버전의 성공은 다르다

LabHub 에서 이어서 보기

한 줄 요약

API가 새 선언을 받아들였다는 사실, 컨트롤러가 그 선언을 관측했다는 사실, 새 프로세스가 요청을 처리한다는 사실은 서로 다른 증거입니다.

왜 이게 필요했나

금요일 오후 새 버전 배포 명령이 성공했습니다. Deployment의 AVAILABLE도 2입니다. 그런데 사용자는 계속 옛 화면을 봅니다. 배포가 성공했으니 브라우저 캐시 문제라고 단정해도 될까요? 아직은 아닙니다. 정상인 옛 Pod 두 개가 요청을 처리하는 동안 준비되지 않은 새 Pod 하나가 옆에서 실패하고 있을 수 있습니다. 가용성이 유지됐다는 사실은 반가운 일이지만, 그 사실만으로 새 버전의 전달까지 증명할 수는 없습니다.

클라우드 네이티브 전달은 소스 코드를 파일로 옮기는 일에서 끝나지 않습니다. 무엇을 실행할지 선언하고, 그 선언을 실제 프로세스로 바꾸고, 요청을 받을 준비가 됐는지 관찰하며, 실패하면 어느 상태로 돌아갈지 결정하는 흐름입니다. CI는 변경을 통합하고 시험하는 과정에 초점을 두고, 지속적 전달은 배포 가능한 상태를 유지하는 데 초점을 둡니다. 모든 변경을 운영에 자동 공개하는 지속적 배포와도 구별합니다. Git에 커밋이 있다는 사실은 이 중 일부의 기록일 뿐, 사용자 응답의 증거는 아닙니다.

어떻게 동작하나

Deployment는 원하는 Pod 템플릿과 복제본 수를 선언합니다. Deployment 컨트롤러는 ReplicaSet을 만들거나 조정하고, ReplicaSet은 필요한 Pod를 유지합니다. kubelet이 컨테이너를 실행하고 readiness가 준비 여부를 보고하면 Service의 전달 대상도 그 상태를 반영합니다. 서로 다른 구성요소가 각자 수렴하므로 한 번의 API 응답을 전체 작업 완료로 읽으면 안 됩니다.

조사할 때는 이름 하나보다 연결 관계를 봅니다. Deployment UID와 그 객체를 소유자로 가리키는 ReplicaSet UID, 다시 그 ReplicaSet을 소유자로 가리키는 Pod UID를 따라가세요. 이름이 비슷한 Pod를 사람이 직접 만들어 놓은 경우를 실제 롤아웃의 결과로 착각하지 않게 됩니다. 새 버전이 기동했는지는 컨테이너 상태와 준비 조건으로, 어떤 버전이 전달되는지는 실제 응답으로 따로 확인합니다.

Deployment의 generation은 선언 변화의 세대를, status.observedGeneration은 컨트롤러가 관측한 세대를 비교하는 데 쓰입니다. 둘이 같아도 새 버전이 모두 준비됐다는 뜻은 아닙니다. updatedReplicas는 새 템플릿에 해당하는 복제본을, availableReplicas는 가용 조건을 만족한 복제본을 보는 데 쓰입니다. 완료 여부는 이 값들과 조건, 실제 응답을 함께 조사해야 합니다. 특히 롤아웃 중 가용한 복제본에는 옛 버전이 포함될 수 있습니다.

kubectl -n kcna-delivery get deployment web -o yamlkubectl -n kcna-delivery get replicasetskubectl -n kcna-delivery get pods -l app=webkubectl -n kcna-delivery get endpointslices

모든 변경이 새 ReplicaSet을 만드는 것은 아닙니다. Deployment 객체 자체의 설명용 annotation을 바꾸는 것과 spec.template 안의 환경변수를 바꾸는 것은 위치가 다릅니다. 이 실습은 먼저 객체의 annotation만 바꿔 기존 Pod·ReplicaSet·revision이 유지되는지 확인합니다. 나중에는 템플릿의 RELEASE를 v1에서 v2로 바꾸어 새 ReplicaSet과 새 Pod가 생기는 것을 비교합니다. 같은 kubectl로 요청했는지가 아니라 어느 선언을 바꿨는지가 중요합니다.

설정도 별도의 경계입니다. ConfigMap은 비밀이 아닌 설정 데이터를 담는 객체입니다. 여기서는 color 값을 컨테이너 환경변수로 주입합니다. ConfigMap의 blue를 green으로 바꿔도 이미 실행 중인 프로세스의 환경변수는 자동으로 다시 읽히지 않습니다. ConfigMap API는 green인데 응답은 blue일 수 있습니다. 이 현상을 데이터 유실로 단정하지 말고, 설정을 언제 어떤 방식으로 소비했는지 확인하세요. 파일 볼륨으로 투영하거나 앱이 API를 직접 읽는 방식과 환경변수 주입을 같은 갱신 규칙으로 일반화하면 안 됩니다.

현장에서 만나는 모습

배포 상태 화면의 초록불 하나에 여러 뜻을 섞으면 대응도 엉뚱한 곳으로 갑니다. GitOps의 동기화는 원하는 선언과 클러스터 선언의 일치를 설명할 수 있지만, 새 앱의 업무 요청이 성공했는지는 별도 검증이 필요합니다. 이미지 태그도 마찬가지입니다. 움직이는 태그 문자열이 같다는 이유로 같은 바이트가 실행된다고 보장할 수는 없습니다. 이 실험은 이미지 digest를 고정하고 작은 합성 앱의 릴리스 환경변수를 바꿉니다. 실제 새 이미지를 빌드하거나 공급망 서명을 검증하는 실습은 아닙니다.

운영에서는 새 버전 식별자, 오류율, 지연, 필요한 업무 경로까지 확인해야 합니다. 여기서 여섯 번의 HTTP 응답을 읽는 것은 수업의 상태를 비교하기 위한 표본이지, 무중단이나 서비스 수준 목표를 통계적으로 보장하는 검사는 아닙니다. 정상 비교군을 보존하는 이유도 범위를 구별하기 위해서입니다. 실험 대상의 선언 변화와 클러스터 전체 장애를 같은 원인으로 취급하지 않습니다.

뒤의 실습에서 할 것

v1·blue가 응답하는 기준선에서 annotation만 바꾸고, ConfigMap만 green으로 바꾼 뒤 각각 Pod 신원을 비교합니다. 그다음 v2 템플릿으로 실제 롤아웃해 새 Pod의 응답이 green이 되는지 확인합니다. 이어지는 이론은 준비되지 않는 v3가 들어왔을 때 기존 응답을 지키고 복구하는 경계를 설명합니다.

공식 근거: [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) · [ConfigMap](https://kubernetes.io/docs/concepts/configuration/configmap/).