使用 Python 编写 Slack 机器人,并将其部署到 Kubernetes,以便确认 Pod 的状态

因为想尝试一下ChatOps的内容,也想学习Python,所以我使用Python创建了一个Slack机器人,并部署到Kubernetes上,以便可以检查Pod的状态。虽然通常会用Hubot来创建机器人,但这次我使用了Python的slackbot模块来完成。

请参考以下链接

根据以下先人的信息作为参考。

    • PythonのslackbotライブラリでSlackボットを作る

 

    • Pythonを使ったSlackBotの作成方法

 

    Python3系でSlack Botの作成〜基礎的な対話を実装する

准备

请点击以下链接,添加Bots应用的Slack集成。确认API令牌并设置机器人的名称和图标等。

image.png

邀请并添加Bot到频道中。

image.png

Python是一种高级编程语言。

请查阅以下官方存储库和上方参考链接来了解如何使用Slackbot模块。

    https://github.com/lins05/slackbot

因为我想从Python访问kube-apiserver来获取Pod和Namespace的信息,所以我还使用了Python的Kubernetes客户端kubernetes模块。

    https://github.com/kubernetes-client/python

编写代码

创建下列三个文件→GitHub

python_slackbot
├── mybot.py
├── run.py
└── slackbot_settings.py

在slackbot_setting.py文件中,可以设置默认的回复消息和要加载的插件等配置。
API_TOKEN可以在这里作为API_TOKEN编写,但也可以通过环境变量SLACKBOT_API_TOKEN进行传递,所以这次我们通过环境变量进行传递。
如果要指定错误通知的接收用户,可以设置ERRORS_TO。请注意,如果用户不存在,则会导致启动错误。

DEFAULT_REPLY = "何言ってんだこいつ"
PLUGINS = ['mybot']
ERRORS_TO = 'sotoiwa'

run.py已按照以下方式编写。

from slackbot.bot import Bot


def main():
    bot = Bot()
    bot.run()


if __name__ == "__main__":
    print('start slackbot')
    main()

在slackbot_settings.py的PLUGINS选项中指定的mybot.py中编写自己的代码。使用@respond_to(‘反应字符串’)来编写被提及时的响应,使用@listen_to(‘反应字符串’)来编写对频道帖子的响应。反应字符串可以使用正则表达式进行指定。

import os
import re

from kubernetes import client, config
import prettytable
from slackbot.bot import respond_to
from slackbot.bot import listen_to


# こんにちはに応答する
@respond_to('hello', re.IGNORECASE)
@respond_to('こんにちは|こんにちわ')
def mention_hello(message):
    message.reply('こんにちは!')


# kubernetesに反応する
@listen_to('kubernetes', re.IGNORECASE)
def listen_kubernetes(message):
    message.reply('kubernetesかっこいい!')
    message.react('+1')


# helmに反応する
@listen_to('helm', re.IGNORECASE)
def listen_helm(message):
    message.reply('helmかっこいい!')
    message.react('+1')


# get pod
@respond_to(r'^get\s+(po|pod|pods)\s+(-n|--namespace)\s+(.*)$')
def mention_get_po(message, arg2, arg3, namespace):

    # kubernetes上で動いているかを環境変数から判断する
    if os.getenv('KUBERNETES_SERVICE_HOST'):
        # ServiceAccountの権限で実行する
        config.load_incluster_config()
    else:
        # $HOME/.kube/config から読み込む
        config.load_kube_config()

    v1 = client.CoreV1Api()
    ret = v1.list_namespaced_pod(namespace=namespace, watch=False)

    table = prettytable.PrettyTable()
    table.field_names = ['name', 'phase']
    table.align['name'] = 'l'
    table.align['phase'] = 'l'

    for i in ret.items:
        table.add_row([i.metadata.name,
                       i.status.phase
                       ])

    msg = '```\n' + table.get_string() + '\n```'
    message.reply(msg)


# get ns
@respond_to(r'^get\s+(ns|namespace|namespaces)$')
def mention_get_ns(message, arg2):

    # kubernetes上で動いているかを環境変数から判断する
    if os.getenv('KUBERNETES_SERVICE_HOST'):
        # ServiceAccountの権限で実行する
        config.load_incluster_config()
    else:
        # $HOME/.kube/config から読み込む
        config.load_kube_config()

    v1 = client.CoreV1Api()
    ret = v1.list_namespace(watch=False)

    table = prettytable.PrettyTable()
    table.field_names = ['name']
    table.align['name'] = 'l'

    for i in ret.items:
        table.add_row([i.metadata.name])

    msg = '```\n' + table.get_string() + '\n```'
    message.reply(msg)

本地执行

如果在本地执行,则应从HOME/.kube/config读取认证信息到kube-apiserver,因此请使用kubectl config命令设置适当的上下文。

安装所需模块。

pip install kubernetes
pip install prettytable
pip install slackbot

导出API令牌。

export SLACKBOT_API_TOKEN=hogehoge

启动机器人。

python run.py

确认运转

你好,你好,对”hello”的提及有反应。

image.png

对于Kubernetes和Helm做出反应并做出相应。

image.png

在机器人上提及Namespace以确认。结果使用prettytable模块进行格式化。

image.png

提及机器人并检查Pod。需要指定命名空间。在以下示例中,由于Pod未运行,所以为空。

image.png

部署到Kubernetes

在Kubernetes上部署机器人。

形象塑造

创建一个 requirements.txt 文件和一个 Dockerfile 文件。

kubernetes
prettytable
slackbot
FROM python:3

WORKDIR /usr/src/app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY ./*.py ./

ENTRYPOINT [ "python", "./run.py" ]

文件的配置如下所示。

python_slackbot
├── Dockerfile
├── mybot.py
├── requirements.txt
├── run.py
└── slackbot_settings.py

构建形象。

docker build -t sotoiwa540/slackbot:1.0 .
docker push sotoiwa540/slackbot:1.0

部署到Kubernetes

如果在本地运行,将从HOME/.kube/config中读取认证信息,但如果在Kubernetes上作为Pod运行,则会根据执行Pod的ServiceAccount的权限进行认证,因此需要创建ClusterRole和ClusterRoleBinding。

这次我要创建一个具有列出Pod和Namespace权限的ClusterRole,并将ClusterRole绑定到默认Namespace下的默认ServiceAccount上。

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: slackbot
rules:
- apiGroups: [""]
  resources:
  - pods
  - namespaces
  verbs:
  - list
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: slackbot
subjects:
- kind: ServiceAccount
  name: default
  namespace: default
roleRef:
  kind: ClusterRole
  name: slackbot
  apiGroup: rbac.authorization.k8s.io
kubectl apply -f slackbot-clusterrole.yaml
kubectl apply -f slackbot-clusterrolebinding.yaml

创建API令牌的秘钥。

kubectl create secret generic slackbot-secret --from-literal=SLACKBOT_API_TOKEN=hogehoge

创建部署。

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
  labels:
    app: slackbot
  name: slackbot
spec:
  replicas: 1
  selector:
    matchLabels:
      app: slackbot
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: slackbot
    spec:
      containers:
      - name: slackbot
        image: sotoiwa540/slackbot:1.0
        imagePullPolicy: Always
        env:
        - name: SLACKBOT_API_TOKEN
          valueFrom:
            secretKeyRef:
              key: SLACKBOT_API_TOKEN
              name: slackbot-secret
kubectl apply -f slackbot-deployment.yaml

确认Pod已经运行。

$ kubectl get po
NAME                        READY   STATUS    RESTARTS   AGE
slackbot-5b68f5dddf-klmpw   1/1     Running   0          8s
$

检查工作是否正常

在微信里提到Bot以确认Pod的状态。

image.png

此外,由于本次仅仅观察了Pod的阶段,因此与直接运行kubectl命令时的STATUS列有所不同。此外,由于Slack发布的文字数量限制,如果Pod数量较多将导致显示混乱。

使用Python的Kubernetes Client库,需要分别创建处理每个提及操作的方法。如果想要编写复杂处理的编程,则可能更适合使用这种方法,但对于仅仅进行状态查询并整理结果的情况,创建每个处理方法并格式化结果非常不方便,因此我改为使用子进程执行kubectl命令。

    PythonのslackbotのPodからkubectlコマンドを実行させる
广告
将在 10 秒后关闭
bannerAds