쿠버네티스의 롤링 업데이트롤아웃과 롤백을 이용한 디플로이먼트 업데이트롤백컨피그맵을 사용시 롤아웃, 롤백디플로이먼트의 롤링 업데이트 설정롤링 업데이트 정의에서 파드 스케일링 속도 조정롤 아웃 속도 조정데몬셋과 스테이트풀셋의 롤링 업데이트스테이트풀셋 롤아웃롤링업데이트 정리릴리스 전략 이해하기블루그린 배치단점
컨테이너에서 실행되는 애플리케이션의 릴리스 주기에는 여러 기반 이미지의 릴리스 주기가 합쳐짐
예를 들어 도커 허브의 운영체제 공식 이미지, 플랫폼의 SDK 및 런타임의 이미지 등은 매달 새 버전이 릴리즈됨
이런 업데이트에는 중요한 보안 패치 등이 포함될 수 있기 때문에 업데이트된 기반 이미지를 반영하는 이미지 빌드 절차를 구축해 두어야 함
쿠버네티스의 롤링 업데이트
롤아웃
: 레플리카셋을 새로 만들어 레플리카 수를 지정된 숫자만큼 늘린 후 기존 레플리카의 레플리카 수를 0으로 낮추는 식으로 이루어짐- 디플로이먼트 정의가 변경될 때마다 항상 롤아웃이 일어나는 것은 아니다. 롤아웃은 파드의 정의가 변경될 때만 일어난다. 기존 레플리카 수 등 레플리카셋을 유지하며 반영할 수 있는 변경에는 롤아웃이 일어나지 않는다.
# 디플로이먼트의 롤아웃 히스토리를 확인 kubectl rollout history deploy/web # 이미지 변경 -> 파드 정의가 변경됨 kubectl set image deployment/vweb web=kiamol/ch09-vweb:v2 # 파드정의가 변경도면 디플로이먼트는 새로운 레플리카셋 생성 kubectl get rs -l app=vweb
- 롤아웃은 명확하게 어떤 객체를 가리키지 않는다는 점에서 여타 API와 다른 점이 많음. 하지만 롤아웃은 애플리케이션 릴리스를 관리하는 데 중요한 도구. 롤아웃을 이용하여 릴리스 히스토리를 관리하고 이전 릴리스로 돌아갈 수도 있다.
롤아웃과 롤백을 이용한 디플로이먼트 업데이트
리비전 번호만 써져 있는 롤아웃 히스토리는 그리 큰 도움이 되지 않음
구체적으로 어떤 변경이 있었고 어느 레플리카셋이 어떤 리비전에 해당하는지 알수 없기 때문
버전번호를 넣은 레이블을 정의하여 이를 레플리카셋에 부여한다면 업데이트 내용을 추적하기 수월함
# 디플로이먼트 변경에 record 옵션을 사용 kubectl apply -f vweb/update/vweb-v11.yaml --record # 레플리카셋의 정보에서 레이블을 확인 kubectl get rs -l app=web --show-labels # 현재 롤아웃 상태를 확인 kubectl rollout status deploy/web # 롤아웃 히스토리를 확인 kubectl rollout history deploy/web # 현재 레플리카셋의 롤아웃 리비전을 출력 kubectl get rs -l app=vweb -o=custom-columns=NAME:metadata.name,REPLICAS:.status.replicas, REVISION:metadata.annotations.deployment\.kubernetes\.io/revision
- 롤아웃 리비전과 레플리카셋 간 관계를 알아내려면 복잡한 JSONPath를 입력해야 하는 것이 단점
record
플래그는 롤아웃을 실행시킨 kubecetl 명령을 저장하는 기능
주의점
- 쿠버네티스 사용에 능숙해질수록 모든 리소스 정의에 넣을 공통 레이블이 필요해질 것. 레이블과 레이블 셀렉터는 객체를 찾고 관리하는 데 반드시 필요한 핵심기능임
- 셀렉터는 디플로이먼트를 다시 생성하지 않는 한 변경할 수 없다.
- 먼저 셀렉터에서 사용할 레이블을 신중하게 정의하되, 업데이트를 관리하기 수월하도록 레이블을 추가 정의하는 것이 원칙임.
- 디플로이먼트는 여러 개의 이전 버전 레플리카셋을 유지할 수 있지만(기본값 열개), 우리가 파드 템플릿 해시 만으로 레플리카셋의 각 버전을 식별하기는 어렵다. ⇒ 레플리카셋에 version 레이블을 같이 넣기. 파드 버전을 확인하기 위해
롤백
kubectl 명령으로 롤아웃 히스토리를 확인할 수 있고, 진행 중인 롤아웃을 중단하거나 이전 리비전으로 롤백할 수도 있다.
바로 이전 리비전으로 돌아가는 명령은 간단하지만, 특정 리비전으로 롤백하려면 조금 복잡한 JSONPath를 활용해야 한다.
# 리비전 히스토리 확인 kubectl rollout history deploy/web # 레플리카셋의 리비전을 확인 kubectl get rs -l app=vweb -o=custom-columns=NAME:metadata.name,REPLICAS:.status.replicas, REVISION:metadata.annotations.deployment\.kubernetes\.io/revision # 롤백했을 때의 예측 결과를 확인 kubectl rollout undo deploy/web --dry-run # 리비전 2로 롤백을 시작 kubectl rollout undo deploy/web --to-revision=2
- 릴리스 절차는 단순하다. 디플로이먼트는 레플리카셋을 생성하거나 재활용하고, 파드 수를 필요에 따라 조정한다. 그리고 레플리카셋에 변동이 생기면 이를 롤아웃으로 기록한다.
컨피그맵을 사용시 롤아웃, 롤백
컨피그맵을 릴리스에 포함시키면, 설정값만 변경하는 릴리스는 롤아웃 기록이 남지 않아 롤백이 불가능함
컨피그맵을 업데이트하면 애플리케이션 동작이 변화함. 그러나 이 업데이트가 디플로이먼트의 변경이 아니므로 이 설정값이 문제를 일으켜도 되돌아갈 리비전이 없다. ⇒ 이 방식을
핫 리로드
방식이라 함- 설정값만 업데이트 할 때는 롤아웃이 발생하지 않으므로 애플리케이션에서 지원만 한다면 아주 매끄러운 업데이트가 가능하다
- 기존 파드와 컨테이너가 그대로 남아 있으므로 서비스 중단의 위험이 아예 없기 때문
- 다만 롤백이 불가능하다는 반대급부가 있으므로 장단점을 잘 저울질해서 선택해야 함
- 컨피그맵과 비밀값을 모두 불변적 요소로 간주하고, 객체이름을 버전 명명 규칙을 따라 짓고 그 내용은 수정하지 않는 방식으로 하면 설정값이 변경될 때는 다른 이름으로 새 객체를 만든 후 이를 참조하도록 디플로이먼트를 업데이트 → 롤아웃
디플로이먼트의 롤링 업데이트 설정
디플로이먼트의 두 가지 업데이트 전략
- 롤링업데이트 : 기존 레플리카셋의 파드 수 차츰 줄이고, 새로운 레플리카셋의 파드 수를 늘려 나가는 식
- 리크레이트 : 기존 레플리카셋의 파드 수 0까지 감소한 후 새 레플리카셋의 파드 수가 증가
정말 불가피하게 리크레이트 전략을 사용해야 한다면 업데이트를 배치하기 전에 확실히 테스트를 마쳐야 함. 아니라면 애플리케이션이 완전히 사용할 수 없는 상태에 빠지기 때문
apiVersion: apps/v1 kind: Deployment metadata: name: vweb labels: kiamol: ch09 spec: replicas: 3 selector: matchLabels: app: vweb strategy: type: Recreate template: metadata: labels: app: vweb version: v2 spec: containers: - name: web image: kiamol/ch09-vweb:v2 ports: - name: http containerPort: 80
롤링 업데이트 정의에서 파드 스케일링 속도 조정
maxUnavailable
: 기존 레플리카셋의 스케일링 속도를 조절하는 값. 정확히 말하면 업데이트 동안 사용할 수 없는 파드의 최대 수. 기존 레플리카셋에서 동시에 종료되는 파드 수
maxSurge
: 새 레플리카셋의 스케일링 속도를 조절하는 값. 정확하게는 업데이트 동안 생기는 잉여 파드의 최대 개수. 새 레플리카셋에서 동시에 함께 시작되는 파드 수
maxUnavilable | maxSurge | ㅤ |
1 | 0 | 삭제 - 후 생성 |
0 | 1 | 생성 후 삭제 |
1 | 1 | 동시-삭제-및-생성 |
롤 아웃 속도 조정
minReadySeconds
: 신규 파드의 상태가 안정적인지 확인할 수 있는 시간 여유. 지정된 값의 시간 동안(단위:초) 오류로 종료되는 컨테이너가 없어야 파드를 안정적으로 판단
progressDeadlineSeconds
: 신규 파드의 상태를 실패로 간주하는 타임아웃 시간. 기본값은 600이므로 10분 안에 파드 상태가 안정되지 않으면 해당 파드의 상태를 실패로 간주
CrashLoopBackOff 상태 : 쿠버네티스는 파드가 실패하면 새로운 파드를 만들어 계속 재시도하게 되는데, 이 때 노드의 CPU 자원이 바닥나지 않도록 재시작 사이에 일정 시간 간격을 둠. 이 간격을 백오프 시간이라 함. 시작과 비정상 종료를 반복하는 상황임
그리고 파드의 실패가 거듭될 때마다 이 간격이 지수적으로 증가.
데몬셋과 스테이트풀셋의 롤링 업데이트
데몬셋과 스테이트풀셋도 두가지 업데이트 전략이 있음
- 롤링업데이트
- 온딜리트 : 각 파드의 업데이트 시점을 직접 제어해야 할 때 사용하는 전략. 업데이트를 배치하면 컨트롤러가 기존 파드를 종료하지 않고 그대로 둔 채 파드를 주시. 그러다 다른 프로세스가 파드를 삭제하면 새로운 정의를 따른 대체 파드를 생성
- 제거되기 전에 가지고 있는 데이터를 모두 디스크에 기록해야 하는 파드를 관리하는 스테이트풀셋을 생각해 보자.
- 다음 파드가 사용할 수 있도록 종료 전 전용 하드웨어에서 접속을 해제해야 하는 파드를 관리하는 데몬셋은 어떤가
# 데몬셋 업데이트 kubectl apply -f todo-list/proxy/update/ningx-rollingUpdate.yaml # 파드의 업데이트 상태 확인 kubectl get pods -l app=todo-proxy --watch
- —watch 플래그는 변경사항을 모니터링할 때 유용함
스테이트풀셋 롤아웃
- 스테이트풀셋은 롤아웃 과정에 설정할 수 있는 선택지가 하나뿐.
- 업데이트 시 마지막 파드부터 롤아웃을 시작해서 첫 번째 파드까지 진행됨.
- 동시에 업데이트 되는 파드 수는 항상 하나기에, maxSurge, maxUnavailable 설정값은 사용 불가
- 대신 partition 값을 사용하여 전체 파드 중 업데이트해야 하는 파드의 비율은 설정할 수 있음
- partition 값을 차츰 줄여 가며 릴리스의 페이스를 조절하다 업데이트가 안정적임을 확인한 후 partition 값을 0으로 설정해서 전체 스테이트풀셋 업데이트.
롤링업데이트 정리
- 디플로이먼트와 데몬셋, 스테이트풀셋은 모두 기본적으로 롤링 업데이트 전략을 사용함
- 큰 틀에서 볼 때 이들 리소스에서 롤링 업데이트는 기존 파드를 점진적으로 변경된 정의의 파드로 대체해 나간다는 점에서 비슷함.
- 각각의 컨트롤러가 서로 다른 목표를 위해 다른 방식으로 동작하기 때문에 세세한 동작 방식에는 조금씩 차이는 있지만, 애플리케이션이 공통으로 만족해야 하는 조건이 있다. 여러 가지 버전이 동시에 동작할 수 있어야 한다는 것
- 그러나 이것이 가능하지 않을때가 잇는데 이때의 업데이트 전략도 있음
릴리스 전략 이해하기
여러 버전을 동시에 실행할 수 없는 상황에서는 블루-그린 배치 전략을 고려해 볼 만하다.
블루그린 배치
블루 그린 배치란 구 버전과 신 버전 애플리케이션을 동시에 배치하되 한쪽만 활성화시킨다는 간단한 개념.
- 스위치를 껐다 켜듯이 활성화된 버전을 선택할 수 있음. 서비스에서 트래픽 전달 대상 파드를 결정하는 레이블 셀렉터를 수정하기만 하면 됨
- 클러스터 용량이 완전한 애플리케이션 두 벌을 동시에 실행할 수 있을만큼 충분해야 함
단점
- 컴퓨팅 파워를 많이 소모하고(파드가 다 준비되어 있으니)
- 업데이트에 여러 단계가 필요하며
- 롤아웃 히스토리가 남지 않는다는 점