> ## Documentation Index > Fetch the complete documentation index at: https://timoni.sh/llms.txt > Use this file to discover all available pages before exploring further. # Bundle Runtime > Fetch values at apply time from Kubernetes Secrets, ConfigMaps and other resources. While Timoni [Bundles](/bundle) offer a way to specify the config values in declarative manner, not all the configuration values of an application are known ahead of time. Some values may be available at runtime, in the Kubernetes clusters where the Bundle is applied. For example, the API token for some backend service that your app consumes is stored in a Kubernetes Secret in-cluster. When installing the application with Timoni, you may want to fetch the token from the Kubernetes Secret and use it as a config value. Timoni Runtime API offers a way to define values which are fetched from the Kubernetes API and mapped to fields inside a Bundle. ## Example The following is an example of a Runtime definition that extracts values from the cluster. ```cue theme={"system"} runtime: { apiVersion: "v1alpha1" name: "production" clusters: { // using the cluster set in kubeconfig current context } values: [ { query: "k8s:v1:ConfigMap:infra:aws-info" for: { "ACCOUNT_ID": "obj.data.account_id" "REGION": "obj.data.region" } }, { query: "k8s:v1:Secret:infra:redis-auth" for: { "REDIS_PASS": "obj.data.password" "REDIS_CA": "obj.data.\"ca.crt\"" } }, ] } ``` The values from the Runtime, can be mapped to fields in a Bundle using `@timoni()` attributes. ```cue theme={"system"} bundle: { _id: string @timoni(runtime:string:ACCOUNT_ID) _reg: string @timoni(runtime:string:REGION) _pass: string @timoni(runtime:string:REDIS_PASS) apiVersion: "v1alpha1" name: "podinfo" instances: { podinfo: { module: url: "oci://\(_id).dkr.ecr.\(_reg).amazonaws.com/modules/podinfo" namespace: "podinfo" values: caching: { enabled: true redisURL: "tcp://:\(_pass)@redis.infra:6379" } } } } ``` Assuming the ConfigMaps and Secrets are in the cluster, and the Runtime file is `runtime.cue` and the Bundle file is `bundle.cue`. Build the runtime to see which values are present on the cluster: ```sh theme={"system"} timoni runtime build -f runtime.cue ``` ```text theme={"system"} ACCOUNT_ID: 1234567890 REGION: us-west-2 REDIS_PASS: password REDIS_CA: -----BEGIN CERTIFICATE----- MIIC/jCCAeagAwIBAgIBADANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwprdWJl cm5ldGVzMB4XDTIzMDgxMDE1MTA1MFoXDTMzMDgwNzE1MTA1MFowFTETMBEGA1UE AxMKa3ViZXJuZXRlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJgA mOniTayGyXG51eYeb1oJGCszRlZv4ci2kzLC0H4YCph6TXDEawrsvyuzGe7fwp4t Jq2fQiJgKbibOjHcOwhYqp1lJDu37p6WsLvx/RxbkHoVX8X2n7n1BVS5MbQ81on9 BdXkff71g8n3HmJo8ZN1abEW434tHFwjjGMDzFoqxTnNM+qMKegxAtTPVbjV4X+5 4/95L7T0XNd97XnunSUAEJRroMTRuaBAcYz81N0ix3Mc0T+G16aV127R0ZFkPlS8 bzjA1NGgbiveX7i7n9mNG4Gy7iElP0iidtdrA6loxWYLW1jmEH5/pWQnki7s3OrK /94xrQ2MaDpXUzcoc0cCAwEAAaNZMFcwDgYDVR0PAQH/BAQDAgKkMA8GA1UdEwEB /wQFMAMBAf8wHQYDVR0OBBYEFJ7f9QzKWA/BQJSRinKne4FZNzScMBUGA1UdEQQO MAyCCmt1YmVybmV0ZXMwDQYJKoZIhvcNAQELBQADggEBAAhGgYFB90Rkexgh56q8 n8uC4XQF6OTJJf/4A9VXNbiZhG+PUYkMUyqeOSOq+IztJVOffuG9ZutYQtJYCX7g TUQmZxeKAw1MAMEWAELmNVdbG6Y6YZ14v8SI+TADqeqcIkmDEkACygfeHKdEFOfV LoRAc3Zn32byP5M6EVjTXWvb+UbVt7umoBOCbMo3BEF71TEDI5Oww6y3YxDM9/Y7 MCTu+0XHZNGDgprmci6fzLv8PV0C6eiuUrrBM237WOfk4BYL6pmCDcCWo6aP2cH7 Y5zcVBxKUs/h5bZfLJFuwXJC5zWudNLOAtNtFhctMwDoNaKYq720g/GmEroq4wgA tBI= -----END CERTIFICATE----- ``` Apply the Bundle using the values from the Runtime: ```sh theme={"system"} timoni bundle apply -f bundle.cue --runtime runtime.cue ``` ```text theme={"system"} applying instance podinfo pulling oci://1234567890.dkr.ecr.us-west-2.amazonaws.com/modules/podinfo using module timoni.sh/podinfo version 6.14.1 installing podinfo in namespace podinfo ServiceAccount/podinfo/podinfo created Service/podinfo/podinfo created Deployment/podinfo/podinfo created waiting for 3 resource(s) to become ready... resources are ready ``` ## Writing a Runtime spec A Runtime file must contain a definition that matches the following schema: ```cue theme={"system"} #Runtime: { apiVersion: string name: string clusters?: [string]: { group!: string kubeContext!: string } values?: [...#RuntimeValue] } #RuntimeValue: { query: string for: {[string]: string} optional: *false | bool } ``` ### API version The `apiVersion` is a required field that specifies the version of the Runtime schema. Currently, the only supported value is `v1alpha1`. ### Name The `name` is a required field used to identify the Runtime. The name must be a lowercase identifier (alphanumeric characters, `-` and `_`, starting and ending with an alphanumeric character) of at most 63 characters. ### Clusters The `clusters` field is for defining the target clusters and environments (group of clusters) where a Bundle is applied. A cluster entry must specify the `group` and `kubeContext` fields. The cluster name (the `clusters` map key) must be a lowercase identifier (alphanumeric characters, `-`, `_` and `.`, starting and ending with an alphanumeric character) of at most 63 characters. The `kubeContext` value must match a context name from the `.kube/config` file. **Default cluster** When no clusters are defined in the Runtime, Timoni will use the current context from the kubeconfig, unless the context is specifed using the `--kube-context` flag. Example: ```cue theme={"system"} runtime: { apiVersion: "v1alpha1" name: "fleet" clusters: { "preview-us-1": { group: "staging" kubeContext: "eks-us-west-2" } "prod-us-1": { group: "production" kubeContext: "eks-us-west-1" } "prod-eu-1": { group: "production" kubeContext: "eks-eu-west-1" } } } ``` The clusters name and group, can be mapped to fields in a Bundle using `@timoni()` attributes. ```cue theme={"system"} bundle: { _cluster: string @timoni(runtime:string:TIMONI_CLUSTER_NAME) _env: string @timoni(runtime:string:TIMONI_CLUSTER_GROUP) apiVersion: "v1alpha1" name: "apps" instances: { app: { module: url: "oci://ghcr.io/stefanprodan/modules/podinfo" namespace: "apps" values: { ui: message: "Hosted by \(_cluster)" if _env == "staging" { replicas: 1 } if _env == "production" { replicas: 2 } } } } } ``` When applying the above Bundle, Timoni will deploy the app instances to all the clusters, in the order defined in the Runtime. If the apply fails on a staging cluster, Timoni will stop the execution and not continue with production. For more details please see the [multi-cluster deployments guide](/bundle-multi-cluster). ### Values The `values` array is for specifying the list of Kubernetes resources and the fields to be extracted. #### Query The `values.query` is a required field that specifies the Kubernetes resource. The `query` field must be in the format `k8s::::`. Example: ```cue theme={"system"} runtime: { apiVersion: "v1alpha1" name: "production" values: [ { query: "k8s:v1:Secret:infra:redis-auth" for: { "REDIS_PASS": "obj.data.password" } }, ] } ``` If the Kubernetes resource is global, the `query` format is `k8s:::`. Example: ```cue theme={"system"} runtime: { apiVersion: "v1alpha1" name: "production" values: [ { query: "k8s:cert-manager.io/v1:ClusterIssuer:letsencrypt" for: { "ISSUER_EMAIL": "obj.spec.acme.email" } }, ] } ``` #### For The `values.for` is a required map that specifies which fields to be extracted from the Kubernetes resource. The `for` map must contain pairs of name and CUE expression. Example: ```cue theme={"system"} runtime: { apiVersion: "v1alpha1" name: "production" values: [ { query: "k8s:source.toolkit.fluxcd.io/v1:GitRepository:flux-system:cluster" for: { "GIT_REVISION": "obj.status.artifact.revision" "GIT_STATUS": "[for c in obj.status.conditions if c.type == \"Ready\" {c.status}][0]" } }, ] } ``` The CUE expression must result in a concrete value of type `string`, `number` or `bool`. #### Optional The `optional` field can be set to `true` and Timoni will skip not found Kubernetes resources instead of throwing an error. ## Using values from Kubernetes API The values defined in a Runtime can be referred in Bundles using CUE attributes. The `@timoni(runtime:[string|number|bool]:[VAR_NAME])` CUE attribute can be placed next to a field to set its value from the runtime. ```cue theme={"system"} bundle: { apiVersion: "v1alpha1" name: "app" instances: { app: { module: url: "oci://localhost:5000/modules/app" namespace: "apps" values: { host: string @timoni(runtime:string:HOST) enabled: bool @timoni(runtime:bool:ENABLED) score: int @timoni(runtime:number:SCORE) } } } } ``` If a runtime value is optional, you can provide defaults which will be used only if the runtime doesn't contain the referenced value: ```cue theme={"system"} values: { host: "example.com" @timoni(runtime:string:HOST) enabled: true @timoni(runtime:bool:ENABLED) score: 1 @timoni(runtime:number:SCORE) } ``` To load the runtime values at apply time, use the `--runtime` flag: ```shell theme={"system"} timoni bundle apply -f bundle.cue --runtime runtime.cue ``` At apply time, Timoni injects the fields values from the runtime, if a specified runtime var is not found and if a default is not provided, the apply with fail with an `incomplete value` error. Runtime values are validated against the type declared in the attribute before they are injected. A `number` value must be a CUE number literal, and a `bool` value must be `true` or `false`; anything else fails the apply with a `failed to parse attribute` error. A `string` value is quoted, so it may hold arbitrary text including newlines. ## Using values from environment variables To use values from environment variables, the environment must contain variables which match the CUE attributes. Example: ```cue theme={"system"} bundle: { apiVersion: "v1alpha1" name: "app" instances: { app: { module: url: "oci://localhost:5000/modules/app" namespace: "apps" values: { sshKey: string @timoni(runtime:string:SSH_KEY) isAdmin: false @timoni(runtime:bool:IS_ADMIN) } } } } ``` Export the env vars and run the `timoni bundle apply --runtime-from-env` command. ```shell theme={"system"} EXPORT SSH_KEY=$(cat .ssh/id_ecdsa.pub) EXPORT IS_ADMIN="true" timoni bundle apply -f bundle.cue --runtime-from-env ``` **Mixing values from the Runtime and Environment** When using `timoni bundle apply --runtime runtime.cue --runtime-from-env`, the values coming from the Runtime take precedence over the Environment. Use `timoni bundle vet --offline` to validate with Runtime values from the environment without connecting to the clusters. This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.