mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-18 03:45:12 +00:00
349 lines
10 KiB
Markdown
349 lines
10 KiB
Markdown
# kustomize plugins
|
|
|
|
Kustomize offers a plugin framework allowing
|
|
people to write their own resource _generators_
|
|
and _transformers_.
|
|
|
|
[generator options]: ../examples/generatorOptions.md
|
|
[transformer configs]: ../examples/transformerconfigs
|
|
|
|
Write a plugin when changing [generator options]
|
|
or [transformer configs] doesn't meet your needs.
|
|
|
|
[12-factor]: https://12factor.net
|
|
|
|
* A _generator_ plugin could be a helm chart
|
|
inflator, or a plugin that emits all the
|
|
components (deployment, service, scaler,
|
|
ingress, etc.) needed by someone's [12-factor]
|
|
application, based on a smaller number of free
|
|
variables.
|
|
|
|
* A _transformer_ plugin might perform special
|
|
container command line edits, or any other
|
|
transformation that exceeds the power of the
|
|
builtin transformations (`namePrefix`,
|
|
`commonLabels`, etc.).
|
|
|
|
## Specification in `kustomization.yaml`
|
|
|
|
Start by adding a `generators` and/or `transformers`
|
|
field to your kustomization.
|
|
|
|
Each field accepts a string list:
|
|
|
|
> ```
|
|
> generators:
|
|
> - relative/path/to/some/file.yaml
|
|
> - relative/path/to/some/kustomization
|
|
> - /absolute/path/to/some/kustomization
|
|
> - https://github.com/org/repo/some/kustomization
|
|
>
|
|
> transformers:
|
|
> - {as above}
|
|
> ```
|
|
|
|
This is exactly like the syntax of the `resources`
|
|
field.
|
|
|
|
The value of each entry in a `resources`,
|
|
`generators` or `transformers` list must be a
|
|
relative path to a YAML file, or a path or URL
|
|
to a [kustomization].
|
|
|
|
[kustomization]: glossary.md#kustomization
|
|
|
|
In the former case the YAML is read from disk directly,
|
|
and in the latter case a kustomization is performed,
|
|
and its YAML output is merged with the YAML read
|
|
directly from files. The net result in all three cases
|
|
is a set of YAML objects.
|
|
|
|
Each object resulting from a `generators` or
|
|
`transformers` field is now further interpreted by
|
|
kustomize as a _plugin configuration_ object.
|
|
|
|
## Configuration
|
|
|
|
A kustomization file could have the following lines:
|
|
|
|
```
|
|
generators:
|
|
- chartInflator.yaml
|
|
```
|
|
|
|
Given this, the kustomization process would expect to
|
|
find a file called `chartInflator.yaml` in the
|
|
kustomization [root](glossary.md#kustomization-root).
|
|
|
|
This is the _plugin's configuration file_.
|
|
|
|
The file `chartInflator.yaml` could contain:
|
|
|
|
```
|
|
apiVersion: someteam.example.com/v1
|
|
kind: ChartInflator
|
|
metadata:
|
|
name: notImportantHere
|
|
chartName: minecraft
|
|
```
|
|
|
|
__The `apiVersion` and `kind` fields are
|
|
used to locate the plugin.__
|
|
|
|
[k8s object]: glossary.md#kubernetes-style-object
|
|
|
|
> Thus, these fields are required. They are also
|
|
> required because a kustomize plugin
|
|
> configuration object is also a [k8s object].
|
|
|
|
To get the plugin ready to generator or transform,
|
|
it is given the entire contents of the
|
|
configuration file.
|
|
|
|
[NameTransformer]: ../plugin/builtin/prefixsuffixtransformer/PrefixSuffixTransformer_test.go
|
|
[ChartInflator]: ../plugin/someteam.example.com/v1/chartinflator/ChartInflator_test.go
|
|
[plugins]: ../plugin/builtin
|
|
|
|
For more examples of plugin configuration YAML,
|
|
browse the unit tests below the [plugins] root,
|
|
e.g. the tests for [ChartInflator] or
|
|
[NameTransformer].
|
|
|
|
|
|
## Placement
|
|
|
|
Each plugin gets its own dedicated directory named
|
|
|
|
```
|
|
$XDG_CONFIG_HOME/kustomize/plugin
|
|
/${apiVersion}/LOWERCASE(${kind})
|
|
```
|
|
|
|
The default value of `XDG_CONFIG_HOME` is
|
|
`$HOME/.config`.
|
|
|
|
The one-plugin-per-directory requirement eases
|
|
creation of a plugin tarball (source, test, plugin
|
|
data files, etc.) for sharing.
|
|
|
|
In the case of a [Go plugin](#go-plugins), it also
|
|
allows one to provide a `go.mod` file for the
|
|
single plugin, easing resolution of package
|
|
version dependency skew.
|
|
|
|
When loading, kustomize will first look for an
|
|
_executable_ file called
|
|
|
|
```
|
|
$XDG_CONFIG_HOME/kustomize/plugin
|
|
/${apiVersion}/LOWERCASE(${kind})/${kind}
|
|
```
|
|
|
|
If this file is not found or is not executable,
|
|
kustomize will look for a file called `${kind}.so`
|
|
in the same directory and attempt to load it as a
|
|
[Go plugin](#go-plugins).
|
|
|
|
If both checks fail, the plugin load fails the overall
|
|
`kustomize build`.
|
|
|
|
## Execution
|
|
|
|
Plugins are only used during a run of the
|
|
`kustomize build` command.
|
|
|
|
Generator plugins are run after processing the
|
|
`resources` field (which itself is in some sense a
|
|
generator in that it emits resources for further
|
|
processing).
|
|
|
|
The full set of resources is then passed into the
|
|
transformation pipeline, wherein builtin
|
|
transformations like `namePrefix` and
|
|
`commonLabel` are applied (if they were specified
|
|
in the kustomization file), followed by the
|
|
user-specified transformers in the `transformers`
|
|
field.
|
|
|
|
The specified order of transformers in the
|
|
`transformers` field should be respected, as
|
|
transformers cannot be expected to be commutative.
|
|
|
|
A `kustomize build` that tries to use plugins but
|
|
omits the flag
|
|
|
|
> `--enable_alpha_plugins`
|
|
|
|
will fail with a warning about plugin use.
|
|
|
|
Flag use is an opt-in acknowledging the absence of
|
|
plugin provenance. It's meant to give pause to
|
|
someone who blindly downloads a kustomization from
|
|
the internet and attempts to run it, without
|
|
realizing that it might attempt to run 3rd party
|
|
code in plugin form. The plugin would have to be
|
|
installed already, but nevertheless the flag is a
|
|
reminder.
|
|
|
|
|
|
## Writing plugins
|
|
|
|
### Exec plugins
|
|
|
|
A _exec plugin_ is any executable that accepts a
|
|
single argument on its command line - the name of
|
|
a YAML file containing its configuration (the file name
|
|
provided in the kustomization file).
|
|
|
|
> TODO: more restrictions on plugin to allow the same exec
|
|
> plugin to be specified in a config under both the
|
|
> `generators` and `transformers` fields.
|
|
> - first arg could be the fixed string
|
|
> `generate` or `transform`,
|
|
> (the name of the configuration file moves to
|
|
> the 2nd arg), or
|
|
> - by default an exec plugin behaves as a tranformer
|
|
> unless a flag `-g` is provided, switching the
|
|
> exec plugin to behave as a generator.
|
|
|
|
[helm chart inflator]: ../plugin/someteam.example.com/v1/chartinflator
|
|
[bashed config map]: ../plugin/someteam.example.com/v1/bashedconfigmap
|
|
[sed transformer]: ../plugin/someteam.example.com/v1/sedtransformer
|
|
|
|
#### Examples
|
|
|
|
* [helm chart inflator] - A generator that inflates a helm chart.
|
|
* [bashed config map] - Super simple configMap generation from bash.
|
|
* [sed transformer] - Define your unstructured edits using a
|
|
plugin like this one.
|
|
|
|
|
|
A generator plugin accepts nothing on `stdin`, but emits
|
|
generated resources to `stdout`.
|
|
|
|
A transformer plugin accepts resource YAML on `stdin`,
|
|
and emits those resources, presumably transformed, to
|
|
`stdout`.
|
|
|
|
kustomize uses an exec plugin adapter to provide
|
|
marshalled resources on `stdin` and capture
|
|
`stdout` for further processing.
|
|
|
|
### Go plugins
|
|
|
|
[Go plugin]: https://golang.org/pkg/plugin/
|
|
|
|
A [Go plugin] for kustomize looks like this:
|
|
|
|
> ```
|
|
> package main
|
|
>
|
|
> import (
|
|
> "sigs.k8s.io/kustomize/pkg/ifc"
|
|
> "sigs.k8s.io/kustomize/pkg/resmap"
|
|
> ...
|
|
> )
|
|
>
|
|
> type plugin struct {...}
|
|
>
|
|
> var KustomizePlugin plugin
|
|
>
|
|
> func (p *plugin) Config(
|
|
> ldr ifc.Loader,
|
|
> rf *resmap.Factory,
|
|
> c []byte) error {...}
|
|
>
|
|
> func (p *plugin) Generate() (resmap.ResMap, error) {...}
|
|
>
|
|
> func (p *plugin) Transform(m resmap.ResMap) error {...}
|
|
> ```
|
|
|
|
Use of the identifiers `plugin`, `KustomizePlugin`
|
|
and implementation of the method signature
|
|
`Config` is required.
|
|
|
|
Implementing the `Generator` or `Transformer`
|
|
method allows (respectively) the plugin's config
|
|
file to be added to the `generators` or
|
|
`transformers` field in the kustomization file.
|
|
Do one or the other or both as desired.
|
|
|
|
[secret generator]: ../plugin/someteam.example.com/v1/secretsfromdatabase
|
|
[service generator]: ../plugin/someteam.example.com/v1/someservicegenerator
|
|
[string prefixer]: ../plugin/someteam.example.com/v1/stringprefixer
|
|
[date prefixer]: ../plugin/someteam.example.com/v1/dateprefixer
|
|
|
|
|
|
#### Examples
|
|
|
|
* [secret generator] - Generate secrets from a database.
|
|
* [service generator] - Generate a service from a name and port argument.
|
|
* [string prefixer] - uses the value in `metadata/name` as the prefix.
|
|
This particular example exists to show how a plugin can
|
|
transform the behavior of a plugin. See the
|
|
`TestTransformedTransformers` test in the `target` package.
|
|
* [date prefixer] - prefix the current date to resource names, a simple
|
|
example used to modify the string prefixer plugin just mentioned.
|
|
* All the builtin plugins [here](../plugin/builtin).
|
|
User authored plugins are
|
|
on the same footing as builtin operations.
|
|
|
|
A plugin can be both a generator and a
|
|
transformer. The `Generate` method will run along
|
|
with all the other generators before the
|
|
`Transform` method runs.
|
|
|
|
Here's a build command that sensibly assumes the
|
|
plugin source code sits in the directory where
|
|
kustomize expects to find `.so` files:
|
|
|
|
```
|
|
d=$XDG_CONFIG_HOME/kustomize/plugin\
|
|
/${apiVersion}/LOWERCASE(${kind})
|
|
|
|
go build -buildmode plugin \
|
|
-o $d/${kind}.so $d/${kind}.go
|
|
```
|
|
|
|
#### Caveats
|
|
|
|
Go plugins allow kustomize extensions that run
|
|
without the cost marshalling/unmarshalling all
|
|
resource data to/from a subprocess for each plugin
|
|
run.
|
|
|
|
[ELF]: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
|
|
|
|
Go plugins work as [defined][Go plugin], but fall
|
|
short of common notions associated with the word
|
|
_plugin_. Go plugin compilation creates an [ELF]
|
|
formatted `.so` file, which by definition has no
|
|
information about the provenance of the object
|
|
code. Skew between the compilation conditions
|
|
(versions of package dependencies, `GOOS`,
|
|
`GOARCH`) of the main program ELF and the plugin
|
|
ELF will cause plugin load failure.
|
|
|
|
Exec plugins also lack provenance, but won't
|
|
complain about compilation skew.
|
|
|
|
In either case, a sensible way to share a plugin
|
|
is as a tar file of source code, tests and
|
|
associated data, unpackable under
|
|
`$XDG_CONFIG_HOME/kustomize/plugin` (exactly where
|
|
one would develop a plugin).
|
|
|
|
[Go modules]: https://github.com/golang/go/wiki/Modules
|
|
|
|
In the case of a Go plugin, an end user accepting
|
|
a shared plugin must compile both kustomize and
|
|
the plugin. Tooling could be built to make Go
|
|
_plugin sharing_ easier, but this requires some
|
|
critical mass of _plugin authoring_, which in turn
|
|
is hampered by confusion around sharing.
|
|
[Go modules], once they are more widely adopted,
|
|
will solve one of the biggest plugin sharing
|
|
difficulties - ambiguous plugin vs host
|
|
dependencies.
|