介绍一个不太小的工具:Shell Operator
Shell Operator 是个冷僻又有点用的东西。这个工具的角度比较刁钻——使用的特定事件来触发 Shell 脚本。
这个工具的使用方式也很有趣,要定义某个任务:
编写任务脚本
使用它的基础镜像,加入任务脚本,打包生成一个 Docker 镜像并推送
把镜像部署到集群之中
对应事件出现时,将执行该任务脚本。
触发方法
Shell Operator 支持多种事件触发,包括 Kubernetes、启动时执行以及定期执行。
定期执行方式可以使用类似 Crontab 的语法,定义特定时间内执行指定脚本。
启动时执行只会执行一次。
Kubernetes 事件触发条件和 Admission Webhook 类似,但是更加细致,支持多种对象的 Added、Modified、Deleted 操作。可以根据名称、标签、特定字段、命名空间进行过滤,还可以使用 jq 语法进行进一步的过滤。
写个脚本
项目 README.md 就提供了一个简单的例子,大致体现了 Shell Operator 的功能和用法。
首先生成一个脚本文件,并设置权限为可执行:
#!/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
这个小脚本体现了 Hook 的基本用法,如果使用 --config 参数启动,则会输出一个 YAML 格式的配置文件,其中表明该脚本会在 Kubernetes 中加入新的 Pod 时候触发。
configVersion: v1
kubernetes:
- apiVersion: v1
kind: Pod
executeHookOnEvent: ["Added"]
在无参数启动时,则会运行这个 Hook 的主逻辑,在 Hook 被触发时,会把触发时的上下文内容以 JSON 的形式保存到一个文件,文件名会保存到 $BINDING_CONTEXT_PATH。这里会用 jq 从文件的 JSON 中获取 Pod 名称,并展示出来。
构建镜像并运行
项目提供了一个基础镜像 flant/shell-operator:latest,其中内置了 bash、kubectl、jq 以及 shell-operator 的可执行文件。把脚本加入镜像:
FROM flant/shell-operator:latest
ADD pods-hook.sh /hooks
构建镜像并推送到镜像库之后,为了让任务正常运行,要给它创建命名空间以及具备合适权限的 ServiceAccount:
$ 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
...
monitor-pods-acc 具备了对 Pod 对象进行 get、watch 以及 list 操作的能力。我们用这个 ServiceAccount 以及前面生成的镜像,生成一个 Pod:
apiVersion: v1
kind: Pod
metadata:
name: shell-operator
namespace: example-monitor-pods
annotations:
prometheus.io/scrape: 'true'
prometheus.io/port: '9115'
spec:
containers:
- name: shell-operator
image: dustise/shell-operator:monitor-pods
imagePullPolicy: Always
serviceAccountName: monitor-pods-acc
触发 Hook
这个 Pod 启动之后,新建一个 Deployment,再看 Hook 的日志:
$ kubectl create deployment sleep --image=dustise/sleep:v0.9.5
deployment.apps/sleep created
$ kubectl logs -f shell-operator -n example-monitor-pods
...
{"binding":"kubernetes","event":"kubernetes","hook":"pods-hook.sh","level":"info","msg":"Pod 'sleep-84d5994d88-qnc7c' added","output":"stdout","queue":"main","task":"HookRun","time":"2020-11-07T15:46:21Z"}
...
监控信息
细心的读者会看到,前面的 Pod 包含了一个 Prometheus 的注解,如果打开 Prometheus 就会看到其中多出了一系列 shell_operator_hook 前缀的监控指标,例如:
shell_operator_tasks_queue_action_duration_seconds_bucket{queue_action="AddLast",queue_name="main",le="0"} 0
shell_operator_tasks_queue_action_duration_seconds_bucket{queue_action="AddLast",queue_name="main",le="1e-06"} 0
shell_operator_tasks_queue_action_duration_seconds_bucket{queue_action="AddLast",queue_name="main",le="2e-06"} 0
并且,Shell Operator 还支持加入自定义的监控指标,只要将指标写入文件,并把文件名保存到 $METRICS_PATH 环境变量之中就可以。
用途
这东西非常适合急救——在一些特殊场合,根据特定条件,对指定对象进行一些操作,例如注解、标签、清除、重启等。
