LoginSignup
5
7

More than 5 years have passed since last update.

PythonのslackbotをKubernetesにデプロイしてPodの状況を確認する

Last updated at Posted at 2019-01-13

ChatOps的なことを試してみたかったのと、Pythonのお勉強のため、PythonでSlackのBotを作成し、Kubernetes上にデプロイして、Podの状況を確認できるようにしたメモ。BotといえばHubotらしいけれども、今回はPythonのslackbotモジュールで作成。

参考リンク

以下の先人の情報を参考に作成。

準備

以下のリンクよりBotsアプリのSlackインテグレーションを追加する。APIトークンを確認し、Botの名前やアイコンなど設定する。

image.png

Botをチャンネルに招待して追加する。

image.png

Python

slackbotモジュールの使い方は以下の公式リポジトリと上の参考リンクを参照。

今回Pythonからkube-apiserverにアクセスしてPodとNamespaceの情報を取得したいので、PythonのKuberentes Clientであるkubernetesモジュールも使う。

コード作成

以下の3つのファイルを作成する。→GitHub

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

slackbot_setting.pyにはデフォルトのリプライや読み込むプラグインなどの設定を記述する。
トークンはAPI_TOKENとしてここで書いてもよいが、環境変数SLACKBOT_API_TOKENでも渡せるので今回は環境変数で渡す。
エラーの通知先のユーザーを指定する場合はERRORS_TOを指定する。ユーザーがいない場合は起動エラーになるので注意。

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

run.pyは以下の通り作成。

run.py
from slackbot.bot import Bot


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


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

slackbot_settings.pyPLUGINSで指定したmybot.pyに自分の処理を書く。
@respond_to('反応する文字列')でメンションされたときの反応を書き、@listen_to('反応する文字列')でチャンネルの投稿への反応を書く。反応する文字列は正規表現で指定する。

mybot.py
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する。

export SLACKBOT_API_TOKEN=hogehoge

Botを起動する。

python run.py

稼働確認

こんにちは、こんにちは、helloというメンションに反応する。

image.png

kubernetes、helmに反応してリアクションする。

image.png

BotにメンションしてNamespaceを確認する。結果はprettytableモジュールで整形している。

image.png

BotにメンションしてPodを確認する。Namespaceを指定する必要あり。以下の例ではPodが稼働していないので空。

image.png

Kubernetesへのデプロイ

Kubernetes上にBotをデプロイする。

イメージのビルド

requirements.txtDockerfileを作成する。

requirements.txt
kubernetes
prettytable
slackbot
Dockerfile
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を作成し、defaultのNamespaceのdefaultのServiceAccountにClusterRoleをバインドする。

slackbot-clusterrole.yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: slackbot
rules:
- apiGroups: [""]
  resources:
  - pods
  - namespaces
  verbs:
  - list
slackbot-clusterrolebinding.yaml
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トークンのSecretを作成する。

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

Deploymentを作成する。

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のphaseを見ているだけなので、普通にkubectlコマンドを実行したときのSTATUS列とは異なる。また、Slackの投稿の文字数の制限で、Podの数が多いと表示が崩れる。

(追記)
PythonのKubernetes Clientライブラリを使った方法では、メンションに対応する操作をそれぞれ作る必要がある。複雑な処理をプログラミングしたい場合はこの方法がよいかもしれないが、単なる状況照会についてそれぞれの処理を作ったり結果を整形するのは不便なので、kubectlコマンドをサブプロセスで実行するように変更した。

5
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
7