Creating External Plugins for Kubebuilder
Overview
Kubebuilder’s functionality can be extended through external plugins.
These plugins are executables (written in any language) that follow an
execution pattern recognized by Kubebuilder. Kubebuilder interacts with
these plugins via stdin and stdout, enabling seamless communication.
Why Use External Plugins?
External plugins enable third-party solution maintainers to integrate their tools with Kubebuilder. Much like Kubebuilder’s own plugins, these can be opt-in, offering users flexibility in tool selection. By developing plugins in their repositories, maintainers ensure updates are aligned with their CI pipelines and can manage any changes within their domain of responsibility.
If you are interested in this type of integration, collaborating with the maintainers of the third-party solution is recommended. Kubebuilder’s maintainers are always willing to provide support in extending its capabilities.
How to Write an External Plugin
Communication between Kubebuilder and an external plugin occurs via standard I/O. Any language can be used to create the plugin, as long as it follows the PluginRequest and PluginResponse structures.
PluginRequest contains the data collected from the CLI and any previously executed plugins. Kubebuilder sends this data as a JSON object to the external plugin via stdin.
Fields:
apiVersion: Version of the PluginRequest schema.args: Command-line arguments passed to the plugin.command: The subcommand being executed (e.g.,init,create api,create webhook,edit).universe: Map of file paths to contents, updated across the plugin chain.pluginChain(optional): Array of plugin keys in the order they were executed. External plugins can inspect this to tailor behavior based on other plugins that ran (for example,go.kubebuilder.io/v4orkustomize.common.kubebuilder.io/v2).config(optional): Serialized PROJECT file configuration for the current project. Use it to inspect metadata, existing resources, or plugin-specific settings. Kubebuilder omits this field before the PROJECT file exists—typically during the firstinit—so plugins should check for its presence.
Note: Whenever Kubebuilder has a PROJECT file available (for example during create api, create webhook, edit, or a subsequent init run), PluginRequest includes the config field. During the very first init run the field is omitted because the PROJECT file does not exist yet.
Example PluginRequest (triggered by kubebuilder init --plugins go/v4,sampleexternalplugin/v1 --domain my.domain):
{
"apiVersion": "v1alpha1",
"args": ["--domain", "my.domain"],
"command": "init",
"universe": {},
"pluginChain": ["go.kubebuilder.io/v4", "kustomize.common.kubebuilder.io/v2", "sampleexternalplugin/v1"]
}
Example PluginRequest for create api (includes config):
{
"apiVersion": "v1alpha1",
"args": ["--group", "crew", "--version", "v1", "--kind", "Captain"],
"command": "create api",
"universe": {},
"pluginChain": ["go.kubebuilder.io/v4", "kustomize.common.kubebuilder.io/v2", "sampleexternalplugin/v1"],
"config": {
"domain": "my.domain",
"repo": "github.com/example/my-project",
"projectName": "my-project",
"version": "3",
"layout": ["go.kubebuilder.io/v4"],
"multigroup": false,
"resources": []
}
}
Example PluginRequest (triggered by kubebuilder edit --plugins sampleexternalplugin/v1):
{
"apiVersion": "v1alpha1",
"args": [],
"command": "edit",
"universe": {}
}
PluginResponse
PluginResponse contains the modifications made by the plugin to the project. This data is serialized as JSON and returned to Kubebuilder through stdout.
Example PluginResponse:
{
"apiVersion": "v1alpha1",
"command": "edit",
"metadata": {
"description": "The `edit` subcommand adds Prometheus instance configuration for monitoring your operator.",
"examples": "kubebuilder edit --plugins sampleexternalplugin/v1"
},
"universe": {
"config/prometheus/prometheus.yaml": "# Prometheus CR manifest...",
"config/prometheus/kustomization.yaml": "resources:\n - prometheus.yaml\n",
"config/default/kustomization_prometheus_patch.yaml": "# Instructions for enabling Prometheus..."
},
"error": false,
"errorMsgs": []
}
How to Use an External Plugin
Prerequisites
- Kubebuilder CLI version > 3.11.0
- An executable for the external plugin
- Plugin path configuration using
${EXTERNAL_PLUGINS_PATH}or default OS-based paths:- Linux:
$HOME/.config/kubebuilder/plugins/${name}/${version}/${name} - macOS:
~/Library/Application Support/kubebuilder/plugins/${name}/${version}/${name}
- Linux:
Example: For a plugin foo.acme.io version v2 on Linux, the path would be $HOME/.config/kubebuilder/plugins/foo.acme.io/v2/foo.acme.io.
Available Subcommands
External plugins can support the following Kubebuilder subcommands:
init: Project initializationcreate api: Scaffold Kubernetes API definitionscreate webhook: Scaffold Kubernetes webhooksedit: Update project configuration
Optional subcommands for enhanced user experience:
metadata: Provide plugin descriptions and examples with the--helpflag.flags: Inform Kubebuilder of supported flags, enabling early error detection.
Configuring Plugin Path
Set the environment variable $EXTERNAL_PLUGINS_PATH
to specify a custom plugin binary path:
export EXTERNAL_PLUGINS_PATH=<custom-path>
Otherwise, Kubebuilder would search for the plugins in a default path based on your OS.
Example CLI Commands
You can now use it by calling the CLI commands:
# Add Prometheus monitoring to an existing project
kubebuilder edit --plugins sampleexternalplugin/v1
# Update an existing project with Prometheus monitoring
kubebuilder edit --plugins sampleexternalplugin/v1
# Display help information for the init subcommand
kubebuilder init --plugins sampleexternalplugin/v1 --help
# Display help information for the edit subcommand
kubebuilder edit --plugins sampleexternalplugin/v1 --help
# Plugin chaining example: Use go/v4 plugin first, then apply external plugin
kubebuilder edit --plugins go/v4,sampleexternalplugin/v1