일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 기록으로 실력을 쌓자
- APM
- Elasticsearch
- 정보처리기사실기 기출문제
- 정보처리기사 실기
- kotlin querydsl
- 정보처리기사 실기 기출문제
- Pinpoint
- PETERICA
- kotlin
- kotlin coroutine
- mysql 튜닝
- CKA
- Kubernetes
- CKA 기출문제
- Spring
- 공부
- aws
- Linux
- CloudWatch
- AI
- MySQL
- 오블완
- 티스토리챌린지
- AWS EKS
- minikube
- Java
- 코틀린 코루틴의 정석
- IntelliJ
- kotlin spring
- Today
- Total
피터의 개발이야기
[kubernetes] Deployment이란? 서비스 중단, 무중단 배포방법 본문
ㅁ 관련 글
ㅇ [Kubernetes] Kubernetes환경에서 graceful shutdown이란
ㄴ Pod가 종료 시 서비스는 50X등의 기타 에러가 발생하면 안된다.
ㄴ 기타 오류를 방지 하기 위한 graceful shutdown에 대해서 정리하였다.
ㅇ [DevOps] 청록색 배포, A/B 테스트 및 카나리아 배포
ㄴ 클러스터 환경에서 배포의 방식을 이야기 할 때에 흔이 이야기되는 용어에 대해서 설명한 글이다.
ㄴ 카나리, 블루그린 배포 방식에 대해서 기본적으로 알아두면 좋다.
ㄴ 카나리는 일정비율로 배포한다는 점에서 RollingUpdate에 상응하고,
블루그린은 A와 B 그룹 중 하나를 통으로 배포한다는 점에서 Restart에 상응한다.
ㅁ 들어가며
애플리케이션 수명주기 관리의 핵심은 신규 애플리케이션의 배포에 있다. Deployment는 그 이름처럼 배포 기능을 세분화하고 있다. 앱의 배포 시 롤링 업데이트, 리스타트를 지원하고 앱 배포 도중 잠시 멈출 수도 롤백할 수도 있다. 이번 글에서는 Deployment의 기능을 쿠버네티스 예제를 기반으로 정리하였다.
ㅁ Deployment란?
디플로이먼트(Deployment) 는 파드와 레플리카셋(ReplicaSet)에 대한 선언적 업데이트를 제공한다. 디플로이먼트는 쿠버네티스에서 상태가 없는 앱을 배포할 때 사용하는 가장 기본적인 컨트롤러이다. 배포 전략(.spec.strategy)으로는 RollingUpdate, Recreate가 있다. RollingUpdate가 기본 값이다.
ㅇ Recreate: spec.strategy.type==Recreate이면 새 파드를 delete하고 생성한다. (서비스 중단 배포)
ㅇ RollingUpdate: 파드를 maxUnavailable 와 maxSurge 기준에 따라 롤링 업데이트 방식으로 업데이트 한다.(서비스 무중단 배포)
아래의 글에서 서비스 무중단 배포에 해당하는 RollingUpdate를 알아보고,
서비스 중단 배포인 Recreate와 더불어 파괴적(disruptive) 업데이트에 대해서 알아보도록 하자.
ㅁ 디플로이먼트 생성
# 테스트를 위한 3대의 nginx 생성 deployment
$ cat nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
# apply
$ k apply -f nginx-deloyment.yaml
deployment.apps/nginx-deployment created
# deployment 확인
$ k get deployments.apps nginx-deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 3m3s
# replicaset 확인
$ k get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-86dcfdf4c6 3 3 3 3m8s
ㅁ 디플로이 업데이트
디플로이먼트는 업데이트되는 동안 일정한 수의 파드만 중단되도록 보장한다. 기본적으로 적어도 의도한 파드 수의 75% 이상이 동작하도록 보장한다(최대 25% 불가).
디플로이먼트 컨트롤러는 각 시간마다 새로운 디플로이먼트에서 레플리카셋이 의도한 파드를 생성하고 띄우는 것을 주시한다. 만약 디플로이먼트가 업데이트되면, 기존 레플리카셋에서 .spec.selector 레이블과 일치하는 파드를 컨트롤 하지만, 템플릿과 .spec.template 이 불일치하면 스케일 다운이 된다.
# nginx 이미지 변경
$ kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1
deployment.apps/nginx-deployment image updated
# 롤링아웃 상태 확인
$ k rollout status deployment nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
deployment "nginx-deployment" successfully rolled out
# deployment 확인
$ k get deployments.apps nginx-deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 57m
# replicaset 확인
$ k get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-848dd6cfb5 3 3 3 7m4s <=== 신규
nginx-deployment-86dcfdf4c6 0 0 0 58m <=== 예전
dds는 업데이트되는 동안 일정한 수의 파드만 중단되도록 보장한다. 기본적으로 적어도 의도한 파드 수의 75% 이상이 동작하도록 보장한다(최대 25% 불가).
# deployment 상세 확인
$ k describe deployments.apps nginx-deployment
Name: nginx-deployment
Namespace: default
CreationTimestamp: Mon, 22 Jan 2024 00:13:39 +0900
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=nginx
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
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-848dd6cfb5 (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 2m11s deployment-controller Scaled up replica set nginx-deployment-848dd6cfb5 to 3
ㅁ 디플로이먼트 롤백
롤백은 앱의 버젼 변경 시
때때로 디플로이먼트의 롤백을 원할 수도 있다. 예를 들어 디플로이먼트가 지속적인 충돌로 안정적이지 않은 경우. 기본적으로 모든 디플로이먼트의 롤아웃 기록은 시스템에 남아있어 언제든지 원할 때 롤백이 가능하다. 다만 이는 디플로이먼트 파드 템플릿 (.spec.template)이 변경되는 경우에만 새로운 수정 버전이 생성된다는 것을 의미한다.
# 잘못된 버젼 업데이트 가정, 1.6.1 아닌 1.61
$ kubectl set image deployment/nginx-deployment nginx=nginx:1.161
deployment.apps/nginx-deployment image updated
# rollout 상태 확인 시 고착 상태
$ kubectl rollout status deployment/nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
# replicaset 확인
$ k get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-79c8677895 1 1 0 2m57s
nginx-deployment-7f857449c7 0 0 0 9m43s
nginx-deployment-848dd6cfb5 3 3 3 34m
# pod 상태확인
$ k get po
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 24h
nginx-deployment-79c8677895-c6jsz 0/1 ImagePullBackOff 0 2m46s <== 신규 image 버젼
nginx-deployment-848dd6cfb5-gwxtl 1/1 Running 0 34m
nginx-deployment-848dd6cfb5-tcrvp 1/1 Running 0 34m
nginx-deployment-848dd6cfb5-xxzdv 1/1 Running 0 34m
# replicaset 상세 확인
$ k describe rs nginx-deployment-79c8677895
Name: nginx-deployment-79c8677895
Namespace: default
Selector: app=nginx,pod-template-hash=79c8677895
Labels: app=nginx
pod-template-hash=79c8677895
Annotations: deployment.kubernetes.io/desired-replicas: 3
deployment.kubernetes.io/max-replicas: 4
deployment.kubernetes.io/revision: 2
Controlled By: Deployment/nginx-deployment
Replicas: 1 current / 1 desired
Pods Status: 0 Running / 1 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=nginx
pod-template-hash=79c8677895
Containers:
nginx:
Image: nginx:1.161
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 52s replicaset-controller Created pod: nginx-deployment-79c8677895-f8m2k
ㅇ 디플로이먼트의 롤아웃 기록 확인
# rollout history 확인 중
$ k rollout history deployment nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
2 <none>
3 <none>
4 <none>
# history revision 상세조회
$ k rollout history deployment/nginx-deployment --revision 2
deployment.apps/nginx-deployment with revision #2
Pod Template:
Labels: app=nginx
pod-template-hash=79c8677895
Containers:
nginx:
Image: nginx:1.161
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
$ k rollout history deployment/nginx-deployment --revision 4
deployment.apps/nginx-deployment with revision #4
Pod Template:
Labels: app=nginx
pod-template-hash=59b5f554d8
Containers:
nginx:
Image: nginx:1.1611
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
ㄴ 쿠버네티스 문서와 비교하면, Change-Cause에 실행했던 명령어 이력이 나타난다. 하지만 deployment에 .metadata.anotation 필드를 정의하지 안하 <node>이라고 표시되었다.
ㄴ 어노테이션 업데이트은 이곳에 있다.
ㄴ revision 상세 조회 시 내용은 확인 가능하였다.
# 수정 버전의 세부 정보 확인
$ kubectl rollout history deployment/nginx-deployment --revision=4
deployment.apps/nginx-deployment with revision #4
Pod Template:
Labels: app=nginx
pod-template-hash=59b5f554d8
Containers:
nginx:
Image: nginx:1.1611
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
# Pod 정상확인
$ k get po
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 34h
nginx-deployment-848dd6cfb5-gpzhs 1/1 Running 0 9h
nginx-deployment-848dd6cfb5-nw8j9 1/1 Running 0 9h
nginx-deployment-848dd6cfb5-qfxxb 1/1 Running 0 9h
ㅇ 이전 버전으로 롤백
# 특정 revision으로 롤백하는 경우
$ kubectl rollout undo deployment/nginx-deployment --to-revision=6
deployment.apps/nginx-deployment rolled back
ㅁ 디플로이먼트 스케일링
# scale out
$ kubectl scale deployment/nginx-deployment --replicas=5
deployment.apps/nginx-deployment scaled
ㅇ autoscale
클러스터에서 horizontal Pod autoscaling를 설정 한 경우 디플로이먼트에 대한 오토스케일러를 설정할 수 있다. 그리고 기존 파드의 CPU 사용률을 기준으로 실행할 최소 파드 및 최대 파드의 수를 선택할 수 있다.
# autoscale 지정
$ k autoscale deployment nginx-deployment --min=2 --max=5 --cpu-percent=80
horizontalpodautoscaler.autoscaling/nginx-deployment autoscaled
ㅇ 비례적 스케일링(Proportional Scaling)
디플로이먼트 롤링업데이트는 여러 버전의 애플리케이션을 동시에 실행할 수 있다. 롤아웃 중 안정성을 위해 ASIS-TOBE사이에 비율을 가지고 균형을 조절할 수 있다.
# 현재 비율 지정
$ k get deployments.apps nginx-deployment -o yaml
.................
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
.................
# 잘못된 이미지 적용
$ kubectl set image deployment/nginx-deployment nginx=nginx:1.161
deployment.apps/nginx-deployment image updated
# replicaset 확인
$ k get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-79c8677895 1 1 0 10h <=== 신규 생성된
nginx-deployment-86dcfdf4c6 2 2 2 66m
# 롤백
$ k rollout undo deployment nginx-deployment
deployment.apps/nginx-deployment rolled back
# replicaset 확인
# t
$ k get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-79c8677895 0 0 0 10h <=== 신규 생성, 0으로 정지
nginx-deployment-86dcfdf4c6 2 2 2 70m <=== 기존 유지
ㄴ 전체 Pod 중 25%, 4개면 1개만 신규 Pod 생성한다.
ㄴ 위의 경우처럼 잘못된 이미지로 인해 정상이 1개발생. 4개중 1개면 작업이 홀링된다.
ㄴ 위험 감지 후 롤백 시 기존에 Pod가 유지된 상태이기 때문에 시스템 안정성을 확보할 수 있다.
ㅁ 디플로이먼트 롤아웃 일시 중지와 재개
디플로이먼트를 업데이트하면 바로 Pod가 업데이트 되었다. 디플로이먼트 롤아웃을 일시 중지 상태로 변경하면 새 업데이트가 있어서 Pod에 영향을 주지 않는다.
일시정지
# 디플로이먼트 일시중지
$ kubectl rollout pause deployment/nginx-deployment
deployment.apps/nginx-deployment paused
# 업데이트 테스트
$ kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
deployment.apps/nginx-deployment image updated
# replicaSet 확인
$ k get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-59b5f554d8 0 0 0 10h <== 기존
nginx-deployment-79c8677895 0 0 0 10h <== 기존
nginx-deployment-848dd6cfb5 0 0 0 10h <== 기존
nginx-deployment-86dcfdf4c6 2 2 2 90m <== 기존
ㅇ 디플로이먼트 일시중지 후 업데이트가 안되는지 확인해 보았다.
ㅇ 기존 replicaset만 있고 새로운 rs가 생성되지 않았다.
# 디플로이먼트를 편집하기
# 기존 리소스를 업데이트를 진행하는 과정 예시
$ kubectl set resources deployment/nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
deployment.apps/nginx-deployment resource requirements updated
ㅇ 바로바로 반영되지 않으니 편하게 deployment를 편집해도 서비스에는 영향이 없다.
ㅇ 이후 업데이트가 완료되면 일시정지를 해제한다.
재개
# 재개
$ kubectl rollout resume deployment/nginx-deployment
deployment.apps/nginx-deployment resumed
# rs 확인
$ k get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-59b5f554d8 0 0 0 10h
nginx-deployment-6bfc44755c 2 2 2 8s <== 신규 rs
nginx-deployment-79c8677895 0 0 0 11h
nginx-deployment-848dd6cfb5 0 0 0 11h
nginx-deployment-86dcfdf4c6 0 0 0 95m
# 업데이트 상태 확인: 완료되었다.
$ k rollout status deployment nginx-deployment
deployment "nginx-deployment" successfully rolled out
# 히스토리 확인
$ k rollout history deployment nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
4 <none>
9 <none>
10 <none>
11 <none>
12 <none>
# 히스토리 상세 확인
$ k rollout history deployment nginx-deployment --revision 12
deployment.apps/nginx-deployment with revision #12
Pod Template:
Labels: app=nginx
pod-template-hash=6bfc44755c
Containers:
nginx:
Image: nginx:1.16.1
Port: 80/TCP
Host Port: 0/TCP
Limits:
cpu: 200m
memory: 512Mi
Environment: <none>
Mounts: <none>
Volumes: <none>
ㅇ 일시정지 시 적용한 resource가 재개와 함께 적용되었다.
ㅇ 적용되용은 history에 반영되고, revision 12에서 확인할 수 있었다.
ㅁ 파괴적(disruptive) 업데이트
지금까지 디플로이먼트는 .spec.strategy.type==RollingUpdate 인 경우였다. 이 방식은 파드를 롤링 업데이트 방식으로 업데이트 하고 maxUnavailable와 maxSurge 를 명시해서 롤링 업데이트 프로세스를 제어할 수 있다. 경우에 따라, 한 번 초기화를 거쳐 업데이트를 해야하는 경우가 있다. DB에 필수 컬럼이 추가되는 경우, 혹은 즉시 업데이트를 수행하는 경우 파괴적 업데이트를 진행할 수 있다.
ㅇ Receate
# deployment 수정
$ k edit deployments.apps nginx-deployment
.... ASIS ....
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
.... TOBE ....
strategy:
type: Recreate
.............
# 업데이트
$ kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
deployment.apps/nginx-deployment image updated
# Pod 조회: 한꺼번에 전체 Pod가 신규 생성됨.
$ k get po
NAME READY STATUS RESTARTS AGE
nginx-deployment-5b8d6b8dbf-dnbms 1/1 Running 0 27s
nginx-deployment-5b8d6b8dbf-sm6rt 1/1 Running 0 27s
nginx-deployment-5b8d6b8dbf-w9cx6 1/1 Running 0 27s
ㅇ Replace --force
# replace --force
$ k replace -f nginx-deloyment.yaml --force
deployment.apps "nginx-deployment" deleted
deployment.apps/nginx-deployment replaced
# Pod 모니터링
$ k get po
NAME READY STATUS RESTARTS AGE
nginx-deployment-58bf96d6bd-kjns7 0/1 Terminating 0 28s
nginx-deployment-58bf96d6bd-qhtjj 0/1 ContainerCreating 0 2s
nginx-deployment-58bf96d6bd-rt8qn 0/1 ContainerCreating 0 2s
nginx-deployment-58bf96d6bd-tlk7p 0/1 Terminating 0 28s
nginx-deployment-58bf96d6bd-vtrx8 0/1 ContainerCreating 0 2s
$ k get po
NAME READY STATUS RESTARTS AGE
nginx-deployment-58bf96d6bd-qhtjj 1/1 Running 0 4s
nginx-deployment-58bf96d6bd-rt8qn 0/1 ContainerCreating 0 4s
nginx-deployment-58bf96d6bd-vtrx8 0/1 ContainerCreating 0 4s
$ k get po
NAME READY STATUS RESTARTS AGE
nginx-deployment-58bf96d6bd-qhtjj 1/1 Running 0 5s
nginx-deployment-58bf96d6bd-rt8qn 1/1 Running 0 5s
nginx-deployment-58bf96d6bd-vtrx8 1/1 Running 0 5s
ㄴ --force는 기본적으로 이전 Object를 delete를 수행한다.
ㄴ deployment를 삭제하고 새로 생성하면서 서비스 중단이 발생한다.
ㅁ 카나리(canary) 디플로이먼트
만약 디플로이먼트를 이용해서 일부 사용자 또는 서버에 릴리스를 롤아웃 하기 위해서는 리소스 관리에 설명된 카나리 패던에 따라 각 릴리스 마다 하나씩 여러 디플로이먼트를 생성할 수 있다. 새 릴리스가 완전히 롤아웃되기 전에 실제 운영 트래픽을 수신할 수 있도록 새로운 애플리케이션 릴리스(파드 템플리트의 이미지 태그를 통해 지정됨)의 카나리 를 이전 릴리스와 나란히 배포하는 것이 일반적이다.
참고로 [DevOps] 청록색 배포, A/B 테스트 및 카나리아 배포 글은 배포 방식에 대한 글이다. 카나리아 배포 방식이 무엇인지 의미를 알 수 있다.
ㅁ 함께 보면 좋은 사이트
'Kubernetes > 기초공부' 카테고리의 다른 글
[MSA] 마이크로서비스 - 분산 트랜잭션 처리를 위한 Saga 패턴 (0) | 2024.02.27 |
---|---|
[kubernetes] command, env 문법 공부 (0) | 2024.01.24 |
[kubernetes] Pod 로그 확인 (0) | 2024.01.20 |
[kubernetes] Pod 한꺼번에 삭제하기 (0) | 2024.01.19 |
[kubernetes] 다중 스케줄러 (0) | 2024.01.18 |