Kubernetes 이야기

Kubernetes의 다양한 배포방식 (3) Canary 배포 본문

Kubernetes/devops

Kubernetes의 다양한 배포방식 (3) Canary 배포

kmaster 2022. 2. 20. 15:12
반응형

Canary 배포

출처 : https://www.weave.works/blog/kubernetes-deployment-strategies

 

Canary 라는 용어는 옛날 탄광에서 나오는 유독 가스에 죽거나 다치는 일을 피하고자 광부들이 유독 가스에 민감한 카나리아를 데리고 갱도로 내려간 일에서 나온 용어로 다가온 위험을 먼저 알려준다는 의미로 사용된다.

 

 

Canary 배포는 새 버전이 모든 사용자에게 릴리스되기 전에 초기 테스트로 일부 사용자에게 점진적으로 롤아웃하는 방법이다. 이 방법의 목적은 성능 메트릭을 수집하고 전체 배포에 대한 사용자의 영향을 예측하기 위해 소수의 사용자를 대상으로 하는 것입니다. 또한 Istio 등을 사용하면 특정 조건 ( 예를 들어,  IE 사용자는 신규앱, 나머지는 기존앱, 특정 IP는 신규앱, 나머지는 기존앱 ) 으로도 사용자 요청을 분배해서 처리할 수 있다.

 

장점

  • 빠른 롤백
  • 실제 사용자 및 사용 사례로 테스트
  • 버그는 소수의 사용자에게만 영향을 미친다.

단점

  • 느린 출시 속도
  • 각 단계의 테스트 및 모니터링 필요
  • 구현하기 쉽지 않음

이제 Canary 배포를 해보자. 시나리오는 아래와 같다.

 

기존앱 : v1, replicas : 3

신규앱 : v2

 

기존앱(v1) 3개가 운영중인 상태에서 신규앱(v2) 를 배포한 후 기존앱에 75%, 새로운앱은 25%의 비율로 부하를 준다고 가정하면 기존앱은 3개가 운영중이므로 신규앱은 replicas를 1로 하면 75:25 비율로 사용자 요청이 분배될 것이다. ( 물론 service 부하 방식에 따라 다를 수는 있다. )

 

APM이나 Istio 의  Kiali와 같은 도구를 사용하면 부하 비율이나 에러율등을 정확히 모니터링하기 쉽다. ( 모니터링 방법에 대해서는 추후 다른 글에서 소개하도록 하겠다. )

 

Blue/Green 배포 시 사용했던 샘플 앱을 다시 배포해 보자. ( label이 틀려졌으니 확인 하자. )

 

Deployment (v1)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-v1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello
      version: v1
  template:
    metadata:
      labels:
        app: hello
        version: v1
    spec:
      containers:
      - name: hello
        image: ghcr.io/kmaster8/hello:v1
        ports:
        - containerPort: 5050

여기서 기존 Blue/Green 에서 못봤던 "version: v1" 이라는 lable이 추가되었다.

 

Service (v1)

apiVersion: v1
kind: Service
metadata:
  name: prod-service
spec:
  type: ClusterIP
  selector:
    app: hello
    version: v1
  ports:
  - protocol: TCP
    port: 5000
    targetPort: 5000

여기서 기존 Blue/Green 에서 못봤던 "version: v1" 이라는 lable이 추가되었다.

 

Ingress (v1)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tomcat
spec:
  rules:
  - host: test.prod.10.60.200.121.sslip.io
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: prod-service
            port:
              number: 5000

 

이제 신규앱 (v2) 를 배포해보자.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello
      version: v2
  template:
    metadata:
      labels:
        app: hello
        version: v2
    spec:
      containers:
      - name: hello
        image: ghcr.io/kmaster8/hello:v2
        ports:
        - containerPort: 5050

 

v2에서는 lable에 version: v2 를 설정한다.

 

v2를 배포해도 prod-service는 아직까지 v1 앱만 연결된 상태이다. 이제 prod-service에 신규앱 (v2) 를 추가 연결해 보자.

kubectl patch service prod-service --patch '{"spec": {"selector": {"version": null}}}'

service의 lable이 기존 v1을 바라봤으나, v1과 v2 모두를 연결해야 하기 때문에 version: null 로 세팅한다.

 

이렇게 설정하면 아래와 같은 그림이 구성된다.

 

구성이 되었으면 브라우저에 접속해서 호출한 후 F5로 새로고침하면 v1과 v2가 보일 것이다. ( 75:25 )

 

이제 v2의 오류가 없다고 판단되면, v2의 Deployment (hello-v2) replica를 3으로 하고, v1의 Deployment (hello-v1)을 삭제하면 아래와 같이 운영되게 될 것이다.

 

kubectl delete deployment hello-v1 && kubectl scale --replicas=3 deployment/hello-v2 && kubectl get deployments

 

NAME                READY   UP-TO-DATE   AVAILABLE   AGE
hello-v2            3/3     3            3           5m3s

 

브라우저에 다시 호출해보면 v2만 출력될 것이다.

반응형
Comments