Containerized KRM Functions

Guide to writing containerized KRM functions for use as Kustomize plugins

Authoring Containerized KRM Functions

A containerized KRM Function is any container whose entrypoint accepts a ResourceList as input on stdin and emits a ResourceList as output on stdout, in accordance with the KRM Functions Specification.

Configuration

Containerized KRM Function plugins are referenced directly by the metadata of the KRM object used to configure them.

For example, the plugin configuration might look like:

apiVersion: someteam.example.com/v1 kind: ChartInflator metadata:  name: notImportantHere  annotations:  config.kubernetes.io/function: |  container:  image: example.docker.com/my-functions/chart-inflator:0.1.6 spec:  chartName: minecraft 

Guided example

This is a (no reading allowed!) 60 second copy/paste guided example.

This demo writes and uses a somewhat ridiculous containerized plugin (written in Go) that follows the KRM Function Specification and generates a ConfigMap.

Prerequisites:

  • linux or osx
  • curl
  • bash
  • docker
  • Go 1.16

Make a place to work

DEMO=$(mktemp -d) 

Install kustomize

Per the instructions:

curl -s "https://raw.githubusercontent.com/\ kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash mkdir -p $DEMO/bin mv kustomize $DEMO/bin 

Create a kustomization

Make a kustomization directory to hold all your config:

MYAPP=$DEMO/myapp mkdir -p $MYAPP 

Make a service config:

# $MYAPP/service.yaml kind: Service apiVersion: v1 metadata:  name: the-service spec:  type: LoadBalancer  ports:  - protocol: TCP  port: 8666  targetPort: 8080 

Now make a config file for the plugin you’re about to write.

This config file is just another Kubernetes resource object. The config.kubernetes.io/function annotation is used to find the docker container that implements the ValueAnnotator type.

# $MYAPP/annotator.yaml apiVersion: transformers.example.co/v1 kind: ValueAnnotator metadata:  name: notImportantHere  annotations:  config.kubernetes.io/function: |  container:  image: example.docker.com/my-functions/valueannotator:1.0.0 value: 'important-data' 

Finally, make a kustomization file referencing all of the above:

# $MYAPP/kustomization.yaml resources: - service.yaml transformers: - annotator.yaml 

Review the files

ls -C1 $MYAPP 

Make a home for plugins

Since Kustomize accesses your code indirectly through the container, you can develop containerized plugins anywhere you’d like within your Go path.

Let’s create a new directory for our code:

mkdir $GOPATH/src/kustomize-plugin-demo 

Create the plugin

First initialize the plugin directory with go mod:

cd $GOPATH/src/kustomize-plugin-demo 

Create the main.go with the demo code:

// $GOPATH/src/kustomize-plugin-demo/main.go package main import ( "os" "sigs.k8s.io/kustomize/kyaml/fn/framework" "sigs.k8s.io/kustomize/kyaml/fn/framework/command" "sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/yaml" ) type ValueAnnotator struct { Value string `yaml:"value" json:"value"` } func main() { config := new(ValueAnnotator) fn := func(items []*yaml.RNode) ([]*yaml.RNode, error) { for i := range items { err := items[i].PipeE(yaml.SetAnnotation("custom.io/the-value", config.Value)) if err != nil { return nil, err } } return items, nil } p := framework.SimpleProcessor{Config: config, Filter: kio.FilterFunc(fn)} cmd := command.Build(p, command.StandaloneDisabled, false) command.AddGenerateDockerfile(cmd) if err := cmd.Execute(); err != nil { os.Exit(1) } } 

Create the go module

go mod init go mod tidy 

Generate the dockerfile

Because our program uses command.AddGenerateDockerfile(cmd), go can generate a default Dockerfile for us:

go run main.go gen . 

Build the container

docker build . -t example.docker.com/my-functions/valueannotator:1.0.0 

Note that since this is a quick local-only demo, we do not need to push the image, and the tag doesn’t need to refer to a real docker registry.

Build your app

$DEMO/bin/kustomize build --enable-alpha-plugins $MYAPP 

You should see the “important-data” added to the Service’s annotations.

Clean up

rm -r $GOPATH/src/kustomize-plugin-demo