-
Notifications
You must be signed in to change notification settings - Fork 0
Deployment Guide
Captain Dany edited this page Jun 11, 2026
·
1 revision
┌─────────────┐
│ Push to dev │
└──────┬──────┘
│
┌────────────┴────────────┐
▼ ▼
┌─────────┐ ┌──────────┐
│ CI │ │ CD │
│ (all │ │ (deploy │
│ checks) │ │ to dev) │
└─────────┘ └────┬─────┘
│
┌──────────┴──────────┐
▼ ▼
┌──────────┐ ┌──────────┐
│ Staging │ │Production│
│ (manual │ │ (manual │
│approval) │ │approval) │
└──────────┘ └──────────┘
Runs on every push/PR to main/dev:
- Path filtering (backend, frontend, docker)
- Go lint (
golangci-lint), test (with coverage), build - Frontend build (
npm ci && npm run build) - Docker build check (no push)
- Security audit (
govulncheck) - Dependency review (on PRs)
Triggers on push to dev/main or workflow_dispatch:
- Calculate Version — semantic version from git tags
- Build & Push Image — Docker build, push to ghcr.io, attestation
-
Deploy to Dev — Helm install to
oscar-devnamespace (automatic) -
Deploy to Staging — Manual approval gate → Helm install to
oscar-staging -
Deploy to Production — Manual approval gate → Helm install to
oscar-production
# Create namespace
kubectl create namespace oscar-dev
kubectl create namespace oscar-staging
# Create ghcr pull secret (required for image pull)
kubectl create secret docker-registry ghcr-pull \
--docker-server=ghcr.io \
--docker-username=CaptDany \
--docker-password=<GH_PAT> \
-n oscar-dev
kubectl create secret docker-registry ghcr-pull \
--docker-server=ghcr.io \
--docker-username=CaptDany \
--docker-password=<GH_PAT> \
-n oscar-staging
# Create app secret (at least 32 characters)
$secret = -join ((65..90)+(97..122)+(48..57) | Get-Random -Count 64 | % {[char]$_})
kubectl create secret generic oscar-app-secret \
--from-literal=app-secret=$secret \
-n oscar-dev
# Create service account (Helm handles this, but if deploying manually without Helm...)| Secret | Description |
|---|---|
SA_TOKEN |
Service account token (kube-system/github-actions) for programmatic kubeconfig |
GITHUB_TOKEN |
Auto-created, has push/pull permissions |
The old
KUBECONFIG_DEV,KUBECONFIG_STAGING,KUBECONFIG_PRODsecrets have been removed. The workflow builds the kubeconfig programmatically usingkubectl configcommands with theSA_TOKENsecret.
# Create service account (one-time)
kubectl create serviceaccount github-actions -n kube-system
# Bind cluster-admin role
kubectl create clusterrolebinding github-actions-admin \
--clusterrole=cluster-admin \
--serviceaccount=kube-system:github-actions
# Create long-lived token
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: github-actions-token
namespace: kube-system
annotations:
kubernetes.io/service-account.name: github-actions
type: kubernetes.io/service-account-token
EOF
# Get the token
$tokenB64 = kubectl get secret github-actions-token -n kube-system -o jsonpath='{.data.token}'
$token = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($tokenB64))
$token | gh secret set SA_TOKEN --repo CaptDany/oscarPush to dev branch triggers full CI + CD to Dev.
gh workflow run CD --repo CaptDany/oscar --ref dev \
-f environment=stagingdeploy/helm/opencrm/
├── Chart.yaml
├── values.yaml
├── templates/
│ ├── _helpers.tpl
│ ├── deployment.yaml # Deployment + Service + Secret
│ ├── namespace-resources.yaml # Postgres/Redis (conditional)
│ ├── serviceaccount.yaml # ServiceAccount
│ ├── ingress.yaml # Ingress
│ └── hpa.yaml # HPA (conditional)
The CD pipeline overrides these Helm values:
-
image.repository— ghcr.io/captdany/oscar (lowercase!) -
image.tag— semantic version (no+character, Docker rejects it) -
secret.data.database-url— Postgres connection string -
env.APP_ENV/env.APP_BASE_URL— per environment
| Symptom | Cause | Fix |
|---|---|---|
exec: executable oci not found |
Kubeconfig uses OCI exec auth | Switch to SA token (kubectl config set-credentials) |
InvalidImageName: must be lowercase |
Image repo has uppercase | Use captdany/oscar not CaptDanny/oscar
|
invalid reference format |
Docker tag has +
|
Replace + with - in semver |
serviceaccount not found |
Missing SA template | Add serviceaccount.yaml to Helm chart |
APP_SECRET is required |
Missing env var | Create oscar-app-secret k8s secret |
context deadline exceeded |
Deployment not ready | Increase --timeout, check pod logs |
Failed to ping database |
No DATABASE_URL | Set secret.data.database-url or deploy Postgres |