Skip to content

Promote Image

Deploy a new image tag to a tenant environment.

Purpose

Deploy a specific image tag to one or all tenant environments by triggering do-deploy.yml workflow dispatch.

When to use

  • Rolling out a new release to staging or production
  • Re-deploying an older tag (rollback)
  • Promoting a staging-validated tag to production

Steps

Deploy latest release to a tenant

  1. Go to unipuka/soa -> Actions -> do-deploy.yml -> Run workflow
  2. Set tag = desired image tag (e.g. v1.2.3 or git SHA)
  3. Set tenant = oep-stg / mansety-prd / us-prd
  4. For prod tenants: reviewer approval required before workflow proceeds
  5. Workflow commits chore(deploy): bump <tenant> to <tag> to unipuka-infra-ops/master
  6. Argo CD detects change within 3 min, runs PreSync migrate Job, then rolls Deployments

Re-deploy an older tag (rollback)

If the image tag is still in DOCR (within 30-tag retention window):

# Dispatch with the older tag
gh workflow run do-deploy.yml -R unipuka/soa \
  -f tag=v1.1.0 -f tenant=oep-stg

If image was GC'd from DOCR (beyond 30-tag window), rebuild first:

# Rebuild image from historical commit
gh workflow run do-build.yml -R unipuka/soa \
  -f ref=<git-sha-or-tag>
# Then deploy as normal

Chart versioning lockstep (BD-5.3 contract)

Every do-deploy.yml dispatch MUST bump three keys atomically in one commit:

  1. apps/laravel/values-<tenant>.yaml: image.tag -> new semver (e.g. v1.2.3)
  2. apps/laravel/Chart.yaml: version -> bump (e.g. 0.1.0 -> 0.1.1)
  3. apps/laravel/Chart.yaml: appVersion -> same semver as image.tag

Without all 3 bumps, ct lint check-version-increment: true blocks the PR (helm-lint CI turns red). This also gives Argo CD a deterministic chart version per deploy (visible in Argo UI revision history).

# Example bump for oep-stg deploy of v1.2.3
NEW_TAG=v1.2.3
yq -i ".image.tag = \"$NEW_TAG\"" apps/laravel/values-oep-stg.yaml
yq -i ".version = \"0.1.1\"" apps/laravel/Chart.yaml
yq -i ".appVersion = \"$NEW_TAG\"" apps/laravel/Chart.yaml
git add apps/laravel/
git commit -m "chore(deploy): bump oep-stg to $NEW_TAG"

DOCR capacity

Basic tier (5 GiB / $5/mo) chosen over Starter (500 MiB hard cap). Single shared oep/api repo for all tenants (image identical; only Doppler env differs). Image size ~363 MB. Basic gives ~13 image slots raw, but layer deduplication makes retention much higher in practice. Two-layer GC (per-push tag prune + weekly untagged-manifest sweep) keeps storage well under 5 GiB ($0.02/GiB overage if exceeded).

Registry tier change is a registry.tf one-liner (subscription_tier_slug = "basic"). Applied in BD-4.0.

DOCR retention

Two-layer retention strategy (BD-5.5):

Layer Trigger What it does
Per-push tag prune Every master push (prune job in do-build.yml) Deletes oldest tags beyond newest-30 count. Fast, runs immediately after each release.
Weekly backstop prune Sunday 03:00 UTC (docr-gc.yml cron) + workflow_dispatch Same tag-count prune as per-push, but as a weekly safety net.
DOCR automated GC Daily, platform-managed by DigitalOcean Sweeps untagged manifests and unreferenced blobs automatically in our current registry configuration; cannot be disabled or triggered manually here (HTTP 412 if attempted while automated GC is enabled in this registry).

Rules:

  • latest tag is always excluded from deletion.
  • Tags sorted by UpdatedAt descending; oldest beyond count-30 are deleted.
  • After 30 tagged images exist, each new push removes the oldest one automatically.
  • If image was pruned (beyond 30-tag window), rebuild from the original commit:
gh workflow run do-build.yml -R unipuka/soa -f ref=<git-sha-or-tag>

Verify tag count after a prune run:

# Should be <= 32 lines (30 tags + latest + header)
doctl registry repository list-tags api | wc -l

Rollback

Git revert the deploy commit in unipuka-infra-ops/master - Argo CD prune + selfHeal will re-sync the previous tag.

V&V

  • argocd app get <tenant>-laravel shows new image tag and Synced/Healthy
  • kubectl get pods -n <tenant> all Running with new image
  • curl https://<hostname>/health returns 200