쿠버네티스 배포와 업데이트
Pod를 배포(업데이트)하는 세 가지 방법
Blue Green Update
Canary Deployment
Rolling Update
Blue/Green Update
- 구 버전과 신 버전이 모두 동작한 상태에서 트래픽만 신 버전으로 전환
- Rollback이 쉽고, 업데이트 과정에서 소요되는 시간 절약
- 하드웨어 리소스 소비: 구, 신 버전의 애플리케이션이 동시 동작해야 함
기존에 실행된 파드 개수만큼 신규 파드를 모두 실행하기 때문에 동일 환경에서의 서버 자원이 두 배로 필요하지만 롤백이 용이하다.
다음과 같은 deployment, service를 동작하시오.
- blue라는 이름으로 smlinux/nginx:blue 이미지를 가진 Pod 2개를 배포하시오.
- Label은 version=blue을 사용하여 port는 8080 포트를 사용한다.
- app-svc 서비스를 version=blue 레이블로 묶어 NodePort 타입의 서비스 포트 80으로 운영하세요.
- green이라는 이름으로 smlinux/nginx:green 이미지를 가진 Pod 2개를 배포하시오.
- Label은 version=green을 사용하여 port는 8080 포트를 사용한다.
- app-svc의 레이블을 version=green으로 변경하시오.
kubectl config use-context k8s
kubectl create deployment blue --image=smlinux/nginx:blue --port=8080 --replicas=2 --dry-run=client -o yaml > blue.yaml
vi blue.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: blue
spec:
replicas: 2
selector:
matchLabels:
version: blue
template:
metadata:
labels:
version: blue
spec:
containers:
- image: smlinux/nginx:blue
name: nginx
port:
- containerPort: 8080
# 디플로이먼트 생성 및 확인 (blue)
kubectl apply -f blue.yaml
kubectl get deployments.apps blue
kubectl get deployments.apps blue -o wide
# 서비스 노출 (app-svc) 및 확인
kubectl expose deployment blue --type=NodePort --port=80 --target-port=8080 --name=app-svc
kubectl get svc app-svc -o wide
kubectl create deployment green --image=smlinux/nginx:green --port=8080 --replicas=2 --dry-run=client -o yaml > green.yaml
vi green.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: green
spec:
replicas: 2
selector:
matchLabels:
version: green
template:
metadata:
labels:
version: green
spec:
containers:
- image: smlinux/nginx:green
name: nginx
ports:
- containerPort: 8080
# 디플로이먼트 생성 및 확인 (green)
kubectl apply -f green.yaml
kubectl get pod | grep -e green -e blue
kubectl get svc app-svc -o wide
curl node1:31664
BLUE app service: nginx_1.14
# version: blue -> version: green
kubectl edit svc app-svc
...
selector:
version: green
curl node1:31664
GREEN app service: nginx_1.15
Canary Deployment
- 옛날 광부들이 광산에 유독가스 여부를 확인하기 위해 카니라아라는 새를 데리고 들어간 것에 유래
- 기존 버전을 유지한 채로 일부 버전만 신규 버전으로 올려서 버전에 버그나 이상이 없는지 확인
카나리 배포는 무중단 배포로 문제 발생 시 롤백이 용이하여 리스크가 적지만 두 가지 버전을 동시에 관리해야 하는 이슈가 발생하며 원래 필요한 자원의 수보다 많은 자원이 필요하다.
다음과 같은 deployment, service를 동작하시오.
- stable라는 이름으로 smlinux/app:stable 이미지를 가진 Pod를 2개 배포하시오.
- Label은 name=app, version=stable을 사용하며 port는 8080 포트를 사용한다.
- canary-svc 서비스를 name=app 레이블로 묶어 NodePort 타입의 서비스 포트 80으로 운영하시오.
- new라는 이름으로 smlinux/app:new-release 이미지를 가진 Pod 1개를 배포하시오.
- Label은 name=app, version=new를 사용하며 port는 8080 포트를 사용한다.
- canary-svc의 레이블을 version=green으로 변경하시오.
kubectl create deployment stable --image=smlinux/app:stable --replicas=2 --port=8080 --dry-run=client -o yaml > stable.yaml
vi stable.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: stable
spec:
replicas: 2
selector:
matchLabels:
name: app
version: stable
template:
metadata:
labels:
name: app
version: stable
spec:
containers:
- image: smlinux/app:blue
name: app
ports:
- containerPort: 8080
# stable 디플로이먼트 배포
kubectl apply -f stable.yaml
# stable 디플로이먼트 서비스 yaml 파일 생성
kubectl expose deployment stable --type=NodePort --port=80 --target-port=8080 --name=canary-svc --dry-run=client -o yaml > canary-svc.yaml
# 서비스 야믈 파일 수정 (NodePort)
vi canary-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: canary-svc
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8080
selector:
name: app
type: NodePort
# 서비스 생성
kubectl apply -f canary-svc.yaml
# 디플로이먼트, 서비스 생성 확인
kubectl get deployments.apps stable -o wide
kubectl get svc canary-svc -o wide
curl node1:30277
...
APP stable Service
# stable 디플로이먼트의 파드 확인
kubectl get pod | grep stable
# new 디플로이먼트 yaml 파일 생성
kubectl create deployment new --image=smlinux/app:new-release --replicas=1 --port=8080 --dry-run=client -o yaml > new.yaml
vi new.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: new
spec:
replicas: 1
selector:
matchLabels:
name: app
version: new
template:
metadata:
labels:
name: app
version: new
spec:
containers:
- image: smlinux/app:new-release
name: app
ports:
- containerPort: 8080
kubectl apply -f new.yaml
# 서비스의 셀렉터가 name: app 이며
# 두 디플로이먼트가 가진 공통된 레이블 name: app으로
# 두 디플로이먼트에서 실행된 파드의 컨테이너를 모두 보여준다.
curl node1:30277
...
NEW app service
...
APP stable Service
# 무중단 배포, 점진적 교체
kubectl scale deployment new --replicas=2
kubectl scale deployment stable --replicas=1
kubectl get pods | grep -e stable -e new
Deployment
- 애플리케이션 Pod를 배포, ReplicaSet 배포 및 Pod 개수 제어
- new 버전으로의 Update 및 Rolling Update 지원
- History를 이용한 이전 버전으로 Roll back 지원
Deployment Rolling Update
maxUnavailable: 최대 불가
- 사용할 수 없는 최대 Pod 수(내림수)
- 30% 설정 시 사용가능한 Pod의 수는 70% 이상이 되도록 운영
- 업데이트 후 삭제되는 파드의 최대 개수
maxSurge: 최대 서지
- 운영 가능한 최대 Pod 수(올림수)
- 실행할 수 있는 파드의 최대 개수
- 기존 실행되고 있던 파드의 개수에 백분위(올림수)를 사용하여 적용할 수도 있고 숫자로 직접 파드의 개수를 지정할 수도 있다.
progressDeadlineSeconds: 진행 대기시간
- 업데이트 진행되는 것을 대기하는 시간, 이 시간 내 update 못하면 rollback
- 롤링 업데이트 제한 시간, progressDeadlineSeconds를 초과할 시 업데이트를 하지 않고 구버전을 사용
minReadySeconds: 최소 대기 시간
- Pod가 이 시간만큼 대기한 후 running
revisionHistoryLimit: 최대 히스토리로 남길 수 있는 리비전 개수 (--record
)
kubectl get deployments.apps
# maxSurge, maxUnavailable, revisionHistoryLimit, progressDeadlineSeconds 확인
kubectl edit deployments.apps nginx
애플리케이션 rolling update
- deployment 생성:
- name: app-deploy
- image: smlinux/app:v1
- port: 8080
- replicas: 3
- 앞서 생성한 app-deploy의 service 생성:
- name: app-service
- type: NodePort
- port: 80
- app-deploy를 rolling update 및 rollback
- image: smlinux/app:v2
- maxUnavailable: 25%
- maxSurge: 50%
- progressDeadlineSeconds: 300
- app:v1 버전으로 rollback
# app-deploy 디플로이먼트 생성 및 확인
kubectl create deployment app-deploy --image=smlinux/app:v1 --port=8080 --replicas=3
kubectl get deployments.apps app-deploy
kubectl get pod | grep -i app-deploy
...
app-deploy-[replicaSet name]-[Pod name1]
app-deploy-[replicaSet name]-[Pod name2]
app-deploy-[replicaSet name]-[Pod name3]
# app-service 서비스 생성
kubectl expose deployment app-deploy --type=NodePort --port=80 --target-port=8080 --name=app-service
kubectl get svc app-service -o wide
...
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
app-service NodePort 10.103.71.190 <none> 80:31745/TCP 7s app=app-deploy
curl node1:31745
...
This is v1 running in pod app-deploy-5d4889455f-ffjww
curl node2: 31745
...
This is v1 running in pod app-deploy-5d4889455f-rfswr
# new shell (for the purpose of watching pod that is changed)
watch kubectl get pod
kubectl get deployments.apps app-deploy
kubectl edit deployments.apps app-deploy
...
spec:
progressDeadlineSeconds: 300
...
strategy:
rollingUpdate:
maxSurge: 50%
maxUnavailable: 25%
...
- image: smlinux/app:v2
...
# 변경된 레플리카셋 확인 (app:v2)
curl node1:31745
...
This is v2 running in pod app-deploy-7f68466878-5t55g
# 히스토리 확인
kubectl rollout history deployment/app-deploy
...
REVISION CHANGE-CAUSE
1 <none>
2 <none>
# 이전 버전(app:v1)으로 롤백
kubectl rollout undo deployment/app-deploy
# 롤백 확인
curl node1:31745
...
This is v1 running in pod app-deploy-5d4889455f-rkjf2