Environment Configuration
This guide is for configuration your running process reads at startup: log levels, feature flags, service URLs, database credentials, and API keys. It is not a deployment guide and it does not create a separate staging or production environment. Deploy each environment as its own app, then target that app by name.
Environment configuration changes the Deployment’s container environment. It does not rebuild the image or change the app’s Service, hostname, or Gateway API HTTPRoute.
Choose the right store
Section titled “Choose the right store”| Use | For | Visibility |
|---|---|---|
1ctl config create |
Non-sensitive runtime values such as LOG_LEVEL, feature flags, and internal URLs |
Plain text in a Kubernetes ConfigMap and visible to people who can inspect configuration |
1ctl secret create |
Passwords, tokens, connection strings, and private keys | Stored as a Kubernetes Secret; the normal table output shows metadata without values |
Do not put either kind of runtime value in satusky.toml. That file describes the application to deploy; these commands configure an application that already exists.
Target one deployed app
Section titled “Target one deployed app”Deploy the app first, then set its name once for the commands below:
APP=my-api1ctl app get "$APP"Use --app "$APP" in scripts when you do not want the current directory or a config file to decide which deployment is changed. --deployment-id is the equivalent explicit target when you have the UUID.
Add non-secret values
Section titled “Add non-secret values”config create is an upsert: keys you supply are added or updated, and unrelated keys remain in place.
1ctl config create --app "$APP" \ --env APP_ENV=production \ --env LOG_LEVEL=warn \ --env FEATURE_SEARCH_V2=enabledList the configuration for only this app:
1ctl config list --app "$APP"The CLI list output identifies the configuration and deployment. It may include non-secret values, so do not use it for credentials.
Add a secret without putting its value in the command
Section titled “Add a secret without putting its value in the command”Read the secret into your shell without echoing it, pass it once, then remove the shell variable. Replace DATABASE_URL with the key your application expects.
read -r -s -p 'Database URL: ' DATABASE_URLprintf '\n'1ctl secret create --app "$APP" --kv "DATABASE_URL=$DATABASE_URL"unset DATABASE_URLsecret create upserts only the supplied keys, so it is also the safe way to rotate one credential without replacing other secrets. Config and secret changes reconcile a fresh pod template. Wait for the application to become healthy; use an explicit restart only when you intentionally want another rollout:
1ctl app status "$APP" --watchDo not paste real secrets into shell history, source files, satusky.toml, or CI logs. In CI, provide a protected CI variable and pass it with the same quoted --kv "KEY=$VARIABLE" form.
List secret metadata by app. This is a metadata/count check, not a way to retrieve a value:
1ctl secret list --app "$APP"Treat this as secret-group metadata only. It does not retrieve a value and should not be used to prove that a particular key reached the process. Use the value-free presence checks below.
Prove the new pod received the configuration
Section titled “Prove the new pod received the configuration”1ctl app status --watch reports the current workload state, but it does not identify a particular configuration generation. After the rollout is healthy, an operator with Kubernetes access should wait for the Deployment and then check the references and test only whether a secret is present. The following never prints the secret value.
NAMESPACE=<your-organization-namespace>
kubectl -n "$NAMESPACE" rollout status "deployment/$APP" --timeout=5m
# The deployed container should reference both stores by key.kubectl -n "$NAMESPACE" get deployment "$APP" -o json | \ jq -r '.spec.template.spec.containers[].env[] | select(.name == "APP_ENV" or .name == "DATABASE_URL") | if .valueFrom.configMapKeyRef then "\(.name): ConfigMap reference" elif .valueFrom.secretKeyRef then "\(.name): Secret reference" else "\(.name): unexpected direct value" end'
# The non-secret value is exact; the secret check reports presence only.POD=$(kubectl -n "$NAMESPACE" get pod -l "app=$APP" \ -o jsonpath='{.items[0].metadata.name}')kubectl -n "$NAMESPACE" exec "$POD" -- sh -c \ '[ "$APP_ENV" = production ] && echo "APP_ENV injected"; \ [ -n "$DATABASE_URL" ] && echo "DATABASE_URL present"'On Gateway API installations, you can separately confirm that the route is still present; runtime configuration must not create or replace it:
kubectl -n "$NAMESPACE" get httprouteSome clusters are still completing the Gateway API migration and may expose an Ingress during that compatibility period. Do not edit either routing resource to configure environment variables or secrets.
Remove one key safely
Section titled “Remove one key safely”Remove exactly the key you no longer need, then wait for the reconciled rollout so new pods cannot retain a stale process environment:
1ctl config unset --app "$APP" --key FEATURE_SEARCH_V21ctl secret unset --app "$APP" --key DATABASE_URLconfig unset and secret unset remove the selected key from desired state and the Deployment reference. They do not delete the complete configuration bundle or unrelated keys. For Infisical-backed secrets, the materialized Kubernetes Secret is updated on the operator’s next resync; use the key-presence check above before treating credential rotation or removal as complete.
Separate environments deliberately
Section titled “Separate environments deliberately”Use distinct app names for staging and production, for example my-api-staging and my-api. Each app has its own config and secret bundles. You can still keep separate satusky.staging.toml and satusky.production.toml files for image, resource, and domain settings, but use --app or --deployment-id when changing runtime configuration so the target is unambiguous.
Checklist
Section titled “Checklist”- Deploy the target app before creating config or secrets.
- Use
config createonly for values safe to expose as plain text. - Use
secret createfor credentials; never retrieve or print their values to verify them. - Wait for the reconciled rollout after a config or secret change; restart only when explicitly needed.
- Verify Kubernetes references and secret presence without reading secret data.
- Keep routing separate: configuration changes should leave the app’s Service and HTTPRoute untouched.