롤아웃
새 버전을 대상 전체에 한 번에 던지지 않고 범위를 조금씩 넓혀 가며 반영하는 일입니다. 먼저 일부에만 올려 두고 이상이 없는지 지켜본 다음 범위를 넓힙니다. 지켜보는 동안 이상이 보이면 넓히기를 멈추거나 되돌립니다.
상세
급식 메뉴를 바꿀 때 첫날부터 전교생에게 내지 않고 한 학년에게 먼저 내 봅니다. 반응이 괜찮으면 다음 학년으로 넓히고, 탈이 나면 거기서 멈춥니다.
롤아웃은 새 버전이나 변경을 대상 전체에 한 번에 반영하지 않고 정해진 절차에 따라 범위를 넓혀 가는 과정입니다. 한 번의 행위가 아니라 시간에 걸쳐 진행되는 과정이라는 점이 본체입니다. 그래서 진행 중이라는 상태가 생기고, 지금 어디까지 갔는지 물어볼 수 있고, 끝나기 전에 멈추거나 되돌릴 수 있습니다.
대개 세 가지가 붙습니다. 반영할 범위를 쪼개는 것, 쪼갠 사이사이에 지켜보는 것, 이상이 보이면 멈추거나 되돌리는 것입니다. 이 셋이 갖춰져야 넓히는 도중에 판단할 자리가 생깁니다.
flowchart TD
A[일부에 먼저 반영] --> B[정해진 기간 관찰]
B -->|이상 없음| C[범위를 넓힘]
C --> B
C --> E[전체 반영 완료]
B -->|이상 발견| D[멈춤 또는 되돌림]
일부에 먼저 반영하고, 정해진 기간 지켜보고, 괜찮으면 넓히고, 아니면 멈추거나 되돌립니다. 넓히고 다시 지켜보는 이 왕복이 전체에 닿을 때까지 되풀이됩니다. 구글 SRE(Site Reliability Engineering) 책은 자사 서비스의 갱신이 거의 전부 정해진 절차에 따라 점진적으로 진행되며 사이사이에 적절한 검증 단계가 끼워진다고 적습니다. 새 서버를 한 데이터센터의 몇 대에 설치해 정해진 기간 지켜보고, 괜찮아 보이면 그 데이터센터의 모든 기계로, 다시 전 세계의 모든 기계로 넓히는 식입니다.
배경
도는 시스템은 건드리지 마라는 말이 시스템 관리의 오랜 격언입니다. 구글 SRE 책은 어떤 변경이든 위험을 뜻하며 시스템의 신뢰성을 담보하려면 그 위험을 최소화해야 한다고 적습니다. 작은 시스템에 참인 이 말이, 크게 복제되고 전 세계에 흩어진 시스템에서는 갑절로 참이라고도 적습니다.
그렇다고 바꾸지 않을 수는 없습니다. 대상 전체를 한 번에 바꾸면 새 판의 결함이 모든 사용자에게 동시에 나타납니다. 알아차렸을 때는 이미 전부 바뀐 뒤라 되돌리는 것 말고 남은 수가 없습니다. 필요한 것은 결함이 드러날 자리를 작게 잡고, 드러날 때까지 기다릴 시간을 버는 일이었습니다.
그래서 범위를 쪼개고 그 사이에 검증을 끼웠습니다. 같은 책은 새 소프트웨어의 설치를 관리하는 도구가 대개 새로 뜬 서버를 한동안 지켜보며 죽거나 이상하게 굴지 않는지 확인한다고 적습니다. 변경이 검증 기간을 통과하지 못하면 자동으로 롤백됩니다. 이렇게 해서 배포는 한 번 누르고 끝나는 일이 아니라 시작과 진행과 완료라는 상태를 가진 과정이 됐습니다.
갈래
새 판을 어디에 얼마나 먼저 놓고 옛 판을 언제 치우느냐가 축입니다. 겹치는 시간을 아예 두지 않는 쪽부터, 트래픽 비율까지 손으로 조절하는 쪽까지 늘어섭니다.
재생성
쿠버네티스 디플로이먼트의 .spec.strategy.type 을 Recreate 로 두면 새 파드를 만들기
전에 기존 파드를 전부 죽입니다. 두 판이 같이 도는 시간이 없는 대신, 죽인 뒤 새로 뜰
때까지는 도는 파드도 없습니다. 축의 한쪽 끝입니다.
롤링 업데이트
.spec.strategy.type 의 기본값입니다. 옛 레플리카셋을 점차 줄이고 새 레플리카셋을 점차
늘리는 식으로 파드를 갈아치웁니다. 한 번에 얼마나 비워도 되는지는 maxUnavailable 이,
원하는 수보다 얼마나 더 띄워도 되는지는 maxSurge 가 정합니다.
sequenceDiagram
participant 컨트롤러
participant 옛레플리카셋
participant 새레플리카셋
컨트롤러->>새레플리카셋: 파드를 조금 늘림
컨트롤러->>옛레플리카셋: 파드를 조금 줄임
Note over 컨트롤러: maxSurge 와 maxUnavailable 이 폭을 정함
컨트롤러->>새레플리카셋: 남은 만큼 늘림
컨트롤러->>옛레플리카셋: 0 으로 줄임
컨트롤러가 새 쪽을 조금 늘리고 옛 쪽을 조금 줄이는 일을 되풀이합니다. 두 값이 그 한 걸음의 폭을 정합니다. 값은 절대 개수로도 비율로도 적을 수 있고, 둘 다 기본값은 25%입니다.
카나리
일부에게만 새 판을 먼저 내보내고 실제 운영 트래픽 아래에서 지켜보는 방식입니다. 구글 SRE 책은 롤아웃의 첫 단계를 흔히 카나리라고 부른다고 적습니다. 유독 가스를 감지하려고 광부가 탄광에 데리고 들어가던 카나리아에서 온 이름입니다.
쿠버네티스 문서는 디플로이먼트로 이걸 하려면 릴리스마다 디플로이먼트를 따로 만들고 track
같은 레이블로 두 벌을 갈라 두라고 적습니다. 안정 판과 카나리 판의 레플리카 수를 조절하면
각 판이 받는 운영 트래픽의 비율이 정해집니다.
sequenceDiagram
participant 트래픽
participant 안정판
participant 카나리판
트래픽->>안정판: 요청 대부분
트래픽->>카나리판: 요청 일부
Note over 안정판,카나리판: 레플리카 수의 비가 곧 트래픽의 비
Argo Rollouts 의 자동 승격
Argo Rollouts 는 쿠버네티스 컨트롤러와 CRD(Custom Resource Definition, 사용자 정의 리소스) 묶음으로 블루-그린, 카나리, 카나리 분석, 실험, 점진적 전달 기능을 얹습니다. 인그레스 컨트롤러나 서비스 메시와의 연동은 선택입니다. 붙이면 그쪽의 트래픽 조정 능력을 빌려 갱신 중에 트래픽을 새 버전으로 점차 옮깁니다. 여기에 더해 여러 제공자의 지표를 조회해 핵심 수치를 확인한 뒤 승격이나 롤백을 자동으로 굴릴 수 있습니다.
같은 문서는 쿠버네티스 기본 디플로이먼트의 롤링 업데이트가 준비성 프로브로 기본적인 안전 장치를 준다고 적으면서도, 그 전략이 여러 한계를 마주한다고 적습니다. 롤아웃 속도를 제어할 수단이 적고, 새 버전으로 흐르는 트래픽을 제어하지 못하고, 준비성 프로브는 더 깊은 검사나 부하 검사, 한 번만 도는 검사에는 맞지 않고, 외부 지표를 조회할 수 없다는 것입니다.
단계적 출시
서버가 아니라 사용자 기기에 설치되는 쪽에도 같은 축이 있습니다. Google Play Console 도움말은 업데이트를 일부 사용자 비율에만 내보내고 그 비율을 시간에 걸쳐 올리는 방식을 단계적 출시라고 적습니다. 앱을 처음 게시할 때는 쓸 수 없고 업데이트에만 쓸 수 있습니다.
구글 SRE 책도 이 얘기를 합니다. 안드로이드 앱의 새 판을 설치본의 일부에만 업그레이드로 제안하고 그 비율을 100%까지 점차 올리는 식으로 롤아웃할 수 있다고 적습니다. 새 판이 백엔드 서버에 추가 트래픽을 낳는 경우에 특히 도움이 된다고 적습니다. 넓혀 가는 동안 서버가 받는 영향을 관찰해 문제를 일찍 알아챌 수 있기 때문입니다.
예시
kubectl rollout status
쿠버네티스 문서는 디플로이먼트의 롤아웃 상태를 보려면 kubectl rollout status deployment/nginx-deployment 를 실행하라고 적습니다. 출력은 이런 모양입니다.
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
deployment "nginx-deployment" successfully rolled out
첫 줄이 진행 중이라는 상태입니다. 새 레플리카 3개 중 2개까지 갱신됐다고 알립니다. 둘째 줄이 완료 상태입니다. 롤아웃이 과정이라는 것이 이 두 줄에 그대로 드러납니다.
kubectl describe deployments
같은 문서의 kubectl describe deployments 출력에는 지금 어떤 전략으로 어디까지 갔는지가
같이 찍힙니다.
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.16.1
Replicas 줄이 원하는 수와 갱신된 수와 쓸 수 있는 수를 한 줄에 보입니다.
RollingUpdateStrategy 줄에 찍힌 25% 두 개가 앞서 말한 maxUnavailable 과 maxSurge 의
기본값입니다. Image 줄의 nginx:1.16.1 이 이번에 굴린 판입니다.
track 레이블로 가른 카나리
쿠버네티스 문서는 안정 판과 카나리 판을 레이블로 가르는 실물을 보입니다.
안정 판은 track 레이블의 값이 stable 입니다.
name: frontend
replicas: 3
labels:
app: guestbook
tier: frontend
track: stable
image: gb-frontend:v3
새로 내보내는 쪽은 같은 레이블에 다른 값을 답니다.
name: frontend-canary
replicas: 1
labels:
app: guestbook
tier: frontend
track: canary
image: gb-frontend:v4
두 벌의 파드가 겹치지 않게 갈린 상태로 나란히 뜹니다. 문서는 안정 판과 카나리 판의 레플리카 수를 조절해 각 판이 받는 운영 트래픽의 비율을 정할 수 있다고 적습니다. 이 경우에는 3 대 1 입니다.
Play Console 의 단계적 출시
Google Play Console 도움말이 적은 조작은 이렇습니다. Staged rollout 절로 내려가 출시 비율을 입력하고 Start rollout to production 을 누르면 롤아웃이 시작됩니다. 비율을 올릴 때는 Manage rollout 에서 Update rollout 을 골라 비율을 고치고 Confirm update 를 누릅니다.
문제를 발견하면 진행 중인 단계적 출시를 중단할 수 있습니다. 도움말은 중단이 그 판을 겪는 사용자 수를 최소화하는 데 도움이 된다고 적습니다. 중단하면 그 뒤로 이 판을 새로 받는 사용자가 없어집니다. 이미 받은 사용자는 그 판에 그대로 남습니다.
관련 항목
쿠버네티스에서 이것을 다루는 개념과 명령
디플로이먼트 · 레플리카셋 · 파드 · 파드 템플릿 · 리비전 · 레이블 · 릴리스 · kubectl rollout status
이것을 실제로 구현·채택한 플랫폼
쿠버네티스 · Argo Rollouts · 인그레스 컨트롤러 · 서비스 메시 · Google Play Console
이것을 굴리는 방식과 기법
롤링 업데이트 · 재생성 · 블루-그린 배포 · 카나리 배포 · 단계적 출시 · 기능 플래그 · 트래픽 전환
이것의 진행 여부를 판단하는 안전장치
롤백 · 준비성 프로브 · 카나리 분석 · 검증 기간
이것이 속하는 상위 분류
다른 이름: rollout · 롤 아웃