How to Create a Sonobuoy Plugin
Today we are going to learn how to create a Sonobuoy plugin. Sonobuoy plugins are some metadata in the form of a YAML file that deploys a container that has the actual code that is responsible for executing the test or tests. Plugins come in two types, a daemonset or a job. We will be building a job plugin.
Description
We will create a plugin that will deploy the pstools container as a daemonset. This will ensure that it is deployed to every node in the cluster. This doesn’t seem like much a a test, except this is a mixed workload cluster running both Windows and Linux nodes. This will test that our container is compatible with all the nodes that we have in our cluster. I will be running my cluster using Rancher with a downstream cluster that is RKE2 v1.22.4 using Calico for CNI. My nodes will be openSUSE Leap 15.3 for the control plane, linux worker, and Windows 2019 for the other worker node. That’s it for the high level of what we are going to achieve.
Creating the Plugin
The first step is to create our directory.
mkdir mixed-workload-e2e
cd mixed-workload-e2e
We can now use the Sonobuoy CLI to generate our plugin YAML file.
sonobuoy gen plugin -n mixed-workload-e2e \
-f junit \
-i phillipsj/mixed-workload-e2e:latest > mixed-workload-e2e.yaml
We will need to do a little modification like specifying the node selector and architecture we want to support. In addition to that we can add some metadata.
podSpec:
nodeSelector:
kubernetes.io/os: linux
kubernetes.io/arch: amd64
containers: []
restartPolicy: Never
serviceAccountName: sonobuoy-serviceaccount
sonobuoy-config:
driver: Job
plugin-name: mixed-workload-e2e
result-format: junit
source_url: https://raw.githubusercontent.com/phillipsj/my-sonobuoy-plugins/main/mixed-workload-e2e/mixed-workload-e2e.yaml
description: A plugin for deploying a mixed OS workload for ensuring that your image deploys correctly.
spec:
image: phillipsj/mixed-workload-e2e:latest
name: plugin
resources: {}
volumeMounts:
- mountPath: /tmp/sonobuoy/results
name: results
Next we need to create the manifest file for the pstools daemonset workload.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: mixed-workload
labels:
app: mixed-workload
spec:
selector:
matchLabels:
name: mixed-workload
template:
metadata:
labels:
name: mixed-workload
spec:
tolerations:
# this toleration is to have the daemonset runnable on master nodes
# remove it if your masters can't run pods
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
containers:
- name: mixed-workload
image: phillipsj/pstools:v0.2.0
We need a way to execute our manifest and then generate our results. The default plugin has a reference to a run.sh
so we will use that to execute our tests and move our results file.
#! /bin/bash
sh ./t/workload.t -j
mv /t/workload.t-tests.xml /tmp/sonobuoy/results
We are going to just use Bash, kubectl, and osht to create our tests. We will do a really basic test by using kubectl get to the number of nodes we have. Then we will apply our manifest and wait for it to be deployed succesfully. Finally, we will use kubectl to get our pods and verify that the number of pods match the number of nodes. We will need to create a directroy called t
and our test file called workload.t
. In our workload.t
file we place our code.
#!/bin/bash
set -eu
. osht.sh
PLAN 3
nodes=$(kubectl get nodes -o json | jq -r '.items[] | select(.status.phase = "Ready") | .metadata.name' | wc -l)
echo -e "Nodes: $nodes"
RUNS kubectl apply -f manifest.yaml
RUNS kubectl rollout status daemonsets/mixed-workload
pods=$(kubectl get pod -l "name=mixed-workload" -o json | jq -r '.items[] | select(.status.phase = "Running") | .metadata.name' | wc -l)
echo -r "Pods: $pods"
IS $nodes == $pods
Finally, we can create the last piece which is our Dockerfile
for creating our container. We will use the SUSE SLE Base Container Image which we will install kubectl, osht, and our files.
FROM registry.suse.com/suse/sle15:latest
COPY . /
RUN zypper --non-interactive install curl jq \
&& curl -LO https://dl.k8s.io/release/v1.23.0/bin/linux/amd64/kubectl \
&& chmod +x kubectl \
&& mv kubectl /usr/local/bin/kubectl \
&& cd t \
&& curl -LO https://raw.githubusercontent.com/coryb/osht/master/osht.sh
WORKDIR /
ENTRYPOINT ["sh", "run.sh"]
Let’s build, tag, and push our container.
docker build . -t phillipsj/mixed-workload-e2e:latest -t phillipsj/mixed-workload-e2e:v0.1.0
docker push phillipsj/mixed-workload-e2e --all-tags
We now have everything in place that we can run our plugin.
Running our Sonobuoy Plugin
The Sonobuoy CLI can be used to execute our plugin and make sure to include a node selector or the aggregator since it is a mixed OS cluster.
$ sonobuoy run --plugin mixed-workload-e2e.yaml --aggregator-node-selector kubernetes.io/os=linux
INFO[0000] create request issued name=sonobuoy namespace= resource=namespaces
INFO[0000] create request issued name=sonobuoy-serviceaccount namespace=sonobuoy resource=serviceaccounts
INFO[0000] create request issued name=sonobuoy-serviceaccount-sonobuoy namespace= resource=clusterrolebindings
INFO[0000] create request issued name=sonobuoy-serviceaccount-sonobuoy namespace= resource=clusterroles
INFO[0000] create request issued name=sonobuoy-config-cm namespace=sonobuoy resource=configmaps
INFO[0000] create request issued name=sonobuoy-plugins-cm namespace=sonobuoy resource=configmaps
INFO[0000] create request issued name=sonobuoy namespace=sonobuoy resource=pods
INFO[0000] create request issued name=sonobuoy-aggregator namespace=sonobuoy resource=services
Let’s check the status.
$ sonobuoy status
PLUGIN STATUS RESULT COUNT PROGRESS
mixed-workload-e2e complete passed 1
Sonobuoy plugins have completed. Preparing results for download.
Our Sonobuoy test passed and all we need to do is cleanup.
$ sonobuoy delete
INFO[0000] delete request issued kind=namespace namespace=sonobuoy
INFO[0000] delete request issued kind=clusterrolebindings
INFO[0000] delete request issued kind=clusterroles
Wrapping Up
We have reached the end and we have a functioning plugin. I hope this helps you create your own plugins. You can check out my repo here.
Thanks for reading,
Jamie
If you enjoy the content, then consider buying me a coffee.