Deploy an Application with Configurations and Secrets
This guide walks you through deploying an application that uses environment variables, configuration files, and secrets. OpenChoreo lets you inject all of these into your workload without baking them into your container image.
Overviewβ
When deploying real applications, you typically need to:
- Pass environment variables (log levels, feature flags)
- Mount configuration files (app settings, certificates)
- Inject secrets (database passwords, API tokens) from an external secret store
OpenChoreo handles all of these through the Workload resource and the SecretReference resource.
Prerequisitesβ
Before you begin, ensure you have:
- OpenChoreo installed in your Kubernetes cluster
- kubectl configured to access your cluster
- External Secrets Operator (ESO) installed (required for secrets)
- Secrets stored in your secret backend (this guide uses the default OpenBao dev setup)
For production secret management, see Secret Management to configure a proper secret backend.
Step 1 β Store Secrets in OpenBaoβ
Store the secret values your application needs. This example stores a database password and a GitHub personal access token.
kubectl exec -n openbao openbao-0 -- sh -c '
export BAO_ADDR=http://127.0.0.1:8200 BAO_TOKEN=root
bao kv put secret/db-password value="supersecret"
bao kv put secret/github-pat value="ghp_your_token_here"
'
Step 2 β Create SecretReferencesβ
SecretReference resources tell OpenChoreo how to pull a specific secret from your external store and make it available to your workload.
kubectl apply -f - <<EOF
---
apiVersion: openchoreo.dev/v1alpha1
kind: SecretReference
metadata:
name: database-secret
namespace: default
spec:
refreshInterval: 1h
template:
type: Opaque
data:
- secretKey: password
remoteRef:
key: db-password
property: value
---
apiVersion: openchoreo.dev/v1alpha1
kind: SecretReference
metadata:
name: github-pat-secret
namespace: default
spec:
refreshInterval: 1h
template:
type: Opaque
data:
- secretKey: gitPAT
remoteRef:
key: github-pat
property: value
EOF
Each SecretReference maps a key from the external store to a Kubernetes secret key that your workload can reference by name.
Step 3 β Deploy the Component and Workloadβ
Create a Component using the deployment/worker ComponentType, and a Workload that injects environment variables, a configuration file, and the secrets defined above. The container echoes all injected values and then sleeps indefinitely so you can inspect the output.
kubectl apply -f - <<EOF
---
apiVersion: openchoreo.dev/v1alpha1
kind: Component
metadata:
name: config-tutorial-app
namespace: default
spec:
owner:
projectName: default
componentType:
kind: ClusterComponentType
name: deployment/worker
autoDeploy: true
---
apiVersion: openchoreo.dev/v1alpha1
kind: Workload
metadata:
name: config-tutorial-app-workload
namespace: default
spec:
owner:
projectName: default
componentName: config-tutorial-app
container:
image: "alpine:3.19"
command:
- sh
- -c
- |
echo "=== Environment Variables ==="
echo "LOG_LEVEL=$LOG_LEVEL"
echo "DATABASE_PASSWORD=$DATABASE_PASSWORD"
echo "=== Config File ==="
cat /conf/application.toml
echo "=== Secret File ==="
cat /conf/gitPAT
echo "=== Done. Sleeping... ==="
sleep infinity
env:
- key: LOG_LEVEL
value: info
- key: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: database-secret
key: password
files:
- key: application.toml
mountPath: /conf
value: |
schema_generation:
enable: true
- key: gitPAT
mountPath: /conf
valueFrom:
secretKeyRef:
name: github-pat-secret
key: gitPAT
EOF
What's happening hereβ
| Field | Description |
|---|---|
container.env[].value | Plain-text environment variable injected directly |
container.env[].valueFrom.secretKeyRef | Secret value pulled from a SecretReference and injected as an env var |
container.files[].value | Inline file content mounted at the specified path |
container.files[].valueFrom.secretKeyRef | Secret value pulled from a SecretReference and mounted as a file |
Step 4 β Override Configurations per Environment (Optional)β
Use a ReleaseBinding to override environment variables and config files for a specific environment without changing the base Workload. This is useful for promoting the same component across dev, staging, and production with different settings.
kubectl apply -f - <<EOF
---
apiVersion: openchoreo.dev/v1alpha1
kind: ReleaseBinding
metadata:
name: config-tutorial-app-development
namespace: default
spec:
environment: development
owner:
componentName: config-tutorial-app
projectName: default
componentTypeEnvironmentConfigs:
replicas: 2
resources:
requests:
cpu: "50m"
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
workloadOverrides:
container:
env:
- key: FEATURE_FLAG
value: "true"
- key: NEW_ENV_VAR
value: new_value
files:
- key: application.toml
mountPath: /conf
value: |
schema_generation:
enable: false
EOF
The workloadOverrides section merges with the base Workload β overriding matching keys and adding new ones β while keeping everything else from the original definition.
Verify the Deploymentβ
Check that the component and workload were created:
kubectl get component config-tutorial-app
kubectl get workload config-tutorial-app-workload
Check that the pods are running:
kubectl get pods -A | grep config-tutorial-app
Once the pod is running, inspect the container output to verify the injected values:
kubectl logs -n <pod-namespace> -l openchoreo.dev/component=config-tutorial-app
Verify the ConfigMaps, ExternalSecrets, and Secrets were created for the configurations:
kubectl get configmap -A | grep config-tutorial-app
kubectl get externalsecret -A | grep config-tutorial-app
kubectl get secrets -A | grep config-tutorial-app
Summaryβ
You've learned how to deploy an application with environment variables, configuration files, and secrets using OpenChoreo's Workload and SecretReference resources, and how to override configurations per environment using ReleaseBinding.
Next Stepsβ
- Set up Secret Management for production secret backends
- Explore more examples of deploying applications