Update Env Vars (Non-Secret) #
Env vars change through an ops repo PR. That is the path — edit one file, merge, let the workflow deploy.
k8s/deploy/staging/values.yaml # staging
k8s/deploy/production/values.yaml # production
The repo is the source of truth.
A change made straight on the cluster (kubectl edit configmap, a local helm upgrade) lasts until the next deploy renders the values file over it, and the drift stays invisible until someone else’s unrelated merge undoes your work.
Where each kind of configuration lives #
Check this first. It decides which guide you need.
| What you are changing | Lives in | Guide |
|---|---|---|
| Non-secret env var | k8s/deploy/<env>/values.yaml → ConfigMap |
this page |
| Secret value | GCP Secret Manager → Kubernetes Secret | update secrets |
| Secret name (new container) | Terraform, gcp/envs/<env> |
Terraform |
| Image tag | CI, or the deploy workflow inputs | this page |
| Infrastructure (Cloud SQL, GKE, IAM) | Terraform, gcp/envs/<env> |
Terraform |
Change a variable #
-
Find where it is set:
grep -rn "<VAR_NAME>" k8s/deploy k8s/chartsIf it is not in a
deploy/<env>/values.yaml, the default comes from the chart atk8s/charts/funnelstory/values.yaml. Override it in the environment file rather than editing the chart default. -
Edit the key under
backend.config:(orfrontend.config:for frontend vars):backend: config: ALLOWED_DOMAINS: "funnelstory.io,funnelstory.ai" -
Open a PR and merge to
main. -
Deploy — see the table below. Staging is automatic; production is not.
-
Confirm it reached the pod:
kubectl -n fs-apps exec deploy/backend -- printenv | grep <VAR_NAME>
Secrets go in Secret Manager, mapped through backend.secrets. Anything in values.yaml is plaintext in Git.
How it deploys #
| Staging | Production | |
|---|---|---|
| Trigger | automatic on merge to main |
manual workflow_dispatch only |
| Workflow | .github/workflows/helm-deploy.yml |
.github/workflows/helm-deploy-production.yml |
| Approval | none | production GitHub Environment reviewers |
Staging runs helm upgrade --atomic --wait on push.
Takes about 5 minutes.
For production, run Helm Deploy (production) from the Actions tab and leave both image tag inputs blank.
Blank means “keep the tag the live release is already on”, so the rollout carries only your config change.
Filling a tag in also ships whatever bootstrap tag sits in values.yaml, which is usually older than what is live.
How it reaches the pod #
Values render into a Kubernetes ConfigMap.
The pod loads it with envFrom: configMapRef.
An env var change needs the pod to restart to take effect. The deploy workflow does that for you — there is no manual step.
Merge and deploy to apply a config change.
A kubectl rollout restart on its own restarts the pod against the ConfigMap already on the cluster, which stays the old one until a deploy renders the new values.
Both deploy workflows pass only their per-environment values file, so k8s/deploy/values-base.yaml has no effect on a deploy.
Next: run the grep in step 1 to find your variable.