Go Backend Deployment Workflow
An interactive, zoomable version of this diagram is available at go-backend-deploy.html.

Overview

The Go backend service uses an interactive script backend/go/deploy.sh to orchestrate building container images, publishing them to GitHub Container Registry (GHCR), updating environment-specific Kustomize overlays, and rolling out workloads to Kubernetes. This workflow is designed to:
  • Eliminate Docker Desktop dependencies: Fully supports daemonless Podman and native Linux Buildah.
  • Support low-power dev machines: Leverages remote Kaniko jobs inside the Kubernetes/K3s cluster for in-cluster container builds.
  • Provide flexible rollout strategies: Supports immediate hot-fixes via kubectl apply -k, strict declarative GitOps via ArgoCD, or a Dual Sync mode that combines both.

High-Level Pipeline Architecture

The deployment pipeline is organized into four logical stages:

Step 1: Environment & Prerequisites Detection

When you run deploy.sh, it immediately resolves target environment parameters and validates local tooling:

Script Inputs & Environment Variables

Automated Tooling Checks

  1. Build Engine Detection: Checks if buildah (Linux native) or podman is installed.
  2. Kubernetes CLI: Ensures kubectl exists in $PATH.
  3. Overlay Existence: Confirms that k8s/overlays/${ENV} exists before proceeding.

Step 2: Build Engine Selection

The script presents three build options depending on your local hardware and environment:

Option 1: Local Build (Podman / Buildah)

  • Engine: Automatically selects buildah bud on Linux or podman build on macOS.
  • Workflow: Compiles backend/go/Dockerfile locally, tags with ${FULL_IMAGE}:${VERSION} and :latest, then pushes to GHCR.
  • Cross-Platform Compilation:
  • Best For: Fast, iterative inner loops on powerful workstations.

Option 2: Remote Build (Kaniko in K3s Cluster)

  • Engine: Ephemeral Kubernetes batch/v1 Job executing gcr.io/kaniko-project/executor:latest.
  • Workflow:
    1. Locates ghcr-secret in the target namespace (or across cluster namespaces).
    2. Constructs an authenticated Git context URL (injecting $GITHUB_TOKEN if present).
    3. Cleans up any existing kaniko-build-backend job.
    4. Deploys the Kaniko Job into the cluster with --cache=true and sub-path backend.
    5. Waits for completion (timeout up to 40 minutes for ARM/Raspberry Pi builds) and deletes the job upon success.
  • Best For: Lightweight laptops without container engines, remote development, or building directly on target architecture nodes.

Option 3: Skip Build

  • Workflow: Leaves registry images untouched and skips straight to overlay configuration.
  • Best For: Re-deploying an already-built image, testing configuration changes, or promoting a known commit hash without rebuilding.

Step 3: Kustomize Overlay Tagging

Once the image is confirmed in the registry:
  1. The script navigates to backend/go/k8s/overlays/${ENV}.
  2. Updates kustomization.yaml with the new tag:
  3. Uses kustomize edit set image ... if the kustomize CLI is present, otherwise falls back to sed -i for portability.

Step 4: Deployment Execution Modes (Deep Dive)

The deployment execution prompt asks how changes should be applied to the Kubernetes cluster:

Mode 1: Direct Rollout (direct)

  • Command: kubectl apply -k k8s/overlays/${ENV}
  • How it works: Compiles the Kustomize manifests locally and pushes resource definitions directly to the active Kubernetes context.
  • Characteristics:
    • Instantaneous: Pods roll out immediately in seconds.
    • ⚠️ GitOps Drift: If ArgoCD has selfHeal: true enabled on the application, ArgoCD will eventually detect the mismatch with Git and roll the pods back to the Git version.
  • When to use: Quick hot-testing or debugging in development environments.

Mode 2: GitOps via ArgoCD (git)

  • Command: Commits kustomization.yaml and runs git push origin HEAD:${BRANCH_NAME}.
  • Commit Message: Update backend image to ${VERSION} for ${ENV} [skip ci]
  • How it works:
    • The [skip ci] tag prevents redundant GitHub Actions test workflows from triggering.
    • ArgoCD continuously monitors the target branch specified in backend/go/argocd/application.yaml.
    • When ArgoCD detects the new commit, it synchronizes the live cluster according to its environment policy:
      • development & uat: Automated sync (prune: true, selfHeal: true).
      • staging: Automated sync (prune: true, selfHeal: false, manual approval).
      • production: Strictly manual sync for safety (automated: null).
  • Characteristics:
    • 🔒 Auditable & Declarative: Every deployment is recorded in Git commit history.
    • 🛡️ Zero Drift: Cluster state strictly reflects Git repository state.
  • When to use: Standard team workflows and promotions to staging and production.

Mode 3: Dual Sync (both)

  • Command: Runs kubectl apply -k AND commits and pushes to Git.
  • How it works:
    • The local cluster rolls out the new image immediately without waiting for ArgoCD’s poll cycle.
    • The Git commit is pushed concurrently, updating the target branch so ArgoCD sees the Git state and cluster state as perfectly in sync.
  • Characteristics:
    • 🚀 Zero Waiting: Immediate rollout speed of kubectl apply.
    • 🤝 Zero Drift: No risk of ArgoCD rolling back your local update.
  • When to use: The recommended choice when developing against a cluster managed by ArgoCD.

Mode 4: Skip Deployment (skip)

  • Action: Stops execution without touching the cluster or committing to Git.
  • When to use: Preparing the Kustomize overlay locally for manual inspection or inclusion in a wider PR.

Decision Matrix for Developers


ArgoCD Environment Sync Policies

Defined in backend/go/argocd/application.yaml:

Troubleshooting & Common Issues

Kaniko build fails with ghcr-secret not found: Ensure a GitHub Container Registry token secret exists in your target namespace:
ArgoCD rolls back your direct kubectl apply changes: If you selected 1) Direct in an environment where ArgoCD has selfHeal: true (such as development), ArgoCD will detect cluster drift from Git and revert your pod back to the Git tag. Select 3) Both to commit the new tag and keep Git in sync.
Non-interactive CI/CD execution: You can bypass the interactive prompts in scripts or automated jobs by setting environment variables: