Skip to content

Deploy an update

Most deploys are one git commit. ArgoCD sees the change, applies it, the pods roll. No buttons pressed, no SSH, no kubectl apply.

The three shapes of "an update"

Nearly every change falls into one of these:

1. Bumping an image version (most common)

Example: a dev team shipped 4.99.11.0-wecare and you want to deploy it.

bash
# Edit the image tag in the relevant manifest
$EDITOR manifests_v1/app-constructs/ecommercen-clients/wecare/adveshop4/base/kustomization.yaml

Find the images: section:

yaml
images:
  - name: ecommercen/adveshop4-php_fpm
    newTag: 4.99.10.0-wecare    # ← change this
  - name: ecommercen/adveshop4-php_cli
    newTag: 4.99.10.0-wecare

Bump to the new tag, save, then:

bash
git add -p                              # review diff line by line
git commit -m "[App: wecare] Bump image to 4.99.11.0-wecare"
git push

Within ~1 minute ArgoCD picks up the push. The Deployment's spec.template.spec.containers[*].image changes. Kubernetes' Deployment controller rolls pods one-by-one (maxSurge: 50%, maxUnavailable: 0 → always at least the old count running until new ones are Ready).

2. Changing a config setting

Example: wecare needs pm.max_children raised from 50 to 75.

bash
$EDITOR manifests_v1/app-constructs/ecommercen-clients/wecare/adveshop4/base/app.yaml
# find the `app-web-fpm-www-cm` ConfigMap, edit the value

Commit + push. ArgoCD applies the new ConfigMap. Stakater Reloader notices the ConfigMap changed and triggers a rolling restart of the Deployment that mounts it. No manual pod action needed.

3. Upgrading an upstream component (ArgoCD, Longhorn, etc)

We have a scripted workflow for this:

bash
python3 scripts/check-updates.py      # see what's outdated
python3 scripts/do-updates.py --dry-run   # preview
python3 scripts/do-updates.py         # apply all safe updates + commit
git push origin main

The scripts read scripts/apps.yaml (single source of truth for versions). They know which updates are safe-auto (patch bumps), which need a human (major bumps, skip_major: true), and which are manual-only (e.g., operators that require migration steps).

See Tracked apps for the list.

How to tell it landed

Three signals, in increasing confidence order:

1. ArgoCD status

bash
argocd app get app-wecare-adveshop4-prod
# or click the app in the web UI

Look for:

  • Sync Status: Synced
  • Health Status: Healthy (Progressing while rolling out, which is fine)

2. Pod age / image

bash
kubectl -n ecommercen-clients-wecare \
  get pods -l app.kubernetes.io/name=app-web -o wide

New pods should have a recent AGE and the new image. If any pod is still on the old image after a few minutes, the rollout got stuck — see Check app status.

3. Live behaviour

Hit the site, watch Grafana. For wecare, open the Operations dashboard — the P95 latency shouldn't spike, 5xx rate should stay near 0 through the rollout.

Rolling back

The standard answer is not kubectl rollout undo. That works but gets reverted by ArgoCD within a minute because it doesn't match the repo.

The right answer: git revert the commit, push. Same flow as a deploy, just backwards.

bash
git log --oneline | head -5          # find the commit to undo
git revert <commit-sha>
git push

ArgoCD syncs the revert; pods roll back to the previous image. Full audit trail in git.

When things get ambitious

ChangeShapeRisk
Image tag bump (patch version)Simple commitLow — rolling update, easy revert
Image tag bump (major version)Simple commit but test staging firstMedium — may require DB migration
New env varCommit + Reloader restartLow
KEDA scaling thresholdCommit, next scale event picks it upLow
New Ingress hostnameCommit + Cloudflare DNS recordMedium — DNS propagation
New client onboardingSee Add a clientMedium — many moving parts
MariaDB major versionOperator recovery + db-manager agentHigh — test on staging first
Kubernetes version bumpTerraform-driven node replacement + staged rolloutHigh — maintenance window

When in doubt

Delegate to the relevant Claude agent — they know the patterns and the safety rails:

  • Image bumps / routine: just go.
  • App updates via scripts/apps.yaml: the update-checker agent (or do-updates.py + read the output).
  • Client-scoped changes: the gitops-commit-pusher + argocd-manager agents for a sanity-checked flow.
  • Anything touching DB / Redis state: the db-manager agent first, always.

Further reading

Internal documentation — Advisable only