shell operator是由Falnt公司开发并开源的。Flant公司是一家致力于提供解决所有基础设施问题的解决方案的公司。他们自称是提供DevOps-as-a-Service的服务。

需求

  • 一个简单的任务:监听项目创建与删除事件,并发出告警。
  • 一种简单的解决方法:定时脚本cron,每隔一段时间(如1min)获取对Openshift集群的所有项目,并将它与上次获取的结果值进行比较,得到新创建的项目及删除的项目
    该方法的缺点:
    • 不及时
    • 性能差,很多时候并没有操作项目,但仍然需要不断执行脚本
    • 如果1min内即创建了新项目,又把这个项目删除了,则无法监测到
  • 另一种解决方法:事件驱动,即订阅来自Kubernetes对象的事件,如果有对Project操作就触发告警。
    很明显这种方法解决了定时任务的所有问题。
  • 该很么做呢?会不会非常复杂。不会。使用shell-operator项目就可以非常简单地实现。shell-operator项目地址:https://github.com/flant/shell-operator

Shell Operator

实现部骤

  1. 创建shell-operator项目
    1
    $ oc new-project shell-operator
  2. 为该项目创建serviceAccount monitor-namespaces-acc,将给它授予获取全局namespace的权限
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    $ cat << EOF | oc create -f -
    ---
    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"]

    EOF
    $ oc adm policy add-cluster-role-to-user monitor-namespaces -z monitor-namespaces-acc
  3. 创建一个configmap,其中data中的内容为hook脚本
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    $ cat << EOF | oc create -f -
    apiVersion: v1
    data:
    shell-hook.sh: |-
    #!/usr/bin/env bash

    if [[ $1 == "--config" ]] ; then
    cat <<EOF
    {"onKubernetesEvent":[
    {
    "name":"OnCreateDeleteNamespace",
    "kind": "namespace",
    "event":["add", "delete"]
    },
    {
    "name":"OnModifiedNamespace",
    "kind": "namespace",
    "event":["update"],
    "jqFilter": ".metadata.labels"
    }
    ]
    }
    EOF
    else
    bindingName=$(jq -r '.[0].binding' $BINDING_CONTEXT_PATH)
    resourceEvent=$(jq -r '.[0].resourceEvent' $BINDING_CONTEXT_PATH)
    resourceName=$(jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH)
    if [[ $bindingName == "OnModifiedNamespace" ]] ; then
    echo "Namespace $resourceName labels were modified"
    else
    if [[ $resourceEvent == "add" ]] ; then
    echo "Namespace $resourceName was created"
    else
    echo "Namespace $resourceName was deleted"
    fi
    fi
    fi
    kind: ConfigMap
    metadata:
    name: hooks
    EOF
  4. 运行shell-operator应用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    $ cat << EOF | oc create -f -
    apiVersion: apps.openshift.io/v1
    kind: DeploymentConfig
    metadata:
    labels:
    run: shell-operator
    name: shell-operator
    spec:
    replicas: 1
    selector:
    run: shell-operator
    template:
    metadata:
    labels:
    run: shell-operator
    spec:
    serviceAccount: monitor-namespaces-acc
    containers:
    - image: 'flant/shell-operator:latest-alpine3.9'
    imagePullPolicy: IfNotPresent
    name: shell-operator
    volumeMounts:
    - mountPath: /hooks
    name: hooks-no934
    volumes:
    - configMap:
    defaultMode: 511
    name: hooks
    name: hooks-no934
    triggers:
    - type: ConfigChange
    EOF
    说明
  • 应用启动使用monitor-namespaces-accserviceAccount
  • 将configmap内容挂载到deployment应用的/hooks目录中
  • 挂载文件需要给可执行权限defaultMode: 511

Shell Operator

验证

  1. 创建一个project/删除该project
    1
    2
    $ oc new-project  operator-test
    $ oc delete project operator-test
  2. 查看shell-operator的日志

operator日志

额外补充

Shell Operator支持绑定三种hook触发类型

  • onStartup
    onStartup类型只有一个参数:”onStartup”设置绑定顺序
    1
    {"onStartup":10}
  • schedule
    schedule绑定用于周期性运行,支持秒级粒度定义计划
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    {
    "schedule": [
    {"name":"every 10 min",
    "crontab":"0 */10 * * * *",
    "allowFailure":true
    },
    {"name":"Every Monday at 8:05",
    "crontab":"0 5 8 * * 1"
    }
    ]
    }
  • onKubernetesEvent
    监听Kubernetes事件促发
    1
    2
    3
    4
    5
    6
    7
    8
    {
    "onKubernetesEvent": [
    {"name":"Execute on changes of namespace labels",
    "kind": "namespace",
    "event":["update"],
    "jqFilter":".metadata.labels"
    }]
    }

将镜像带的kubectl命令行替换成oc命令行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ cat Dockerfile-oc
FROM ubuntu:18.04
ADD ./oc /bin/oc
ADD ./shell-operator /
RUN apt-get update && \
apt-get install -y ca-certificates wget jq && \
rm -rf /var/lib/apt/lists && \
chmod +x /bin/oc && \
mkdir /hooks
WORKDIR /
ENV SHELL_OPERATOR_WORKING_DIR /hooks
ENTRYPOINT ["/shell-operator"]
CMD ["start"]
$ docker build -f Dockerfile-oc -t docker.io/xhuaustc/shell-operator-oc:latest-3.11 .

其中oc从镜像openshift/origin-cli中导出,而shell-operator从镜像flant/shell-operator中导出
最终镜像保存在:docker.io/xhuaustc/shell-operator-oc:latest-3.11

总结

  • 以上是使用configmap的方式向operator-shell注入自定义的钩子代码,非常灵活,最原始的operator-shell就能够满足各种不种的需求,十分方便。
  • shell-operator项目为我们自定义operator提供了一种非常便利的方式。同时它不仅仅支持bash,也可以支持python,需要在镜像中安装python包。
    1
    2
    3
    $ cat Dockerfile
    FROM flant/shell-operator:latest
    RUN apk --no-cache add python
    钩子代码的环境使用python
    1
    #!/usr/bin/env python
  • 有了这个监控后,就可以非常方便地对Openshift/Kubernetes的资源进行控制,想像空间可以很大。
    1. 例子:有些项目的应用创建有先后关系,就可以方便地使用shell operator进行编排
    2. 例子:不同项目 dev/sit/uat 对不同的用户组 dev/test/ops 会有不同的权限 view/admin/image-puller ,就可以使用项目名格式给不同用户组授予不同的权限
  • 与CRD结合,真正构建自己的operator,想像空间就变得更大了
  • shell-operator项目地址:https://github.com/flant/shell-operator

参考文章

Shell-operator:用于简化Kubernetes operator的创建