Skip to main content

쿠버네티스 배포와 업데이트

Pod를 배포(업데이트)하는 세 가지 방법
  1. Blue Green Update
  2. Canary Deployment
  3. Rolling Update

Blue/Green Update

  1. 구 버전과 신 버전이 모두 동작한 상태에서 트래픽만 신 버전으로 전환
  2. Rollback이 쉽고, 업데이트 과정에서 소요되는 시간 절약
  3. 하드웨어 리소스 소비: 구, 신 버전의 애플리케이션이 동시 동작해야 함

기존에 실행된 파드 개수만큼 신규 파드를 모두 실행하기 때문에 동일 환경에서의 서버 자원이 두 배로 필요하지만 롤백이 용이하다.

다음과 같은 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