ローリングアップデート、切り戻し、ブルーグリーン、カナリア
한국어 원문으로 표시합니다.
목표
Deployment 의 롤아웃 파라미터를 조절하고, 리비전을 쌓아 원하는 지점으로 되돌리며, 블루-그린과 카나리를 라벨·셀렉터·레플리카만으로 구성할 수 있게 된다.
왜 중요한가
Deployment 가 ReplicaSet 을 여러 개 관리한다는 사실을 이해하면 나머지가 전부 따라온다. 이미지를 바꾸면 새 ReplicaSet 이 생기고 옛 것은 레플리카 0 으로 남는다. rollout undo 가 즉각적인 이유는 이미지를 다시 받는 게 아니라 이미 있는 ReplicaSet 을 다시 부풀리기 때문이다. revisionHistoryLimit 을 0 으로 두면 그 안전망이 사라진다.
maxSurge 와 maxUnavailable 은 "얼마나 빠르게"와 "얼마나 안전하게"의 트레이드오프다. maxUnavailable: 0 은 배포 중에도 가용 파드 수를 유지하지만 새 파드가 Ready 가 될 때까지 기다려야 하므로 느리다. 그리고 이 안전장치는 Readiness Probe 가 있어야만 의미가 있다 — 프로브가 없으면 컨테이너가 뜬 즉시 Ready 로 간주된다.
블루-그린과 카나리는 별도 CRD 없이 라벨만으로 만들 수 있다. 차이는 Service 셀렉터의 좁기다. 셀렉터에 버전 라벨까지 넣으면 한쪽만 받고(블루-그린), 공통 라벨만 넣으면 양쪽이 다 들어와 개수 비율대로 나뉜다(카나리).
단계
- 네임스페이스
ckad-deploy를 만들고 Deploymentweb을 만든다. 이미지nginx:1.25, 레플리카 4. (컨테이너 이름은nginx가 된다.) web의 전략을RollingUpdate로 두고maxSurge: 1,maxUnavailable: 0으로 설정한다.web의 이미지를nginx:1.26으로 올리고, Deployment 에 애너테이션kubernetes.io/change-cause=nginx 1.26 으로 업데이트를 붙인다.web의 이미지를nginx:1.27로 한 번 더 올리고, 애너테이션kubernetes.io/change-cause=nginx 1.27 으로 업데이트로 갱신한다. 이 시점에 ReplicaSet 이 3개 이상 존재해야 한다.web을 리비전 2 로 되돌린다. 되돌리기도 앞으로 나아가는 변경이므로 리비전 4 가 새로 생기고, 그 리비전의 이미지는nginx:1.26이어야 한다.- 블루-그린을 만든다. Deployment
checkout-blue(레플리카 2, 라벨app=checkout과version=blue, 이미지nginx:1.26)와checkout-green(레플리카 2, 라벨app=checkout과version=green, 이미지nginx:1.27)을 만들고, Servicecheckout(포트 80, targetPort 80)의 셀렉터를app=checkout+version=green으로 준다. - 카나리를 만든다. Deployment
pay-stable(레플리카 9, 라벨app=pay와track=stable, 이미지nginx:1.26)와pay-canary(레플리카 1, 라벨app=pay와track=canary, 이미지nginx:1.27)를 만들고, Servicepay(포트 80, targetPort 80)의 셀렉터는app=pay하나만 준다. web에kubectl rollout pause를 먼저 건 뒤, 이미지를nginx:1.28로 바꾸고revisionHistoryLimit을 3 으로 설정한다. 일시 중지 상태이므로 새 ReplicaSet 은 만들어지지 않아야 한다. (재개하지 않는다. 레플리카 4는 그대로 둔다.)
참고
kubectl patch deployment web -n ckad-deploy -p '{"spec":{"strategy":{"rollingUpdate":{"maxSurge":1,"maxUnavailable":0}}}}'kubectl annotate deployment web -n ckad-deploy kubernetes.io/change-cause='...' --overwritekubectl rollout history deployment/web -n ckad-deploy와--revision=2로 리비전별 내용을 본다.- 흔한 실수 1:
kubectl set image에 컨테이너 이름 대신 Deployment 이름을 쓰는 것.deployment/web nginx=nginx:1.26처럼컨테이너=이미지다. - 흔한 실수 2: 카나리에서 Service 셀렉터에
track까지 넣는 것. 그러면 한쪽만 받으므로 카나리가 아니라 블루-그린이 된다. - 8단계는
pause를 먼저 걸어야 의미가 있다. 순서가 바뀌면 롤아웃이 이미 시작된다.
네임스페이스와 Deployment 만들기
네임스페이스 ckad-deploy 를 만들고 Deployment web 을 만든다. 이미지 nginx:1.25, 레플리카 4. (컨테이너 이름은 nginx 가 된다.)
kubectl create deployment 에 --image 와 --replicas 를 준다. 생성된 Deployment 의 라벨과 셀렉터가 무엇인지 확인해 둔다 — 뒤 단계에서 쓴다.
롤링 업데이트 파라미터 조정
web 의 전략을 RollingUpdate 로 두고 maxSurge: 1, maxUnavailable: 0 으로 설정한다.
spec.strategy.rollingUpdate 밑에 두 값이 있다. kubectl edit 로 고치거나 kubectl patch 에 JSON 을 주면 된다. maxUnavailable: 0 은 배포 중에도 원래 개수를 유지하겠다는 뜻이다.
이미지 갱신과 change-cause 기록
web 의 이미지를 nginx:1.26 으로 올리고, Deployment 에 애너테이션 kubernetes.io/change-cause=nginx 1.26 으로 업데이트 를 붙인다.
kubectl set image deployment/이름 컨테이너=이미지 형태다. 컨테이너 이름을 정확히 써야 한다. CHANGE-CAUSE 는 kubernetes.io/change-cause 애너테이션으로 직접 붙인다.
한 번 더 올려 리비전 쌓기
web 의 이미지를 nginx:1.27 로 한 번 더 올리고, 애너테이션 kubernetes.io/change-cause=nginx 1.27 으로 업데이트 로 갱신한다. 이 시점에 ReplicaSet 이 3개 이상 존재해야 한다.
리비전은 ReplicaSet 으로 남는다. kubectl get rs -n <ns> 로 몇 개가 쌓였는지, kubectl rollout history 로 리비전 번호가 어디까지 왔는지 확인한다.
특정 리비전으로 되돌리기
web 을 리비전 2 로 되돌린다. 되돌리기도 앞으로 나아가는 변경이므로 리비전 4 가 새로 생기고, 그 리비전의 이미지는 nginx:1.26 이어야 한다.
kubectl rollout undo 에 --to-revision=번호 를 준다. 되돌려도 리비전 번호는 줄어들지 않고 새 번호가 붙는다. 어느 리비전이 어떤 이미지였는지는 kubectl rollout history --revision=N 으로 본다.
블루-그린 — Service 셀렉터 전환
블루-그린을 만든다. Deployment checkout-blue(레플리카 2, 라벨 app=checkout 과 version=blue, 이미지 nginx:1.26)와 checkout-green(레플리카 2, 라벨 app=checkout 과 version=green, 이미지 nginx:1.27)을 만들고, Service checkout(포트 80, targetPort 80)의 셀렉터를 app=checkout + version=green 으로 준다.
두 Deployment 는 공통 라벨 하나와 서로 다른 버전 라벨을 갖는다. Service 셀렉터에 버전 라벨까지 넣으면 그쪽만 엔드포인트에 들어온다. Service 를 만든 뒤 셀렉터만 바꿔 보는 것이 이 패턴의 전부다.
카나리 — 레플리카 비율로 트래픽 나누기
카나리를 만든다. Deployment pay-stable(레플리카 9, 라벨 app=pay 와 track=stable, 이미지 nginx:1.26)와 pay-canary(레플리카 1, 라벨 app=pay 와 track=canary, 이미지 nginx:1.27)를 만들고, Service pay(포트 80, targetPort 80)의 셀렉터는 app=pay 하나만 준다.
카나리는 반대로 Service 셀렉터를 좁게 잡아 두 Deployment 의 파드가 모두 들어오게 한다. 그러면 트래픽 비율은 레플리카 개수 비율이 된다. 각 Deployment 에는 구분용 라벨을 따로 둔다.
일시 중지 상태로 변경 모으기 (종합)
web 에 kubectl rollout pause 를 먼저 건 뒤, 이미지를 nginx:1.28 로 바꾸고 revisionHistoryLimit 을 3 으로 설정한다. 일시 중지 상태이므로 새 ReplicaSet 은 만들어지지 않아야 한다. (재개하지 않는다. 레플리카 4는 그대로 둔다.)
kubectl rollout pause 를 먼저 걸면 이후의 템플릿 변경이 즉시 새 ReplicaSet 을 만들지 않고 쌓인다. 순서가 바뀌면 롤아웃이 이미 시작된다. 보관할 이전 ReplicaSet 개수를 정하는 필드도 함께 설정한다.