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.
Prerequisites
Section titled “Prerequisites”tofu,kubectl,helm,helmfile(+helm-diffplugin),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).
One-time, or after infra changes
Section titled “One-time, or after infra changes”# 1. Capture infra outputs into the env file helmfile consumescd infracat > ../deploy/values/prod.env <<EOFBASE_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-1ACME_EMAIL=stijn@techwolf.aiEOF
# 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.shexport KUBECONFIG=$PWD/kubeconfig
# 3. Build + push arm64 images (writes IMAGE_TAG + digests into prod.env)./scripts/build_push.shApplication secrets are not created by hand: External Secrets Operator syncs
them from AWS Secrets Manager (infra/persistent), see deploy/README.md.
Deploy or update
Section titled “Deploy or update”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:
scripts/deploy_cluster.sh # opens the tunnel, converges all phases, smoke-testsWhat it does, if you need to run a step by hand from deploy/:
helmfile -l phase=infra apply --skip-diff-on-install # traefik, cnpg, ebs-csi, external-secretshelmfile -l name=vouch apply # app + ClusterSecretStore + ExternalSecrets# HyperDX ingestion key, synced from Secrets Manager (vouch/hyperdx) by ESOexport HYPERDX_API_KEY=$(kubectl -n observability get secret hyperdx-key -o jsonpath='{.data.api-key}' | base64 -d)helmfile apply # hyperdx + otel-gatewayenvsubst < manifests/hyperdx-ingress.yaml | kubectl apply -f -Hosts (sslip.io on the EIP)
Section titled “Hosts (sslip.io on the EIP)”https://app.$BASE_DOMAIN— demo clienthttps://api.$BASE_DOMAIN— FastAPIhttps://hyperdx.$BASE_DOMAIN— HyperDX (basic-auth)
Verify
Section titled “Verify”curl https://api.$BASE_DOMAIN/healthzuv run --project server python scripts/demo_e2e.py https://api.$BASE_DOMAINA green demo_e2e.py against the live host confirms the full match protocol
works end to end in production.