当前位置: 首页 > 软件库 > 云计算 > 云原生 >

shell-operator

授权协议 Apache-2.0 License
开发语言 Google Go
所属分类 云计算、 云原生
软件类型 开源软件
地区 不详
投 递 者 钱安和
操作系统 跨平台
开源组织
适用人群 未知
 软件概览

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 or delete 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

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.

Build an image with your hooks

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

Create RBAC objects

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

Install shell-operator in a cluster

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

It all comes together

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.

Hook binding types

Every hook should respond with JSON or YAML configuration of bindings when executed with --config flag.

kubernetes

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 and kind fields.

Note: return configuration as JSON is also possible as JSON is a subset of YAML.

onStartup

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

schedule

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

Prometheus target

Shell-operator provides a /metrics endpoint. More on this in METRICS document.

Examples and notable users

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.

Articles & talks

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:

Other languages:

Community

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.

License

Apache License 2.0, see LICENSE.

  • 前一段时间发了一篇 Shell Operator 的介绍,搓例子的时候,就想起个需求,我想把 Pod 所在节点上的特定标签复制给 Pod,例如机架、虚拟机节点所在的物理机等,都可以用标签的形式来表达,并可以用这些标签进行选择和统计等。 Shell Operator 的基本开发流程是: 编写配置文件,确定触发条件。 开发操作脚本,打包容器镜像。 确定操作权限,设置 RBAC。 运行和测试。 官方的例

  •  shell 脚本的错误:代码如下: #!/bin/bash alive=`ps aux|grep youdun|grep -v grep|wc -l` if [ $alive -eq 0 ] then nohup /usr/local/php-7.1/bin/php /**/**.php >> /**/**.log 2>&1 & fi 开始的时候我时用的 if [ $alive -eq 0 ]

  • 当$f4 为 <NE> 这种类型的字符串时 if [ -z $f4 ] 或 if [ $f4 != "<NE>" ] 会报错: Binary Operator Expected 解决方法:将$f4用双引号括起来  if [ -z "$f4" ] 或 if [ "$f4" != "<NE>" ]  原因:$f4的内容中的 "<" 会被理解为小于号,因此解析器会期待后面是数字,因此会报错.

  • shell脚本报错:"[: =: unary operator expected" 在匹配字符串相等时,我用了类似这样的语句: if [ $STATUS == "OK" ]; then echo "OK" fi 在运行时出现了 [: =: unary operator expected 的错误,就一直找不到原因,尝试了删除等号两侧的空格和括号里的空格都不管用,最后baidu了一下,才找到原因。把语

  • shell脚本报错:"[: =: unary operator expected"     在匹配字符串相等时,我用了类似这样的语句: if [ $STATUS == "OK" ]; then      echo "OK" fi     在运行时出现了 [: =: unary operator expected 的错误,就一直找不到原因,尝试了删除等号两侧的空格和括号里的空格都不管用,最后baid

  • 今天写了一个shell脚本,类似于下面这样 if [ $userId = “” ]; then echo "0” else echo "1" fi 出现报错unary operator expected 报错的原因是:如果变量userId的值为空,那么就if语句就变成了if [ ="" ],这不是一个合法的条件。为了避免出现这种情况,我们必须给变量加上引号if [ “$

  • unexpected operator:意外的运算符 出现这个问题,可以先使用以下步骤排查问题: (1) 检查语法是否正确+编码是否正确(使用utf8编码,不能是utf8-bom编码); (2)确认shell脚本中使用的是#!/bin/bash还是#!/bin/sh,如果是#!/bin/sh修改替换为#!/bin/bash试试

 相关资料
  • Shell排序是一种高效的排序算法,基于插入排序算法。 该算法避免了大的移位,如插入排序的情况,如果较小的值是最右边的并且必须移动到最左边。 该算法对广泛传播的元素使用插入排序,首先对它们进行排序,然后对间距较小的元素进行排序。 该间距称为interval 。 此间隔基于Knuth的公式计算为 - Knuth的公式 h = h * 3 + 1 where − h is interval wi

  • shell 模块提供了集成其他桌面客户端的关联功能. 在用户默认浏览器中打开URL的示例: var shell = require('shell'); shell.openExternal('https://github.com'); Methods shell 模块包含以下函数: shell.showItemInFolder(fullPath) fullPath String 打开文件所在文

  • 使用默认应用程序管理文件和 url。 进程: Main, Renderer shell 模块提供与桌面集成相关的功能。 在用户的默认浏览器中打开 URL 的示例: const { shell } = require('electron') shell.openExternal('https://github.com') Manage files and URLs using their defau

  • Erlang shell用于测试表达式。 因此,在实际测试应用程序本身之前,可以非常轻松地在shell中进行测试。 以下示例展示了如何在shell中使用加法表达式。 这里需要注意的是表达式需要以点(。)分隔符结束。 执行命令后,shell会打印另一个提示符,这次是命令编号2(因为每次输入新命令时命令编号都会增加)。 以下函数是Erlang shell中最常用的函数。 b() - 打印当前变量绑定。

  • 可能您早已能够熟练的使用 GUI(图形用户界面),例如您可以使用鼠标双击一个图标,来打开或者执行它。 我们来看这个过程: 您使用鼠标定位桌面上的一个程序图标,按下左键两次。系统读取鼠标指针的位置,并且判断该位置下图标的涵义,根据预设的双击动作,运行程序或者打开文件。 这一套 GUI 系统,便是一种 Shell,它的作用是实现人机交互。如果我们不能够控制电脑,那么电脑还不如电视机好玩,不是么?电视机

  • 使用默认应用程序管理文件和 url。 Process: Main, Renderer (只能在非沙盒下使用) shell 模块提供与桌面集成相关的功能。 在用户的默认浏览器中打开 URL 的示例: const { shell } = require('electron') shell.openExternal('https://github.com') 注意: 虽然 shell 模块可以在渲染