Skip to content

Deploy to the cluster

Vouch runs in two layers: OpenTofu provisions AWS + k3s (infra/); helmfile converges everything inside the cluster (deploy/). This guide is the manual path; the one-click pipeline is in Deploy via CI.

  • tofu, kubectl, helm, helmfile (+ helm-diff plugin), docker (buildx), htpasswd (apache2-utils), and an AWS SSO session for the account profile.
  • Infra already applied: cd infra && tofu apply (writes the EIP and ECR URLs).
Terminal window
# 1. Capture infra outputs into the env file helmfile consumes
cd infra
cat > ../deploy/values/prod.env <<EOF
BASE_DOMAIN=$(tofu output -raw base_domain)
EIP=$(tofu output -raw eip)
REGISTRY=$(tofu output -raw registry)
ECR_API=$(tofu output -raw ecr_api_url)
ECR_WEB=$(tofu output -raw ecr_web_url)
AWS_REGION=eu-west-1
ACME_EMAIL=stijn@techwolf.ai
EOF
# 2. Kubeconfig (over SSM, no SSH; points at https://127.0.0.1:6443 — the
# k3s API is only reachable through an SSM port-forward)
cd .. && ./scripts/get_kubeconfig.sh
export KUBECONFIG=$PWD/kubeconfig
# 3. Build + push arm64 images (writes IMAGE_TAG + digests into prod.env)
./scripts/build_push.sh

Application secrets are not created by hand: External Secrets Operator syncs them from AWS Secrets Manager (infra/persistent), see deploy/README.md.

The converge is phased (operators first, then the app, then observability) and the k3s API is only reachable through an SSM tunnel, so use the script rather than a bare helmfile apply:

Terminal window
scripts/deploy_cluster.sh # opens the tunnel, converges all phases, smoke-tests

What it does, if you need to run a step by hand from deploy/:

Terminal window
helmfile -l phase=infra apply --skip-diff-on-install # traefik, cnpg, ebs-csi, external-secrets
helmfile -l name=vouch apply # app + ClusterSecretStore + ExternalSecrets
# HyperDX ingestion key, synced from Secrets Manager (vouch/hyperdx) by ESO
export HYPERDX_API_KEY=$(kubectl -n observability get secret hyperdx-key -o jsonpath='{.data.api-key}' | base64 -d)
helmfile apply # hyperdx + otel-gateway
envsubst < manifests/hyperdx-ingress.yaml | kubectl apply -f -
  • https://app.$BASE_DOMAIN — demo client
  • https://api.$BASE_DOMAIN — FastAPI
  • https://hyperdx.$BASE_DOMAIN — HyperDX (basic-auth)
Terminal window
curl https://api.$BASE_DOMAIN/healthz
uv run --project server python scripts/demo_e2e.py https://api.$BASE_DOMAIN

A green demo_e2e.py against the live host confirms the full match protocol works end to end in production.