Skip to main content
Version: v0.14 🚧

Base and Override

In practice, what we have observed for production-grade applications is that they usually need to be deployed to a wide range of different targets, be it different environments in the SDLC, or different clouds, regions or runtimes for cost/regulation/performance or disaster recovery related reasons.

In that context, we advocate for a pattern where you can leverage some Kusion and KCL features to minimize the amount of duplicate configurations, by separating the common base application configuration and environment-specific ones.

info

The file names in the below examples don't matter as long as they are called out and appear in the correct order in the entries field (the field is a list) in kcl.mod. The files with common configurations should appear first in the list and stack-specific ones last. The latter one takes precedence.

The configurations also don't have be placed into a single .k file. For complex projects, they can be broken down into smaller organized .k files for better readability.

Base configuration defined in base/base.k:

import kam.v1.app_configuration as ac
import service
import service.container as c
import network.network as n

myapp: ac.AppConfiguration {
workload: service.Service {
containers: {
"myapp": c.Container {
image: "<no value>"
resources: {
"cpu": "500m"
"memory": "512Mi"
}
}
}
replicas: 1
}
accessories: {
"network": n.Network {
ports: [
n.Port {
port: 80
public: True
}
]
}
}
}

Environment-specific configuration defined in dev/main.k:

import kam.v1.app_configuration as ac
import service
import service.container as c

# main.k declares customized configurations for dev stack.
myapp: ac.AppConfiguration {
workload: service.Service {
containers: {
"myapp": c.Container {
# dev stack has different app configuration from the base
image = "gcr.io/google-samples/gb-frontend:v5"
resources = {
"cpu": "250m"
"memory": "256Mi"
}
}
}
replicas = 2
}
}

Alternatively, you could locate a specific property (in this case below, the Container object) in the AppConfiguration object using the dot selector shorthand(such as workload.containers.myapp or workload.replicas below):

import kam.v1.app_configuration as ac

# main.k declares customized configurations for dev stack.
myapp: ac.AppConfiguration {
workload.replicas = 2
workload.containers.myapp: {
# dev stack has different app configuration
image = "gcr.io/google-samples/gb-frontend:v5"
resources = {
"cpu": "250m"
"memory": "256Mi"
}
}
}

This is especially useful when the application configuration is complex but the override is relatively straightforward.

The two examples above are equivalent when overriding the base.