Kubernetes 이야기

Argo rollout을 통한 CD (Continuous Deployment) 구축하기 (1) - Canary 배포 본문

Kubernetes/devops

Argo rollout을 통한 CD (Continuous Deployment) 구축하기 (1) - Canary 배포

kmaster 2022. 2. 25. 22:37
반응형

Argo Rollout 이란

argo rollout은 Kubernetes에 Blue/Green, Canary 등 배포를 지원하기 위한 Kubernetes controller 와 CRD의 집합체이다.

 

argo rollout은 Ingress Controller, Service Mesh 와 통합되어 업데이트 중에 트랙픽을 새 버전으로 전환시킬 수 있다.

또한 점진적인 배포 조건을 메트릭 쿼리를 사용하여 자동화된 배포/롤백을 구축할 수 있다.

 

주요기능

 

  • Blue/Green 배포
  • Canary 배포
  • 자동화된 롤백 및 배포
  • 맞춤형 메트릭 쿼리를 이용한 점진적 배포
  • Ingress Controller 통합 : Nginx, ALB
  • Service Mesh 통합 : Istio, Linkerd, SMI
  • 메트릭 공급자 통합 : Prometheus, Graphite, Datadog, Kubernetes Jobs

설치

# kubectl create namespace argo-rollouts
# kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml

 

kubectl 플러그인 설치

 

kubectl 플러그인은 선택 사항이지만 kubect cli 에서 롤아웃을 관리하고 시각화하는데 편리한 플러그인이다.

 

# curl -LO https://github.com/argoproj/argo-rollouts/releases/download/v1.2.0-rc2/kubectl-argo-rollouts-linux-amd64
# chmod +x ./kubectl-argo-rollouts-linux-amd64
# mv ./kubectl-argo-rollouts-linux-amd64 /usr/local/bin/kubectl-argo-rollouts

# kubectl argo rollouts version
kubectl-argo-rollouts: v1.2.0-rc2+7b69058
  BuildDate: 2022-02-24T22:32:47Z
  GitCommit: 7b690580f69fd491f40c15b3ff4031f13bdae332
  GitTreeState: clean
  GoVersion: go1.17.6
  Compiler: gc
  Platform: linux/amd64

 

시작하기

argo rollout은 다양한 트랙픽 라우팅 솔루션들 ( Nginx, Istio, ALB 등 ) 과 통합된다. 이번에는 Nginx Ingress Controller 와 Canary 배포 연동되는 방법을 테스트해보자.

 

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: rollouts-demo
spec:
  replicas: 1
  strategy:
    canary:
      canaryService: hello-v2
      stableService: hello-v1
      trafficRouting:
        nginx:
          stableIngress: prod-ingress
      steps:
      - setWeight: 5
      - pause: {}
  revisionHistoryLimit: 2
  selector:
    matchLabels:
      app: rollouts-demo
  template:
    metadata:
      labels:
        app: rollouts-demo
    spec:
      containers:
      - name: rollouts-demo
        image: ghcr.io/kmaster8/hello:v1
        ports:
        - name: http
          containerPort: 5000
          protocol: TCP
        resources:
          requests:
            memory: 32Mi
            cpu: 5m

 

이제 실제 hello-v1 서비스를 위한 Ingress를 생성해 보자.

 

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

 

이제 service를 생성해 보자.

apiVersion: v1
kind: Service
metadata:
  name: hello-v1
spec:
  type: ClusterIP
  selector:
    app: rollouts-demo
  ports:
  - protocol: TCP
    port: 5000
    targetPort: 5000
---
apiVersion: v1
kind: Service
metadata:
  name: hello-v2
spec:
  type: ClusterIP
  selector:
    app: rollouts-demo
  ports:
  - protocol: TCP
    port: 5000
    targetPort: 5000

 

배포된 상태를 확인해 보면 아래와 같다.

 

# kubectl get ro -n test
NAME            DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
rollouts-demo   1         1         1            1           59s

# kubectl get svc -n test
NAME       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
hello-v1   ClusterIP   10.111.83.68   <none>        5000/TCP   56s
hello-v2   ClusterIP   10.97.143.51   <none>        5000/TCP   56s

# kubectl get ing -n test
NAME                                CLASS    HOSTS                              ADDRESS        PORTS   AGE
prod-ingress                        <none>   test.prod.10.60.200.121.sslip.io   10.109.32.60   80      62s
rollouts-demo-prod-ingress-canary   <none>   test.prod.10.60.200.121.sslip.io                  80      49s

 

여기서 ingress를 확인해야 한다. prod-ingress라는 이름으로 한개를 생성했지만,  rollout-demo-prod-ingress-canary라는 Canary ingress controller가 자동으로 복제된다. 이 ingress는 카나리아 트래픽 분할 역활을 하는 ingress 이다. 이 ingress의 이름 규칙은 <ROLLOUT-NAME>-<INGRESS-NAME>-canary 라는 이름으로 생성된다.

 

rollout-demo-prod-ingress-canary의 상세정보를 보면 아래와 같다.

k describe ing -n test rollouts-demo-prod-ingress-canary
Name:             rollouts-demo-prod-ingress-canary
Namespace:        test
Address:          10.109.32.60
Default backend:  default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
  Host                              Path  Backends
  ----                              ----  --------
  test.prod.10.60.200.121.sslip.io
                                    /   hello-v2:5000 (172.32.139.179:5000)
Annotations:                        kubernetes.io/ingress.class: nginx
                                    nginx.ingress.kubernetes.io/canary: true
                                    nginx.ingress.kubernetes.io/canary-weight: 0
Events:
  Type    Reason  Age                From                      Message
  ----    ------  ----               ----                      -------
  Normal  Sync    21m (x2 over 22m)  nginx-ingress-controller  Scheduled for sync
  Normal  Sync    21m (x2 over 22m)  nginx-ingress-controller  Scheduled for sync
  Normal  Sync    21m (x2 over 22m)  nginx-ingress-controller  Scheduled for sync

 

위와 같이 실제 호출되는 domain ( http://test.prod.10.60.200.121.sslip.io/ )은 prod-ingress와 동일하지만 canary-weight: 0으로 설정됨에 따라 해당 ingress는 실제 호출 시 연결되지 못한다.

 

# kubectl argo rollouts get rollout rollouts-demo -n test
Name:            rollouts-demo
Namespace:       test
Status:          ✔ Healthy
Strategy:        Canary
  Step:          2/2
  SetWeight:     100
  ActualWeight:  100
Images:          ghcr.io/kmaster8/hello:v1 (stable)
Replicas:
  Desired:       1
  Current:       1
  Updated:       1
  Ready:         1
  Available:     1

NAME                                      KIND        STATUS     AGE  INFO
⟳ rollouts-demo                           Rollout     ✔ Healthy  20m
└──# revision:1
   └──⧉ rollouts-demo-6c75c64f5           ReplicaSet  ✔ Healthy  20m  stable
      └──□ rollouts-demo-6c75c64f5-ltm7c  Pod         ✔ Running  20m  ready:1/1

 

우선 v1 의 앱을 브라우저 통해서 호출해보자.

자, 이제 v2 앱을 배포해 보자.

 

# kubectl argo rollouts set image rollouts-demo rollouts-demo=ghcr.io/kmaster8/hello:v2 -n test
rollout "rollouts-demo" image updated

# kubectl argo rollouts get rollout rollouts-demo -n test
Name:            rollouts-demo
Namespace:       test
Status:          ॥ Paused
Message:         CanaryPauseStep
Strategy:        Canary
  Step:          1/2
  SetWeight:     5
  ActualWeight:  5
Images:          ghcr.io/kmaster8/hello:v1 (stable)
                 ghcr.io/kmaster8/hello:v2 (canary)
Replicas:
  Desired:       1
  Current:       2
  Updated:       1
  Ready:         2
  Available:     2

NAME                                       KIND        STATUS     AGE  INFO
⟳ rollouts-demo                            Rollout     ॥ Paused   27m
├──# revision:2
│  └──⧉ rollouts-demo-56f4f7dc9b           ReplicaSet  ✔ Healthy  26s  canary
│     └──□ rollouts-demo-56f4f7dc9b-8l72h  Pod         ✔ Running  25s  ready:1/1
└──# revision:1
   └──⧉ rollouts-demo-6c75c64f5            ReplicaSet  ✔ Healthy  27m  stable
      └──□ rollouts-demo-6c75c64f5-ltm7c   Pod         ✔ Running  27m  ready:1/1

 

배포 후 rollout-demo-prod-ingress-canary의 상세정보를 보면 아래와 같다.

 

# kubectl describe ing -n test rollouts-demo-prod-ingress-canary
Name:             rollouts-demo-prod-ingress-canary
Namespace:        test
Address:          10.109.32.60
Default backend:  default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
  Host                              Path  Backends
  ----                              ----  --------
  test.prod.10.60.200.121.sslip.io
                                    /   hello-v2:5000 (172.32.139.180:5000)
Annotations:                        kubernetes.io/ingress.class: nginx
                                    nginx.ingress.kubernetes.io/canary: true
                                    nginx.ingress.kubernetes.io/canary-weight: 5
Events:
  Type    Reason  Age                From                      Message
  ----    ------  ----               ----                      -------
  Normal  Sync    64s (x3 over 28m)  nginx-ingress-controller  Scheduled for sync
  Normal  Sync    64s (x3 over 28m)  nginx-ingress-controller  Scheduled for sync
  Normal  Sync    64s (x3 over 28m)  nginx-ingress-controller  Scheduled for sync

 

canary-weight: 5로 변경됨을 확인할 수 있다. 실제 브라우저를 통해 호출해 보면 v1과 v2 가 95% 대 5% 비율로 보일 것이다.

 

 

Kubernetes의 일반적인 canary배포는 pod 개수로 비율을 조절하지만, nginx ingress를 통한 canary배포는 pod의 개수와 상관없이 비율을 조정할 수 있다.

 

이제, v2버전으로 모두 이전해 보자.

 

# kubectl argo rollouts promote rollouts-demo -n test
rollout 'rollouts-demo' promoted

# kubectl argo rollouts get rollout rollouts-demo -n test
# kubectl argo rollouts get rollout rollouts-demo -n test
Name:            rollouts-demo
Namespace:       test
Status:          ✔ Healthy
Strategy:        Canary
  Step:          2/2
  SetWeight:     100
  ActualWeight:  100
Images:          ghcr.io/kmaster8/hello:v2 (stable)
Replicas:
  Desired:       1
  Current:       1
  Updated:       1
  Ready:         1
  Available:     1

NAME                                       KIND        STATUS         AGE    INFO
⟳ rollouts-demo                            Rollout     ✔ Healthy      35m
├──# revision:2
│  └──⧉ rollouts-demo-56f4f7dc9b           ReplicaSet  ✔ Healthy      8m12s  stable
│     └──□ rollouts-demo-56f4f7dc9b-8l72h  Pod         ✔ Running      8m11s  ready:1/1
└──# revision:1
   └──⧉ rollouts-demo-6c75c64f5            ReplicaSet  • ScaledDown   35m
      └──□ rollouts-demo-6c75c64f5-ltm7c   Pod         ◌ Terminating  35m    ready:1/1

 

이제 v1을 모두 terminaing 되고 v2가 승격됨을 확인할 수 있다. 브라우저에서 실제 호출하면 이제 v2 앱만 보이게 된다.

 

 

반응형
Comments