Shell-operator is a tool for running event-driven scripts in a Kubernetes cluster.
This operator is not an operator for a particular software product such as prometheus-operator
or kafka-operator
. Shell-operator provides an integration layer between Kubernetes cluster events and shell scripts by treating scripts as hooks triggered by events. Think of it as an operator-sdk
but for scripts.
Shell-operator is used as a base for more advanced addon-operator that supports Helm charts and value storages.
Shell-operator provides:
- Ease of management of a Kubernetes cluster: use the tools that Ops are familiar with. It can be bash, python, kubectl, etc.
- Kubernetes object events: hook can be triggered by
add
,update
ordelete
events. Learn more about hooks. - Object selector and properties filter: shell-operator can monitor a particular set of objects and detect changes in their properties.
- Simple configuration: hook binding definition is a JSON or YAML document on script's stdout.
- Validating webhook machinery: hook can handle validating for Kubernetes resources.
- Conversion webhook machinery: hook can handle version conversion for Kubernetes resources.
Contents:
- Quickstart
- Hook binding types
- Prometheus target
- Examples and notable users
- Articles & talks
- Community
- License
You need to have a Kubernetes cluster, and the
kubectl
must be configured to communicate with your cluster.
The simplest setup of shell-operator in your cluster consists of these steps:
- build an image with your hooks (scripts)
- create necessary RBAC objects (for
kubernetes
bindings) - run Pod or Deployment with the built image
For more configuration options see RUNNING.
A hook is a script that, when executed with --config
option, outputs configuration to stdout in YAML or JSON format. Learn more about hooks.
Let's create a small operator that will watch for all Pods in all Namespaces and simply log the name of a new Pod.
kubernetes
binding is used to tell shell-operator about objects that we want to watch. Create the pods-hook.sh
file with the following content:
#!/usr/bin/env bash
if [[ $1 == "--config" ]] ; then
cat <<EOF
configVersion: v1
kubernetes:
- apiVersion: v1
kind: Pod
executeHookOnEvent: ["Added"]
EOF
else
podName=$(jq -r .[0].object.metadata.name $BINDING_CONTEXT_PATH)
echo "Pod '${podName}' added"
fi
Make the pods-hook.sh
executable:
chmod +x pods-hook.sh
You can use a prebuilt image flant/shell-operator:latest with bash
, kubectl
, jq
and shell-operator
binaries to build you own image. You just need to ADD
your hook into /hooks
directory in the Dockerfile
.
Create the following Dockerfile
in the directory where you created the pods-hook.sh
file:
FROM flant/shell-operator:latest
ADD pods-hook.sh /hooks
Build an image (change image tag according to your Docker registry):
docker build -t "registry.mycompany.com/shell-operator:monitor-pods" .
Push image to the Docker registry accessible by the Kubernetes cluster:
docker push registry.mycompany.com/shell-operator:monitor-pods
We need to watch for Pods in all Namespaces. That means that we need specific RBAC definitions for shell-operator:
kubectl create namespace example-monitor-pods
kubectl create serviceaccount monitor-pods-acc --namespace example-monitor-pods
kubectl create clusterrole monitor-pods --verb=get,watch,list --resource=pods
kubectl create clusterrolebinding monitor-pods --clusterrole=monitor-pods --serviceaccount=example-monitor-pods:monitor-pods-acc
Shell-operator can be deployed as a Pod. Put this manifest into the shell-operator-pod.yaml
file:
apiVersion: v1
kind: Pod
metadata:
name: shell-operator
spec:
containers:
- name: shell-operator
image: registry.mycompany.com/shell-operator:monitor-pods
imagePullPolicy: Always
serviceAccountName: monitor-pods-acc
Start shell-operator by applying a shell-operator-pod.yaml
file:
kubectl -n example-monitor-pods apply -f shell-operator-pod.yaml
Let's deploy a kubernetes-dashboard to trigger kubernetes
binding defined in our hook:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/aio/deploy/recommended.yaml
Now run kubectl -n example-monitor-pods logs po/shell-operator
and observe that the hook will print dashboard pod name:
...
INFO[0027] queue task HookRun:main operator.component=handleEvents queue=main
INFO[0030] Execute hook binding=kubernetes hook=pods-hook.sh operator.component=taskRunner queue=main task=HookRun
INFO[0030] Pod 'kubernetes-dashboard-775dd7f59c-hr7kj' added binding=kubernetes hook=pods-hook.sh output=stdout queue=main task=HookRun
INFO[0030] Hook executed successfully binding=kubernetes hook=pods-hook.sh operator.component=taskRunner queue=main task=HookRun
...
Note: hook output is logged with output=stdout label.
To clean up a cluster, delete namespace and RBAC objects:
kubectl delete ns example-monitor-pods
kubectl delete clusterrole monitor-pods
kubectl delete clusterrolebinding monitor-pods
This example is also available in /examples: monitor-pods.
Every hook should respond with JSON or YAML configuration of bindings when executed with --config
flag.
This binding defines a subset of Kubernetes objects that shell-operator will monitor and a jq expression to filter their properties. Read more about onKubernetesEvent
bindings here.
Example of YAML output from hook --config
:
configVersion: v1
kubernetes:
- name: execute_on_changes_of_namespace_labels
kind: Namespace
executeHookOnEvent: ["Modified"]
jqFilter: ".metadata.labels"
Note: it is possible to watch Custom Defined Resources, just use proper values for
apiVersion
andkind
fields.
Note: return configuration as JSON is also possible as JSON is a subset of YAML.
This binding has only one parameter: order of execution. Hooks are loaded at the start and then hooks with onStartup binding are executed in the order defined by parameter. Read more about onStartup
bindings here.
Example hook --config
:
configVersion: v1
onStartup: 10
This binding is used to execute hooks periodically. A schedule can be defined with a granularity of seconds. Read more about schedule
bindings here.
Example hook --config
with 2 schedules:
configVersion: v1
schedule:
- name: "every 10 min"
crontab: "*/10 * * * *"
allowFailure: true
- name: "Every Monday at 8:05"
crontab: "5 8 * * 1"
queue: mondays
Shell-operator provides a /metrics
endpoint. More on this in METRICS document.
More examples of how you can use shell-operator are available in the examples directory.
Prominent shell-operator use cases include:
- Deckhouse Kubernetes platform where both projects, shell-operator and addon-operator, are used as the core technology to configure & extend K8s features;
- KubeSphere Kubernetes platform's installer;
- Kafka DevOps solution from Confluent.
Please find out & share more examples in Show & tell discussions.
Shell-operator has been presented during KubeCon + CloudNativeCon Europe 2020 Virtual (Aug'20). Here is the talk called "Go? Bash! Meet the shell-operator":
Official publications on shell-operator:
- "shell-operator v1.0.0: the long-awaited release of our tool to create Kubernetes operators" (Apr'21);
- "shell-operator & addon-operator news: hooks as admission webhooks, Helm 3, OpenAPI, Go hooks, and more!" (Feb'21);
- "Kubernetes operators made easy with shell-operator: project status & news" (Jul'20);
- "Announcing shell-operator to simplify creating of Kubernetes operators" (May'19).
Other languages:
- Chinese: "介绍一个不太小的工具:Shell Operator"; "使用shell-operator实现Operator";
- Dutch: "Een operator om te automatiseren – Hoe pak je dat aan?";
- Russian: "shell-operator v1.0.0: долгожданный релиз нашего проекта для Kubernetes-операторов"; "Представляем shell-operator: создавать операторы для Kubernetes стало ещё проще".
Please feel free to reach developers/maintainers and users via GitHub Discussions for any questions regarding shell-operator.
You're also welcome to follow @flant_com to stay informed about all our Open Source initiatives.
Apache License 2.0, see LICENSE.