我们很高兴在此介绍我们新的开源方案,它能将Kubernetes中Operator的开发提升到一个全新的更简单的水平。它能提供给你一个非常吸引人的机会,让你可以在15分钟内将你的小脚本变成完全成熟的Operator。欢迎[shell-operator](https://github.com/flant/shell-operator)!

### **目标**
shell-operator的思路很简单,它订阅来自Kubernetes对象的事件,并在事件发生后执行外部程序,为其提供有关事件的信息:

在我们运行Kubernetes集群期间,很多小任务开始显现。在[Flant](https://flant.com/),我们迫切想要以正确的方式来自动化它们,因此我们觉得需要更智能的解决方案。通常你可以使用基本的bash脚本来解决所有这些任务,但是如你所知,更推荐的方式是使用Golang来编写Operators。很显然,为每个小任务分别开发成熟的operator将会很低效。
### 15内创建一个Operator
我们将举一个在Kubernetes集群中可以被自动化的例子,以及shell-operator可以如何帮助我们。我们将尝试复制用于访问 Docker 仓库的凭证。
使用私有仓库镜像的Pod应在其清单中包含指定的用于访问仓库的secret。这个secret必须在创建pod之前先创建在每个命名空间中。你可以手动执行此操作,但是,如果我们将配置动态的多个环境,我们将为单个应用程序创建许多命名空间。在多个应用程序(甚至两个或三个)的情况下,secret的数量会变得巨大。关于secret还有一个需求:我们希望能够偶尔更改(注册表)仓库的访问密钥。因此,手动解决方案变得非常低效,你必须自动创建和更新secret。
#### 简单的自动化
我们来写一个脚本,每N秒运行一次,并检查命名空间中secret是否存在。如果secret不存在,那么它将会被创建。这个解决方案的优势是它看起来就像是cron中的一个 shell 脚本,一种经典且易于理解的方法。缺点是在此脚本的两次启动之间的间隔期间可能会出现一些新的命名空间,因此在一段时间内它将不会持有这个secret。这种情况会导致启动pod的过程中出错。
#### 使用shell-operator进行自动化
为了使我们的脚本准确运行,经典的cron执行应该被当有新增命名空间事件发生时的执行所取代。在这种情况下,你可以在使用之前创建一个secret。让我们看看如何使用shell-operator来实现这个功能。
首先,我们先分析一下脚本,就shell-operator而言,脚本都被称之为“钩子“。每个钩子在使用`--config`标志执行时都会通知shell-operator将其绑定(即需要执行哪些事件)。在我们的例子中,我们将使用`onKubernetesEvent`:
{{{
#!/bin/bash
if [[ $1 == "--config" ]] ; then
cat <
{
"onKubernetesEvent": [
{
"kind": "namespace",
"event": [ "add" ]
}
]
}
EOF
fi
}}}
在这里,我们定义我们关注的`namespace`类型的添加(`add`)对象事件。
现在我们需要添加当事件发生时需要执行的代码:
{{{
#!/bin/bash
if [[ $1 == "--config" ]] ; then
# configuration
cat <
{
"onKubernetesEvent": [
{
"kind": "namespace",
"event": [ "add" ]
}
]
}
EOF
else
# response:
# find out what namespace has emerged
createdNamespace=$(jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH)
# create the appropriate secret in it
kubectl create -n ${createdNamespace} -f - <
apiVersion: v1
kind: Secret
metadata:
...
data:
...
EOF
fi
}}}
真棒!我们现在已有一个简洁且漂亮的脚本,想让它能真正发挥作用,我们需要准备一个镜像并将其跑在集群中。
#### 使用钩子制作我们的镜像
你可以很轻易观察到我们在脚本里面使用了`kubectl`和`jq`命令。这意味着镜像中需要包含钩子,shell-operator二进制文件(它将监视事件并执行这个钩子),以及钩子需要用到的命令(`kubectl`和`jq`)。[hub.docker.com](https://hub.docker.com/r/flant/shell-operator)上已提供了包含shell-operator,kubectl和jq的即用型镜像。现在是时候使用`Dockerfile`来添加一个钩子:
{{{
$ cat Dockerfile
FROM flant/shell-operator:v1.0.0-beta.1-alpine3.9
ADD namespace-hook.sh /hooks
$ docker build -t registry.example.com/my-operator:v1 .
$ docker push registry.example.com/my-operator:v1
}}}
#### 在集群中运行
我们再来看看这个钩子,这次我们将关注具体的操作以及它在集群中执行的对象:
1. 它订阅了`namespace`的创建事件;
2. 它在不与它所运行的命名空间相同的空间创建一个secret
这里我们会发现运行这个镜像的pod需要有执行这些操作的权限。你可以授权给一个`ServiceAccount`。由于我们是关注整个集群中的对象,那么权限需要使用`ClusterRole`和`ClusterRoleBinding`形式来配置。
YAML最终配置描述如下:
{{{
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: monitor-namespaces-acc
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: monitor-namespaces
rules:
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "watch", "list"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "create", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: monitor-namespaces
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: monitor-namespaces
subjects:
- kind: ServiceAccount
name: monitor-namespaces-acc
namespace: example-monitor-namespaces
}}}
你可以将创建的镜像部署为一个简单的Deployment:
{{{
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: my-operator
spec:
template:
spec:
containers:
- name: my-operator
image: registry.example.com/my-operator:v1
serviceAccountName: monitor-namespaces-acc
}}}
为方便起见,我们将创建一个单独的命名空间,用于运行shell-operator并应用创建的部署清单:
{{{
$ kubectl create ns example-monitor-namespaces
$ kubectl -n example-monitor-namespaces apply -f rbac.yaml
$ kubectl -n example-monitor-namespaces apply -f deployment.yaml
}}}
好了,shell-operator启动,它将订阅命名空间创建事件并在需要时执行钩子。
这样一个**简单的shell脚本就变成了Kubernetes中一个真正的operator**,并成为集群的一部分。这样做的好处是我们避免了使用Golang来开发operator的复杂过程:

### 过滤
关于对象的观察很棒,但我们通常需要响应对象中某些属性的更改,例如,增加/减少部署中的副本数量或对象对标签中的任何更新。
当一个事件发生时,shell-operator接收该对象的JSON清单。在此JSON中,你可以选择要监视的属性,并**仅在更改时**启动钩子。`jqFilter`字段可以帮助你完成这点:你应该输入将应用于JSON清单的jq表达式。
举个例子,要响应Deployment对象标签中的修改,你必须从`metadata`字段中提取`labels`字段。这个例子中你将需要如下的配置:
{{{
cat <
{
"onKubernetesEvent": [
{
"kind": "deployment",
"event":["update"],
"jqFilter": ".metadata.labels"
}
]
}
EOF
}}}
jqFilter表达式将Deployment的长长的JSON清单转换成带有标签的简短的JSON:

shell-operator将只会在这个简短的JSON发生变化时执行钩子。其它属性的变更将会被忽略。
### 钩子的执行上下文
钩子的配置允许你指定几种事件。例如你可以定义两个Kubernetes事件和两个计划调度:
{{{
{
"onKubernetesEvent": [
{
"name": "OnCreatePod",
"kind": "pod",
"event": [
"add"
]
},
{
"name": "OnModifiedNamespace",
"kind": "namespace",
"event": [
"update"
],
"jqFilter": ".metadata.labels"
}
],
"schedule": [
{
"name": "every 10 min",
"crontab": "0 */10 * * * *"
},
{
"name": "on Mondays at 12:10",
"crontab": "0 10 12 * * 1"
}
]
}
}}}
注意:shell-operator支持以**crontab**样式运行脚本!你可以在[文档](https://github.com/flant/shell-operator/blob/master/HOOKS.md)中找到额外的信息。
为了区分钩子执行的原因,shell-operator会创建一个临时文件并将其路径保存到`BINDING_CONTEXT_TYPE`变量中。此文件包含了执行钩子的原因的JSON描述。例如,每隔10分钟将会使用以下内容启动钩子:
{{{
[{ "binding": "every 10 min" }]
}}}
在周一的话它将以以下内容启动:
{{{
[{ "binding": "every 10 min" }, { "binding": "on Mondays at 12:10" }]
}}}
同时将有`onKubernetesEvent`调用的更详细的JSON,因为它包含了对象的描述:
{{{
[
{
"binding": "onCreatePod",
"resourceEvent": "add",
"resourceKind": "pod",
"resourceName": "foo",
"resourceNamespace": "bar"
}
]
}}}
你能通过名称来全面了解字段的内容(更多详细信息可在[文档](https://github.com/flant/shell-operator/blob/master/HOOKS.md#binding-context)中找到)。使用jq从`resourceName`获取资源名称的示例已经在复制secret的钩子中展示:
{{{
jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH
}}}
你可以通过类似的方式去获取到其它字段。
### 下一步是什么呢?
在该项目仓库中的[/examples directory](https://github.com/flant/shell-operator/tree/master/examples)目录里包含了一些可以直接在集群中使用的示例。你可以将它们用作你开发自己的钩子的基础。
Shell-operator同样支持使用Prometheus来收集指标。[METRICS](https://github.com/flant/shell-operator/blob/master/METRICS.md)章节已描述了这些可用的指标。
你能轻易想到,shell-operator是使用 Go 编写的,并根据开源许可证(Apache 2.0)的条款进行分发。我们非常感谢任何关于开发在Github上的这个[项目](https://github.com/flant/shell-operator)的帮助。你可以通过给我们点[Star](https://github.com/flant/shell-operator/star),反馈问题或者是PR来支持我们!
【原文链接】:[Announcing shell-operator to simplify creating of Kubernetes operators](https://medium.com/flant-com/kubernetes-shell-operator-76c596b42f23) 翻译:冯旭松
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Docker用以提高Linux内核安全性的三大热点技术
- php – woocommerce自定义结帐字段添加费用以订购ajax
- Uber开源JVM Profiler,用以跟踪分布式Java虚拟机
- 使用以 Tensorflow 为后端的 Keras 构建生成对抗网络的代码示例
- Micronaut for Spring 支持 Spring Boot 应用以 Micronaut 形式运行
- Unity动态网格简化算法
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Java核心技术·卷 I(原书第10版)
[美] 凯.S.霍斯特曼(Cay S. Horstmann) / 周立新 等 / 机械工业出版社 / 2016-9 / CNY 119.00
Java领域最有影响力和价值的著作之一,由拥有20多年教学与研究经验的资深Java技术专家撰写(获Jolt大奖),与《Java编程思想》齐名,10余年全球畅销不衰,广受好评。第10版根据Java SE 8全面更新,同时修正了第9版中的不足,系统全面讲解了Java语言的核 心概念、语法、重要特性和开发方法,包含大量案例,实践性强。 一直以来,《Java核心技术》都被认为是面向高级程序员的经典教......一起来看看 《Java核心技术·卷 I(原书第10版)》 这本书的介绍吧!