kubernetes

argo-rollouts

misankim 2023. 3. 7. 22:36

argo-rollouts

공식 가이드

공식 깃허브

퀵스타트 가이드

helm chart github


# 배포

kubectl create namespace argo-rollouts

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

❯ kubectl get all -n argo-rollouts
NAME                                 READY   STATUS    RESTARTS   AGE
pod/argo-rollouts-57bdd948dc-65nf2   1/1     Running   0          24h

NAME                            TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
service/argo-rollouts-metrics   ClusterIP   100.66.2.126   <none>        8090/TCP   24h

NAME                            READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/argo-rollouts   1/1     1            1           24h

NAME                                       DESIRED   CURRENT   READY   AGE
replicaset.apps/argo-rollouts-57bdd948dc   1         1         1       24h


# argo-rollout kubectl 플러그인 설치

brew install argoproj/tap/kubectl-argo-rollouts

확인
kubectl argo rollouts version

매뉴얼한 설치 방법


# 카나리 배포 전략을 사용하는 샘플 앱 배포


## 샘플 매니페스트



## 샘플 매니페스트 내용

❯ cat rollout.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: rollouts-demo
spec:
  replicas: 5
  strategy:
    canary:
      steps:
      - setWeight: 20
      - pause: {}
      - setWeight: 40
      - pause: {duration: 10}
      - setWeight: 60
      - pause: {duration: 10}
      - setWeight: 80
      - pause: {duration: 10}
  revisionHistoryLimit: 2
  selector:
    matchLabels:
      app: rollouts-demo
  template:
    metadata:
      labels:
        app: rollouts-demo
    spec:
      containers:
      - name: rollouts-demo
        image: argoproj/rollouts-demo:blue
        ports:
        - name: http
          containerPort: 8080
          protocol: TCP
        resources:
          requests:
            memory: 32Mi
            cpu: 5m


❯ cat service.yaml
apiVersion: v1
kind: Service
metadata:
  name: rollouts-demo
spec:
  ports:
  - port: 80
    targetPort: http
    protocol: TCP
    name: http
  selector:
    app: rollouts-demo


배포한 앱 확인
kubectl argo rollouts get rollout rollouts-demo
kubectl argo rollouts get rollout rollouts-demo --watch

## 롤아웃 업데이트

kubectl argo rollouts set image rollouts-demo \
rollouts-demo=argoproj/rollouts-demo:yellow

kubectl argo rollouts get rollout rollouts-demo --watch

## 카나리 배포 롤아웃 진행

kubectl argo rollouts promote rollouts-demo

kubectl argo rollouts get rollout rollouts-demo --watch

## 카나리 배포 롤아웃 중단

kubectl argo rollouts set image rollouts-demo \
rollouts-demo=argoproj/rollouts-demo:red

kubectl argo rollouts abort rollouts-demo

kubectl argo rollouts set image rollouts-demo \
rollouts-demo=argoproj/rollouts-demo:yellow


# argorollout 과 istio 를 통합하여 카나리 배포


## 샘플 매니페스트 작성

vim rollout.yaml

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: my-flask-app
spec:
  progressDeadlineSeconds: 300
  replicas: 3
  revisionHistoryLimit: 3
  selector:
    matchLabels:
      app: my-flask-app
  strategy:
    canary:
      trafficRouting:
        istio:
          virtualService:
            name: vs-my-flask-app
          destinationRule:
            name: dr-my-flask-app
            canarySubsetName: canary
            stableSubsetName: stable
      steps:
      - setWeight: 10
      - pause: {}
  template:
    metadata:
      labels:
        app: my-flask-app
    spec:
      terminationGracePeriodSeconds: 30
      containers:
      - name: my-flask-app
        image: asia.gcr.io/my-project-id/my-flask-app:3.7
        imagePullPolicy: Always
        lifecycle:
          preStop:
            exec:
              command:
              - /bin/sleep
              - "10"
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /
            port: 5000
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /
            port: 5000
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        ports:
        - containerPort: 5000
          protocol: TCP
        resources:
          limits:
            cpu: "500m"
            memory: 512Mi
            ephemeral-storage: 1Gi
          requests:
            cpu: "500m"
            memory: 512Mi
            ephemeral-storage: 1Gi
        env:
          - name: "TYPE"
            value: "prod"​


vim vs.yaml

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: vs-my-flask-app
spec:
  gateways:
  - istio-system/istio-ingressgateway
  hosts:
  - my-flask-app.example.com
  http:
  - match:
    - uri:
        prefix: /
    route:
    - destination:
        host: svc-my-flask-app.my-flask-app.svc.cluster.local
        port:
          number: 80
        subset: stable
      weight: 100
    - destination:
        host: svc-my-flask-app.my-flask-app.svc.cluster.local
        port:
          number: 80
        subset: canary
      weight: 0


vim dr.yaml

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: dr-my-flask-app
spec:
  host: svc-my-flask-app.my-flask-app.svc.cluster.local
  subsets:
  - name: canary
    labels:
      app: my-flask-app
  - name: stable   
    labels:   
      app: my-flask-app


## 카나리 배포 진행

배포
kubectl apply -k ./

배포 상태 확인
kubectl argo rollouts get rollout my-flask-app -w

호출 테스트
-> 10% 트래픽만 전환되었는지 확인
for i in {1..10}; do curl https://my-flask-app.example.com/ ; echo; done;

배포 승격
kubectl argo rollouts promote my-flask-app

다시 호출 테스트
-> 100% 트래픽 전환되었는지 확인
for i in {1..10}; do curl https://my-flask-app.example.com/ ; echo; done;


# argorollout 대시보드 실행

kubectl argo rollouts dashboard
-> 로컬호스트 3100 포트로 접속


# 블루/그린 배포 전략을 사용하는 샘플 앱 배포
-> autoPromotionEnabled 옵션 true 로 설정 시 그린(새 버전) 배포의 상태가 정상일 때, 자동으로 트래픽 전환, false 의 경우 수동으로 promote 시켜줘야함(기본값은 true)
-> previewService 는 active 로 전환 전 미리 접속하여 확인해볼 수 있는 k8s service 이름을 지정하는 것으로 필수는 아님


## 매니페스트 작성

vim rollout.yaml

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: my-flask-app
spec:
  progressDeadlineSeconds: 300
  replicas: 3
  revisionHistoryLimit: 3
  selector:
    matchLabels:
      app: my-flask-app
  strategy:
    blueGreen:
      activeService: svc-my-flask-app
      previewService: svc-my-flask-app-preview
      autoPromotionEnabled: true
  template:
    metadata:
      labels:
        app: my-flask-app
    spec:
      terminationGracePeriodSeconds: 30
      containers:
      - name: my-flask-app
        image: asia.gcr.io/my-project-id/my-flask-app:3.3
        imagePullPolicy: Always
        lifecycle:
          preStop:
            exec:
              command:
              - /bin/sleep
              - "10"
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /
            port: 5000
            scheme: HTTP
          initialDelaySeconds: 60
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /
            port: 5000
            scheme: HTTP
          initialDelaySeconds: 60
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        ports:
        - containerPort: 5000
          protocol: TCP
        resources:
          limits:
            cpu: "500m"
            memory: 512Mi
            ephemeral-storage: 1Gi
          requests:
            cpu: "500m"
            memory: 512Mi
            ephemeral-storage: 1Gi
        env:
          - name: "TYPE"
            value: "prod"


vim svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: svc-my-flask-app
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 5000
  selector:
    app: my-flask-app
  type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
  name: svc-my-flask-app-preview
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 5000
  selector:
    app: my-flask-app
  type: ClusterIP


## 샘플 앱 배포 후 확인

kubectl argo rollouts get rollout my-flask-app -w

Name:            my-flask-app
Namespace:       my-flask-app
Status:          ✔ Healthy
Strategy:        BlueGreen
Images:          asia.gcr.io/my-project-id/my-flask-app:3.3 (stable, active)
Replicas:
  Desired:       3
  Current:       3
  Updated:       3
  Ready:         3
  Available:     3

NAME                                      KIND        STATUS        AGE    INFO
⟳ my-flask-app                            Rollout     ✔ Healthy     186d
├──# revision:22
│  └──⧉ my-flask-app-5b84b4bc65           ReplicaSet  ✔ Healthy     5m19s  stable,active
│     ├──□ my-flask-app-5b84b4bc65-b5bp2  Pod         ✔ Running     5m19s  ready:2/2
│     ├──□ my-flask-app-5b84b4bc65-n7tmr  Pod         ✔ Running     5m19s  ready:2/2
│     └──□ my-flask-app-5b84b4bc65-wnpvm  Pod         ✔ Running     5m19s  ready:2/2
├──# revision:21
│  └──⧉ my-flask-app-6db7fccb66           ReplicaSet  • ScaledDown  11m
├──# revision:20
│  └──⧉ my-flask-app-6ffc95df59           ReplicaSet  • ScaledDown  48d
└──# revision:19
   └──⧉ my-flask-app-5fdb5f85cb           ReplicaSet  • ScaledDown  59d


## 새 버전의 이미지로 rollout 배포(배포 중)

kubectl argo rollouts get rollout my-flask-app -w

Name:            my-flask-app
Namespace:       my-flask-app
Status:          ◌ Progressing
Message:         active service cutover pending
Strategy:        BlueGreen
Images:          asia.gcr.io/my-project-id/my-flask-app:3.3 (stable, active)
                 asia.gcr.io/my-project-id/my-flask-app:3.4 (preview)
Replicas:
  Desired:       3
  Current:       6
  Updated:       3
  Ready:         3
  Available:     3

NAME                                      KIND        STATUS         AGE   INFO
⟳ my-flask-app                            Rollout     ◌ Progressing  186d
├──# revision:23
│  └──⧉ my-flask-app-845c745896           ReplicaSet  ◌ Progressing  23s   preview
│     ├──□ my-flask-app-845c745896-b2fhp  Pod         ✔ Running      22s   ready:1/2
│     ├──□ my-flask-app-845c745896-jpkcm  Pod         ✔ Running      22s   ready:1/2
│     └──□ my-flask-app-845c745896-klp56  Pod         ✔ Running      22s   ready:1/2
├──# revision:22
│  └──⧉ my-flask-app-5b84b4bc65           ReplicaSet  ✔ Healthy      12m   stable,active
│     ├──□ my-flask-app-5b84b4bc65-b5bp2  Pod         ✔ Running      12m   ready:2/2
│     ├──□ my-flask-app-5b84b4bc65-n7tmr  Pod         ✔ Running      12m   ready:2/2
│     └──□ my-flask-app-5b84b4bc65-wnpvm  Pod         ✔ Running      12m   ready:2/2
├──# revision:21
│  └──⧉ my-flask-app-6db7fccb66           ReplicaSet  • ScaledDown   18m
├──# revision:20
│  └──⧉ my-flask-app-6ffc95df59           ReplicaSet  • ScaledDown   48d
└──# revision:19
   └──⧉ my-flask-app-5fdb5f85cb           ReplicaSet  • ScaledDown   59d


## 새 버전의 이미지로 rollout 배포(트래픽 전환 완료)
-> 트래픽 전환 시 일시에 새 버전의 서비스로만 트래픽이 전달됨
-> 블루(이전 버전)과 그린(새 버전)의 트래픽이 섞이지 않음

만약 수동 승격 방식(autoPromotionEnabled: false)인 경우 아래와 같이 승격 커맨드로 수동 승격 진행
kubectl argo rollouts promote my-flask-app

Name:            my-flask-app
Namespace:       my-flask-app
Status:          ✔ Healthy
Strategy:        BlueGreen
Images:          asia.gcr.io/my-project-id/my-flask-app:3.3
                 asia.gcr.io/my-project-id/my-flask-app:3.4 (stable, active)
Replicas:
  Desired:       3
  Current:       6
  Updated:       3
  Ready:         3
  Available:     3

NAME                                      KIND        STATUS        AGE   INFO
⟳ my-flask-app                            Rollout     ✔ Healthy     186d
├──# revision:23
│  └──⧉ my-flask-app-845c745896           ReplicaSet  ✔ Healthy     71s   stable,active
│     ├──□ my-flask-app-845c745896-b2fhp  Pod         ✔ Running     70s   ready:2/2
│     ├──□ my-flask-app-845c745896-jpkcm  Pod         ✔ Running     70s   ready:2/2
│     └──□ my-flask-app-845c745896-klp56  Pod         ✔ Running     70s   ready:2/2
├──# revision:22
│  └──⧉ my-flask-app-5b84b4bc65           ReplicaSet  ✔ Healthy     12m   delay:29s
│     ├──□ my-flask-app-5b84b4bc65-b5bp2  Pod         ✔ Running     12m   ready:2/2
│     ├──□ my-flask-app-5b84b4bc65-n7tmr  Pod         ✔ Running     12m   ready:2/2
│     └──□ my-flask-app-5b84b4bc65-wnpvm  Pod         ✔ Running     12m   ready:2/2
├──# revision:21
│  └──⧉ my-flask-app-6db7fccb66           ReplicaSet  • ScaledDown  19m
└──# revision:20
   └──⧉ my-flask-app-6ffc95df59           ReplicaSet  • ScaledDown  48d


## 새 버전의 이미지로 rollout 배포(블루 버전(이전 버전)의 리소스 종료 진행)

Name:            my-flask-app
Namespace:       my-flask-app
Status:          ✔ Healthy
Strategy:        BlueGreen
Images:          asia.gcr.io/my-project-id/my-flask-app:3.4 (stable, active)
Replicas:
  Desired:       3
  Current:       3
  Updated:       3
  Ready:         3
  Available:     3

NAME                                      KIND        STATUS         AGE   INFO
⟳ my-flask-app                            Rollout     ✔ Healthy      186d
├──# revision:23
│  └──⧉ my-flask-app-845c745896           ReplicaSet  ✔ Healthy      118s  stable,active
│     ├──□ my-flask-app-845c745896-b2fhp  Pod         ✔ Running      117s  ready:2/2
│     ├──□ my-flask-app-845c745896-jpkcm  Pod         ✔ Running      117s  ready:2/2
│     └──□ my-flask-app-845c745896-klp56  Pod         ✔ Running      117s  ready:2/2
├──# revision:22
│  └──⧉ my-flask-app-5b84b4bc65           ReplicaSet  • ScaledDown   13m
│     ├──□ my-flask-app-5b84b4bc65-b5bp2  Pod         ◌ Terminating  13m   ready:0/2
│     ├──□ my-flask-app-5b84b4bc65-n7tmr  Pod         ◌ Terminating  13m   ready:0/2
│     └──□ my-flask-app-5b84b4bc65-wnpvm  Pod         ◌ Terminating  13m   ready:0/2
├──# revision:21
│  └──⧉ my-flask-app-6db7fccb66           ReplicaSet  • ScaledDown   20m
└──# revision:20
   └──⧉ my-flask-app-6ffc95df59           ReplicaSet  • ScaledDown   48d


## 새 버전의 이미지로 rollout 배포(배포 완료)
Name:            my-flask-app
Namespace:       my-flask-app
Status:          ✔ Healthy
Strategy:        BlueGreen
Images:          asia.gcr.io/my-project-id/my-flask-app:3.4 (stable, active)
Replicas:
  Desired:       3
  Current:       3
  Updated:       3
  Ready:         3
  Available:     3

NAME                                      KIND        STATUS        AGE   INFO
⟳ my-flask-app                            Rollout     ✔ Healthy     186d
├──# revision:23
│  └──⧉ my-flask-app-845c745896           ReplicaSet  ✔ Healthy     2m7s  stable,active
│     ├──□ my-flask-app-845c745896-b2fhp  Pod         ✔ Running     2m6s  ready:2/2
│     ├──□ my-flask-app-845c745896-jpkcm  Pod         ✔ Running     2m6s  ready:2/2
│     └──□ my-flask-app-845c745896-klp56  Pod         ✔ Running     2m6s  ready:2/2
├──# revision:22
│  └──⧉ my-flask-app-5b84b4bc65           ReplicaSet  • ScaledDown  13m
├──# revision:21
│  └──⧉ my-flask-app-6db7fccb66           ReplicaSet  • ScaledDown  20m
└──# revision:20
   └──⧉ my-flask-app-6ffc95df59           ReplicaSet  • ScaledDown  48d