Compose multi-team clusters with `mergeFragments`
This content is for the v0.1 version. Switch to the latest version for up-to-date documentation.
Use kix.mergeFragments when different teams maintain parts of one cluster’s
namespace and instance trees. Each fragment remains a normal Nix attrset, so
it can live beside the code its team owns.
Define the fragments
Section titled “Define the fragments”A fragment can contribute namespaces, instances, or both. This platform
fragment adds policy for apps and owns a service in platform:
namespaces.apps = { labels."platform.example.com/tier" = "application"; annotations."platform.example.com/owner" = "platform"; };
instances.platform.status-api = { package = packages.echo-server; config.message = "Platform status"; };An application fragment can add labels to the same namespace and declare its own instances:
namespaces.apps.labels."app.kubernetes.io/part-of" = "storefront";
instances.apps.storefront = { package = packages.echo-server; config.message = "Storefront ready"; };Import each fragment into the cluster file with any arguments it needs. In
this example, both imports receive packages:
platformFragment = import ./platform-fragment.nix { inherit packages; };storefrontFragment = import ./storefront-fragment.nix { inherit packages; };Merge the fragments
Section titled “Merge the fragments”Pass the fragments in a list. Use namespacePolicies for policy owned by the
cluster definition itself:
composition = kix.mergeFragments { fragments = [ platformFragment storefrontFragment ];
# Policies applied by the cluster owner merge with the team fragments. namespacePolicies.apps.labels."platform.example.com/managed" = "true"; };Namespace attrsets merge recursively. Two fragments may add different labels, annotations, or quota fields to the same namespace. They may not set the same leaf, even to the same value. Kix treats any duplicate leaf as a namespace policy conflict.
namespacePolicies uses the same merge. Cluster-level policy can add leaves,
but it cannot override or repeat a leaf set by a fragment.
Instance ownership is stricter. Defining the same instance name in the same namespace from two fragments is always an error.
Add the composition to the cluster
Section titled “Add the composition to the cluster”Assign both outputs inside a cluster module:
namespaces = composition.namespaces; instances = composition.instances { };composition.instances is a function so fragments may calculate their
instance tree from shared arguments. Pass those arguments in place of { }
when a fragment’s instances value is a function.
Check the result
Section titled “Check the result”Evaluate the composed cluster:
❱ kix check how-to-fragments
TOOL RESULT DETAILS
eval pass 15 manifests evaluated
kubeconform pass skipped (this validation tool is not yet integrated with Kix)
pluto pass skipped (this validation tool is not yet integrated with Kix)
kyverno pass skipped (this validation tool is not yet integrated with Kix)
scorecard pass 0 errors, 4 warnings, 2 info Inspecting the generated apps Namespace confirms that labels and annotations
from both teams and the cluster policy were retained:
❱ kix build how-to-fragments --output json Show output
{
"kind": "Namespace",
"metadata": {
"name": "apps",
"labels": {
"app.kubernetes.io/managed-by": "kix",
"app.kubernetes.io/part-of": "storefront",
"kubernetes.io/metadata.name": "apps",
"platform.example.com/managed": "true",
"platform.example.com/tier": "application"
},
"annotations": {
"kix.run/identity-hash": "y2nm039ddnq7w89q933whl2nq8z9xls0",
"kix.run/package": "_cluster",
"kix.run/package-namespace": "_cluster",
"platform.example.com/owner": "platform"
}
}
} Keep settings with a single owner where possible. The conflict errors are most useful when overlapping ownership is accidental.