Running kustomize
means one is running a
particular version of a program, reading a
particular version of a kustomization file.
The command kustomize version
prints a three
field version tag (e.g. 1.0.11
) that aspires to
semantic versioning.
When enough changes have accumulated to warrant a new release, a release process is followed, and the fields in the version number are bumped per semver.
At the time of writing (circa release of v2.0.0):
-
A kustomization file is just a YAML file that can be successfully parsed into a particular Go struct defined in the
kustomize
binary. -
This struct does not have a version number, which is the same as saying that its version number matches the program's version number, since it's compiled in.
-
A field's meaning cannot be changed.
-
A field may be deprecated, then removed.
-
Deprecation means triggering a minor (semver) version bump in the program, and defining a migration path in a non-fatal error message.
-
Removal means triggering a major (semver) version bump, and fatal error if field encountered (as with any unknown field).
This kustomize
command reads a Kustomization
file, converts deprecated fields to new
fields, and writes it out again in the latest
format.
This is a type version upgrade mechanism that works within major program revisions. There is no downgrade capability, as there's no use case for it (see discussion below).
At the time of writing, in v1.0.x, there were 12
minor releases, with backward compatible
deprecations fixable via edit fix
.
With the 2.0.0 release, there were three field removals:
-
imageTag
was deprecated whenimages
was introduced, because the latter offers more general features for image data manipulation.imageTag
was removed in v2.0.0. -
patches
was deprecated and replaced bypatchesStrategicMerge
whenpatchesJson6902
was introduced, to make a clearer distinction between patch specification formats.patches
was removed in v2.0.0. -
secretGenerator/commands
was removed due to security concerns in v2.0.0 with no deprecation period.
The edit fix
command in a v2.0.x binary
will no longer recognize these fields.
The k8s API has specific conventions and a process for making changes.
The presence of an apiVersion
field in a k8s
native type signals:
-
its reliability level (alpha vs beta vs generally available),
-
the existence of code to provide default values to fields not present in a serialization,
-
the existence of code to provide both forward and backward conversion between different versions of types.
The k8s API promises a lossless conversion between versions over a specific range. This means that a recent client can write an object bearing the newest possible value for its version, the server will accept it and store it in "versionless" JSON form in storage, and can convert it to a range of older versions should an older client request data.
For native k8s types, this all requires writing Go code in the kubernetes core repo, to provide defaulting and conversions.
For CRDs, there's a proposal on how to manage versioning (e.g. a remote service can offer type defaulting and conversions).
The critical difference between k8s API versioning and kustomization file versioning is
-
A k8s API server is able to go forward and backward in versioning, to work with older clients, over some range.
-
The
kustomize edit fix
command only moves forward within a major program version.
At the time of writing, the YAML in a kustomization file does not represent a k8s API object, and the kustomize command and associated library is neither a server of, nor a client to, the k8s API.
In addition to the field change policy described above, kustomization files conform to the following rules.
Field names with dedicated meaning in k8s
(metadata
, spec
, status
, etc.) aren't used.
This is enforced via code review.
At the time of writing two special k8s
resource fields are allowed, but not required, in
a kustomization file: kind
and apiVersion
.
If either field is present, they both must be, and they must have the following values:
kind: Kustomization
apiVersion: kustomize.config.k8s.io/v1beta1
They are allowed to exist and have specific values in a kustomization file only as a sort of domain-squatting behavior for some future API. A kustomize user gains nothing from adding these fields to a kustomization file.
Use cases for a kustomization file don't include a server storing muliple k8s kinds and offering version downgrades.
The kustomization file is more akin to a
Makefile
. A kustomize command can either read a
kustomization file, or it cannot, and in the later
case will complain as specifically as possible
about why (e.g. unknown field Foo
).
So requiring a kind
and apiVersion
would just
be boilerplate in a user's files, and in all the
examples and tests.
Nevertheless, a user still benefits from a
versioning policy and has a fix
command to
upgrade files as needed.
When/if the kustomization struct graduates to some
kind of API status, with an expectation of
"versionless" storage and downgrade capability,
whatever it looks like at that moment can be
locked into /v1beta1
or /v1
and the kind
and apiVersion
fields can be required from that
moment forward.