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
매뉴얼한 설치 방법
# 카나리 배포 전략을 사용하는 샘플 앱 배포
## 샘플 매니페스트
kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-rollouts/master/docs/getting-started/basic/rollout.yaml
kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-rollouts/master/docs/getting-started/basic/service.yaml
## 샘플 매니페스트 내용
❯ 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