Handbooks / CI/CD & DevOps / Chapter 9
Deploying to Kubernetes from CI
6 pages · ~5 min✓ Reviewed
Builds on Deployment Strategies. Next up: Monitoring and Rollback.
Rolling Updates and Readiness Gating
1. How a Rolling Update Works
- Default strategy is RollingUpdate
- A new ReplicaSet scales up, the old one scales down
- Pods are replaced gradually, so there is no full outage
| Setting | Meaning | Default |
|---|---|---|
maxSurge | Extra pods above desired | 25%, rounded up |
maxUnavailable | Pods allowed below desired | 25%, rounded down |
2. Zero-Downtime Setup
yaml
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0new pod must be Ready before an old one goes
maxSurge: 0+maxUnavailable: 1needs no extra pods- Capacity drops by one during the rollout
3. Readiness Gating
- A new pod is available only after it passes readiness
- If it never passes, the rollout stalls and old pods keep serving
- No readiness probe: pods are Ready at container start, so a broken build rolls out fully
- Port-only probe passes while dependencies are down
- Probe real dependencies (DB, cache) in the readiness endpoint
progressDeadlineSeconds(default 600s) marks a stuck rollout failed
Mark stuck rollouts
Set minReadySeconds and a suitable progressDeadlineSeconds; no automatic rollback happens.
Helm Charts and Per-Environment Values
1. Chart and Release
- Chart =
Chart.yaml+values.yaml+templates/ - Release = one installed instance of a chart
- Revision history is stored in cluster Secrets
2. Values and Precedence
- Go templates read
.Values; defaults live invalues.yaml - One
values-<env>.yamlper env, only the differences - Typical: replicas, resources, ingress host
bash
helm upgrade --install app ./chart \ -f values-prod.yaml \ --set image.tag=1.4.2
- values.yamllowest
- -f fileslater wins
- --sethighest
3. Preview and Gotchas
| Command | Use |
|---|---|
helm template | render locally |
helm lint | check the chart |
helm diff upgrade | plugin: show changes |
GitOps with Argo CD and Flux
1. The GitOps Loop
- Git is the single source of truth for desired state
- In-cluster controller pulls and reconciles continuously
- CI never runs
kubectl applyon the cluster
- CIbuild image
- Config reponew tag
- Controllerpulls
- Clusterreconciled
2. Argo CD vs Flux
yaml
spec:
source:
repoURL: git@github.com:org/config.git
path: apps/web
targetRevision: main
syncPolicy:
automated: {prune: true, selfHeal: true}Argo CD Application
| Argo CD | Flux | |
|---|---|---|
| Resources | Application | GitRepository + Kustomization / HelmRelease |
| UI | Web UI: Synced / OutOfSync, health | None, CLI and CRDs |
| Strength | App-centric, multi-cluster | Lighter, image-update automation |
3. Gotchas
Canary Releases with Service Mesh or Argo Rollouts
1. Canary with Rollouts
- Canary: 5% → 25% → 50% → 100%, promote if metrics healthy
- Plain Deployment: traffic follows pod count, no exact split
yaml
kind: Rollout
strategy:
canary:
steps:
- setWeight: 10
- pause: {duration: 5m}
- setWeight: 50Rollout CRD replaces Deployment
kubectl argo rollouts get rollout appkubectl argo rollouts promote appkubectl argo rollouts abort app
2. Routers and Analysis
| Router | Weights via |
|---|---|
| Istio | VirtualService |
| Linkerd | SMI |
| NGINX | canary annotations |
| None | replica ratio |
- Rollouts drives routers via
trafficRouting AnalysisTemplate: Prometheus error rate, latency- Failure means auto-abort and rollback
Rollback with kubectl rollout and Deployment Cheat Sheet
1. Inspect and roll back
bash
kubectl set image deploy/app app=img:v2 kubectl rollout status deploy/app kubectl rollout history deploy/app --revision=2 kubectl rollout undo deploy/app --to-revision=1
undo with no flag goes to the previous revision
undore-applies the old pod template only- ConfigMap, Secret and scale changes stay as they are
2. Pause, restart, history
pause, make several edits,resume: one rollout for allrestartreplaces pods with no spec change
bash
kubectl rollout pause deploy/app kubectl rollout resume deploy/app kubectl rollout restart deploy/app
revisionHistoryLimit(default 10) caps undoable revisionskubernetes.io/change-causeannotation labels history- Helm:
helm rollback app <revision>; GitOps: git revert
3. Cheat sheet
| Area | Remember |
|---|---|
| Zero downtime | maxUnavailable: 0 + maxSurge: 1, readiness probes |
Check yourself
A Deployment has 4 replicas and the default rolling update (25% / 25%). What are the most pods that can exist, and the fewest available, during rollout?
- maxSurge 25% of 4 = 1, rounded up, so at most 5 pods.
- maxUnavailable 25% of 4 = 1, rounded down, so at least 3 available.
A broken image that crashes on its first DB query was deployed. The Deployment has no readiness probe. Why did the whole rollout finish?
- Without a probe, a pod is Ready as soon as its container starts.
- So old pods were removed on schedule and the bad build replaced them all.
Argo CD has selfHeal on. Someone runs kubectl edit to change replicas from 3 to 6. What happens?
- Argo CD sees drift and reverts it to the 3 in Git.
- Change the value in Git instead, and roll back with git revert.