Keep intentionally empty values
This content is for the v0.1 version. Switch to the latest version for up-to-date documentation.
Some Kubernetes values are meaningful precisely because they are empty.
emptyDir: {} selects a volume source. An empty label selector matches
everything. subresources.status: {} enables a CRD subresource. Kix keeps
these, but it also removes the empty leftovers that appear when every field
inside a container is unset. This guide shows how to stay on the right side
of that line.
Write literal empties as-is
Section titled “Write literal empties as-is”A container you write empty renders exactly as written. No wrapper, no special syntax:
spec.template.spec.volumes = [ { name = "tmp"; emptyDir = { }; }];This renders emptyDir: {} in the output. The same holds for lists:
ingress = [ ]; renders ingress: []. Pasting a standard Kubernetes
manifest into a package works without changes.
What gets removed instead
Section titled “What gets removed instead”A container whose members are all null is treated as unset and omitted,
along with any wrappers that end up empty because of it:
resources = { limits = null; requests = null;};# renders nothing: the container collapses and the field is absentThis is the shape merged, unset options produce, and removing it is what
keeps rendered manifests free of resources: {} noise.
Protect a constructor with kix.keep
Section titled “Protect a constructor with kix.keep”The trap sits between those two cases: a helper that builds a presence-meaningful container out of optional arguments. When every argument is null, the result is a container of nulls, and it collapses. The field disappears from the manifest without an error.
Wrap the result in kix.keep to pin it:
source.emptyDir = kix.keep { medium = config.medium; # may be null sizeLimit = config.sizeLimit; # may be null};# renders emptyDir: {} when both are null,# emptyDir: { sizeLimit = "1Gi"; } when one is setFiltering the nulls yourself works too, and is what kix.mount.emptyDir
does internally:
source.emptyDir = { } // lib.optionalAttrs (medium != null) { inherit medium; } // lib.optionalAttrs (sizeLimit != null) { inherit sizeLimit; };Prefer kix.keep when the container is assembled across several places or
merged after construction: the protection travels with the value, so a later
merge that introduces fresh nulls cannot collapse it.
Verify
Section titled “Verify”Render the cluster and check the field survived:
# in the rendered YAML for the workload:volumes:- name: tmp emptyDir: {}The volumeHasSource scorecard rule backs this up for the volume case. It is
part of the built-in rule set, which runs on every cluster by default, so a
volume that would render without a source is reported with a message naming
the volume and the fix.
The rule’s severity is error, but a cluster caps every finding at
scorecard.maxSeverity, which defaults to warning. Set the cap to error
when this finding should stop the build. See
Fail the build on scorecard findings.