Exec plugin example

Exec plugin in 60 seconds

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

This demo writes and uses a somewhat ridiculous exec plugin (written in bash) that generates a ConfigMap.

This is a guide to try it without damaging your current setup.

Requirements

  • linux or osx
  • git, curl, bash, Go 1.16

Make a place to work

DEMO=$(mktemp -d)

Create a kustomization

Make a kustomization directory to hold all your config:

MYAPP=$DEMO/myapp
mkdir -p $MYAPP

Make a deployment config:

# $MYAPP/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: the-deployment
spec:
  replicas: 3
  template:
    spec:
      containers:
      - name: the-container
        image: monopole/hello:1
        command: ["/hello",
                  "--port=8080",
                  "--date=$(THE_DATE)",
                  "--enableRiskyFeature=$(ENABLE_RISKY)"]
        ports:
        - containerPort: 8080
        env:
        - name: THE_DATE
          valueFrom:
            configMapKeyRef:
              name: the-map
              key: today
        - name: ALT_GREETING
          valueFrom:
            configMapKeyRef:
              name: the-map
              key: altGreeting
        - name: ENABLE_RISKY
          valueFrom:
            configMapKeyRef:
              name: the-map
              key: enableRisky

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 plugin code on your filesystem (more on this later).

# $MYAPP/cmGenerator.yaml
apiVersion: myDevOpsTeam
kind: SillyConfigMapGenerator
metadata:
  name: whatever
  annotations:
    config.kubernetes.io/function: |
      exec: 
        path: ./plugins/silly-generator.sh      
spec:
  altGreeting: Bienvenue
  enableRisky: true

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

# $MYAPP/kustomization.yaml
commonLabels:
  app: hello
resources:
- deployment.yaml
- service.yaml
generators:
- cmGenerator.yaml

Review the files

ls -C1 $MYAPP

Make a home for plugins

Due to their inherent lack of security, exec plugins should be bespoke to and distributed along with the Kustomization they are for. Plugins intended for reuse should be containerized.

The plugin config defined above in $MYAPP/cmGenerator.yaml specifies:

metadata:
  annotations:
    config.kubernetes.io/function: |
      exec: 
        path: ./plugins/silly-generator.sh      

So let’s create that directory:

mkdir $MYAPP/plugins

A plugin gets its own directory to hold itself, its tests and any supplemental data files it might need.

Create the plugin

# $MYAPP/plugins/silly-generator.sh
#!/bin/bash
today=`date +%F`
resourceList=$(cat) # read the `kind: ResourceList` from stdin
altGreeting=$(echo "$resourceList" | yq e '.functionConfig.spec.altGreeting' - )
enableRisky=$(echo "$resourceList" | yq e '.functionConfig.spec.enableRisky' - )

echo "
kind: ResourceList
items:
- kind: ConfigMap
  apiVersion: v1
  metadata:
    name: the-map
  data:
    today: $today
    altGreeting: "$altGreeting"
    enableRisky: "$enableRisky"
"

By definition, an exec plugin must be executable:

chmod a+x $MYAPP/plugins/silly-generator.sh

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

Review the layout

tree $DEMO

Build your app, using the plugin

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

Last modified October 12, 2021: [ci skip] wip (d8c64f9)