LabHub
배우기 러닝패스 코스

Helm Deployment and Rollback Scenarios

Deploy It, Break It, Roll It Back

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

배포를 되돌릴 수 있는 것으로 만듭니다. 배포하고, 일부러 깨뜨리고, 두 가지 방법으로 되돌리고, 갇힌 릴리스를 꺼내는 것까지 한 바퀴 돕니다.

왜 중요한가

배포 자동화의 성패는 성공했을 때가 아니라 실패했을 때 어떤 상태로 남는가로 갈립니다. helm upgrade 는 기본적으로 파드가 뜨는지 보지 않고 성공을 반환합니다. 그래서 CI 는 초록불인데 사용자만 장애를 겪는 상황이 만들어집니다.

이 실습에서는 그 상황을 직접 만들어 봅니다. 4단계에서 없는 이미지로 배포하면 helm 이 STATUS: deployed 라고 말하는 걸 눈으로 보게 됩니다. 그다음 --atomic 을 붙이면 무엇이 달라지는지 비교합니다.

환경

이 파드는 kwok 으로 진짜 kube-apiserver 를 띄웁니다. 파드가 실제로 실행되지는 않지만 릴리스 시크릿·리비전·리소스 변경은 전부 진짜입니다. 그래서 채점도 파일이 아니라 클러스터 상태를 다시 읽어서 합니다.

kubectl get nodes            노드 2대가 Ready
helm version                 v3.16

단계

  1. helm create demohelm install
  2. 릴리스 시크릿에서 매니페스트를 꺼내 /root/helm/02-manifest.yaml
  3. --set replicaCount=4 로 리비전 2
  4. 없는 이미지로 업그레이드 — 성공했다고 나오는 것을 확인
  5. 같은 실수를 --atomic 으로 다시 → /root/helm/05-atomic.txt
  6. helm rollback demo 2
  7. helm template 두 번을 diff → /root/helm/07-diff.txt
  8. pending-upgrade 에 갇힌 릴리스를 꺼내기

참고

차트를 만들고 배포한다

helm create demohelm install

helm create demo 로 뼈대를 만들고 helm install demo ./demo 로 배포합니다. helm list 에 deployed 로 보이면 됩니다. 이 클러스터는 kwok 이라 파드가 실제로 실행되지는 않지만, 릴리스·리비전·리소스는 전부 진짜입니다.

릴리스가 저장된 시크릿을 직접 본다

릴리스 시크릿에서 매니페스트를 꺼내 /root/helm/02-manifest.yaml

kubectl get secret -l owner=helm 으로 이름을 확인합니다. -o jsonpath='{.data.release}'base64 -dbase64 -dgzip -d 순서로 풀면 릴리스 JSON 전체가 나옵니다(매니페스트가 아닙니다). 렌더링된 YAML 은 그 JSON 의 .manifest 필드에 문자열로 들어 있으니 jq -r .manifest 로 꺼내 /root/helm/02-manifest.yaml 에 저장하세요.

replicas 를 올려 리비전 2를 만든다

--set replicaCount=4 로 리비전 2

helm upgrade demo ./demo --set replicaCount=4. 그다음 helm history demo 로 리비전이 둘이 됐는지, 1번이 superseded 가 됐는지 확인하세요.

일부러 깨뜨린다

없는 이미지로 업그레이드 — 성공했다고 나오는 것을 확인

없는 이미지로 업그레이드해 보세요: --set image.repository=nope/nothing --set image.tag=v0. --wait 없이 하면 helm 이 성공했다고 말합니다 — 그게 이 단계에서 볼 것입니다. 뒤 단계에서 되돌릴 것이므로, 채점은 지금 상태가 아니라 리비전 기록을 봅니다.

--atomic 으로 실패를 잡는다

같은 실수를 --atomic 으로 다시 → /root/helm/05-atomic.txt

이번에는 스케줄될 수 없는 파드를 만들어 봅니다: helm upgrade demo ./demo --set nodeSelector.disktype=nope --atomic --timeout 30s. 존재하지 않는 노드 라벨이라 파드가 Pending 에 머물고, --atomic 이 시간 초과를 잡아 자동으로 되돌립니다. 명령이 실패하는 것이 정답입니다 — 출력을 /root/helm/05-atomic.txt 에 저장하세요(2>&1 | tee).

왜 깨진 이미지가 아니라 nodeSelector 인가: 이 실습의 클러스터는 kwok 이라 파드를 실제로 실행하지 않고 Ready 로 표시합니다. 그래서 이미지가 틀려도 --wait 이 통과합니다. 스케줄 자체가 안 되는 조건이라야 진짜로 멈춥니다.

손으로 되돌린다

helm rollback demo 2

helm rollback demo 2 로 리비전 2의 내용으로 되돌립니다. helm history 에 'Rollback to 2' 가 적힌 새 리비전이 생기고, kubectl get deploy demo -o jsonpath='{.spec.replicas}' 가 4여야 합니다.

무엇이 달라지는지 미리 본다

helm template 두 번을 diff → /root/helm/07-diff.txt

적용 전에 차이를 보는 습관이 사고를 막습니다. helm-diff 플러그인이 없으므로 helm template 두 번의 결과를 diff 로 비교하세요. 결과를 /root/helm/07-diff.txt 에 저장합니다. 차이가 있어야 합니다.

pending 에 갇힌 릴리스를 꺼낸다

pending-upgrade 에 갇힌 릴리스를 꺼내기

먼저 갇힌 상황을 진짜로 만듭니다. 스케줄될 수 없는 파드를 --wait 로 기다리게 해 놓고, 그 helm 프로세스를 도중에 죽이세요.

helm upgrade demo ./demo --set nodeSelector.disktype=nope --wait --timeout 300s &
sleep 12
kill -9 $!

실무에서 helm 프로세스가 중간에 죽거나 CI 가 취소되면 정확히 이 상태가 됩니다. 확인은 helm list -a 로 합니다 — helm list 는 기본값이 pending 을 숨깁니다. 이 상태에서 helm upgrade 를 다시 걸면 another operation (install/upgrade/rollback) is in progress 로 막힙니다.

(시크릿에 kubectl label ... status=pending-upgrade 만 걸어서는 갇히지 않습니다. helm 은 상태를 라벨이 아니라 시크릿 안의 릴리스 JSON 에서 읽으므로, 라벨만 바꾸면 helm list 는 여전히 deployed 라고 답하고 다음 배포도 그대로 나갑니다.)

꺼내는 절차: helm 은 갇힌 리비전 시크릿을 스스로 치우지 않습니다. kubectl get secret -l owner=helm,name=demo,status=pending-upgrade 로 찾아 kubectl delete 로 지운 뒤 마지막 정상 리비전으로 helm rollback 합니다. 끝나면 helm list 가 deployed 이고 pending 라벨이 붙은 시크릿이 하나도 없어야 합니다.