[School Of DevOps] Ultimate Argo Bootcamp: Implementing Canary Release for Prod
Делаю:
2026.01.21
$ mkdir -p ~/tmp/labs/
$ cd ~/tmp/labs/
$ git clone https://github.com/sfd226/argo-labs
$ kubectl create ns prod
$ kubectl config set-context --current --namespace=prod
$ kubectl config get-contexts
Prepare Prod Environment
$ cd argo-labs/
$ rm base/deployment.yaml
$ cat << EOF > base/rollout.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
labels:
app: vote
tier: front
name: vote
spec:
replicas: 4
selector:
matchLabels:
app: vote
strategy:
blueGreen:
autoPromotionEnabled: true
autoPromotionSeconds: 30
activeService: vote
previewService: vote-preview
template:
metadata:
labels:
app: vote
tier: front
spec:
containers:
- image: schoolofdevops/vote:v1
name: vote
imagePullPolicy: Always
resources:
requests:
cpu: "50m"
memory: "64Mi"
limits:
cpu: "250m"
memory: "128Mi"
EOF
$ cat << EOF > base/preview-service.yaml
apiVersion: v1
kind: Service
metadata:
name: vote-preview
labels:
role: vote
spec:
selector:
app: vote
ports:
- port: 80
targetPort: 80
protocol: TCP
nodePort: 30100
type: NodePort
EOF
$ cat << EOF > base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- rollout.yaml
- service.yaml
- preview-service.yaml
EOF
$ mkdir prod
$ cat << EOF > prod/service.yaml
apiVersion: v1
kind: Service
metadata:
name: vote
spec:
ports:
- name: "80"
nodePort: 30200
port: 80
protocol: TCP
targetPort: 80
type: NodePort
EOF
$ cat << EOF > prod/preview-service.yaml
apiVersion: v1
kind: Service
metadata:
name: vote-preview
spec:
ports:
- name: "80"
nodePort: 30300
port: 80
protocol: TCP
targetPort: 80
type: NodePort
EOF
$ cat << EOF > prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../base
namespace: prod
commonAnnotations:
supported-by: sre@example.com
labels:
- includeSelectors: false
pairs:
project: instavote
patches:
- path: service.yaml
- path: preview-service.yaml
EOF
$ kustomize build prod
$ kubectl apply -k prod/
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
vote-7f7d9f97bf-bgk26 1/1 Running 0 16s
vote-7f7d9f97bf-gdv4v 1/1 Running 0 16s
vote-7f7d9f97bf-h98jf 1/1 Running 0 16s
vote-7f7d9f97bf-mjw2m 1/1 Running 0 16s
Create Canary Release
$ cat << EOF > prod/rollout.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: vote
spec:
replicas: 5
strategy:
blueGreen: null
canary:
steps:
- setWeight: 20
- pause:
duration: 10s
- setWeight: 40
- pause:
duration: 10s
- setWeight: 60
- pause:
duration: 10s
- setWeight: 80
- pause:
duration: 10s
- setWeight: 100
EOF
$ cat << EOF > prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../base
namespace: prod
commonAnnotations:
supported-by: sre@example.com
labels:
- includeSelectors: false
pairs:
project: instavote
patches:
- path: service.yaml
- path: preview-service.yaml
- path: rollout.yaml
EOF
$ kustomize build prod
$ kubectl apply -k prod/
$ kubectl argo rollouts dashboard -p 3100
http://localhost:3100
$ vi base/rollout.yaml
Прописываю image:
spec:
containers:
- image: schoolofdevops/vote:v2
$ kubectl apply -k prod
$ kubectl argo rollouts status vote
Paused - CanaryPauseStep
Progressing - more replicas need to be updated
Paused - CanaryPauseStep
Progressing - more replicas need to be updated
Paused - CanaryPauseStep
Progressing - more replicas need to be updated
Paused - CanaryPauseStep
Progressing - more replicas need to be updated
Progressing - updated replicas are still becoming available
Progressing - waiting for all steps to complete
Healthy
$ kubectl argo rollouts get rollout vote
Name: vote
Namespace: prod
Status: ॥ Paused
Message: CanaryPauseStep
Strategy: Canary
Step: 7/9
SetWeight: 80
ActualWeight: 80
Images: schoolofdevops/vote:v1 (stable)
schoolofdevops/vote:v2 (canary)
Replicas:
Desired: 5
Current: 5
Updated: 4
Ready: 5
Available: 5
NAME KIND STATUS AGE INFO
⟳ vote Rollout ॥ Paused 3m48s
├──# revision:2
│ └──⧉ vote-6fd5d7d96d ReplicaSet ✔ Healthy 46s canary
│ ├──□ vote-6fd5d7d96d-9hnlw Pod ✔ Running 46s ready:1/1
│ ├──□ vote-6fd5d7d96d-njzdq Pod ✔ Running 33s ready:1/1
│ ├──□ vote-6fd5d7d96d-mqd76 Pod ✔ Running 21s ready:1/1
│ └──□ vote-6fd5d7d96d-llnfz Pod ✔ Running 9s ready:1/1
└──# revision:1
└──⧉ vote-7f7d9f97bf ReplicaSet ✔ Healthy 3m48s stable
└──□ vote-7f7d9f97bf-d4c8s Pod ✔ Running 3m48s ready:1/1
$ kubectl get endpoints
Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice
NAME ENDPOINTS AGE
vote 10.244.0.22:80,10.244.0.24:80,10.244.0.25:80 + 1 more... 6h42m
vote-preview 10.244.0.22:80,10.244.0.24:80,10.244.0.25:80 + 1 more... 6h42m
Add Ingress Rule with Host based Routing
$ cat << EOF > prod/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: vote
namespace: prod
spec:
ingressClassName: nginx
rules:
- host: 127.0.0.1.nip.io
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: vote
port:
number: 80
EOF
$ cat << EOF > prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../base
- ingress.yaml
namespace: prod
commonAnnotations:
supported-by: sre@example.com
labels:
- includeSelectors: false
pairs:
project: instavote
patches:
- path: service.yaml
- path: preview-service.yaml
- path: rollout.yaml
EOF
$ kubectl apply -k prod
$ kubectl get ing
NAME CLASS HOSTS ADDRESS PORTS AGE
vote nginx 127.0.0.1.nip.io 10.96.228.163 80 2m
$ kubectl describe ing vote
// OK!
http://127.0.0.1.nip.io/
Canary with Traffic Routing
$ cat << EOF > prod/rollout.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: vote
spec:
replicas: 5
strategy:
blueGreen: null
canary:
canaryService: vote-preview
stableService: vote
trafficRouting:
nginx:
stableIngress: vote
steps:
- setCanaryScale:
replicas: 3
- setWeight: 20
- pause:
duration: 10s
- setWeight: 40
- pause:
duration: 10s
- setWeight: 60
- pause:
duration: 10s
- setWeight: 80
- pause:
duration: 10s
- setWeight: 100
EOF
$ kubectl apply -k prod/
Поменять image tag
$ vi base/rollout.yaml
$ kubectl apply -k prod
$ kubectl get ing
NAME CLASS HOSTS ADDRESS PORTS AGE
vote nginx 127.0.0.1.nip.io 10.96.215.21 80 8m12s
vote-vote-canary nginx 127.0.0.1.nip.io 10.96.215.21 80 2m51s
$ kubectl describe ing vote-vote-canary
Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice
Name: vote-vote-canary
Labels: <none>
Namespace: prod
Address: 10.96.215.21
Ingress Class: nginx
Default backend: <default>
Rules:
Host Path Backends
---- ---- --------
127.0.0.1.nip.io
/ vote-preview:80 (10.244.0.50:80,10.244.0.51:80,10.244.0.52:80)
Annotations: nginx.ingress.kubernetes.io/canary: true
nginx.ingress.kubernetes.io/canary-weight: 40
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Sync 6s (x4 over 2m23s) nginx-ingress-controller Scheduled for sync
http://localhost:3100/rollouts/rollout/prod/vote