という記事を書いたものの、PythonのKubernetes Clientライブラリを使ったため、get pod
したいなど、それぞれの操作毎にBotの動作を記載する必要があり不便。Python ClientではなくBotのコンテナ内で直接kubectl
コマンドを実行するようにする。
Podからkubectl
コマンドを実行するには、以下の記事に書いた通り、kubectl
のバイナリをコンテナイメージ内に配置し、RBACでPodを実行するServiceAccountに適切な権限を与える必要がある。
準備
Slack側の準備については前回の記事を参照。
Python
slackbot
モジュールの使い方は以下の公式リポジトリを参照。
コード作成
以下の3つのファイルを作成する。→GitHub
slacbot_settings.py
とrun.py
は前回と同じ。
python_slackbot
├── mybot.py
├── run.py
└── slackbot_settings.py
mybot.py
は以下の通り作成。kubernetes
モジュールや出力の整形に使っていたprettytable
モジュールは削除し、kubectl
コマンドをサブプロセスで実行する関数を追加した。
import re
import subprocess
from slackbot.bot import listen_to
from slackbot.bot import respond_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')
# kubectl
@respond_to(r'^kubectl (.*)')
def mention_kubectl(message, kubectl_args):
try:
cmd = 'kubectl {}'.format(kubectl_args)
completed_process = subprocess.run(cmd.split(),
check=True,
capture_output=True)
result_str = completed_process.stdout.decode('utf-8')
except subprocess.CalledProcessError as e:
result_str = e.stderr.decode('utf-8')
msg = '```\n' + result_str + '```'
message.reply(msg)
ローカル実行
ローカルで実行する場合は、HOME/.kube/config
からkube-apiserverへの認証情報を読み込むので、kubectl config
コマンドで適切なコンテキストを設定しておく。
必要なモジュールをインストールする。
pip install slackbot
APIトークンをexport
する。
export SLACKBOT_API_TOKEN=hogehoge
Botを起動する。
python run.py
稼働確認
Botにメンションして任意のkubectlコマンドを実行する。

Kubernetesへのデプロイ
Kubernetes上にBotをデプロイする。
イメージのビルド
requirements.txt
とDockerfile
を作成する。
slackbot
FROM python:3-alpine
WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY ./*.py ./
RUN wget https://storage.googleapis.com/kubernetes-release/release/$(wget -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl \
&& mv kubectl /usr/local/bin/kubectl \
&& chmod +x /usr/local/bin/kubectl
ENTRYPOINT [ "python", "./run.py" ]
ファイル配置は以下の通り。
python_slackbot
├── Dockerfile
├── mybot.py
├── requirements.txt
├── run.py
└── slackbot_settings.py
イメージをビルドする。
docker build -t sotoiwa540/slackbot:1.1 .
docker push sotoiwa540/slackbot:1.1
Kubernetesへのデプロイ
今回はSlackbotをデプロイする専用のNamespaceを作る。
kubectl create ns slackbot
ローカルで実行する場合は、kubectlはHOME/.kube/config
から認証情報を読み込むが、Kubernetes上でPodとして実行する場合はPodを実行するServiceAccountの権限で実行されるので、適切な権限を与える必要がある。
Podに明示的にServiceAccountを指定しない場合は、Podは稼働するNamespaceのdefault
のServiceAccountの権限で実行される。
今回は、デフォルトで存在するview
という読み取りだけでるっぽいClusterRoleを、default
のServiceAccountに割り当てるClusterRoleBindingを作成する。何でも実行できるようにしたかったらcluster-admin
のClusterRoleとかを割り当てればよい。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: slackbot
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: view
subjects:
- kind: ServiceAccount
name: default
namespace: slackbot
kubectl apply -f slackbot-clusterrolebinding.yaml -n slackbot
SlackのAPIトークンを格納したSecretを作成する。
kubectl create secret generic slackbot-secret -n slackbot \
--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.1
imagePullPolicy: Always
env:
- name: SLACKBOT_API_TOKEN
valueFrom:
secretKeyRef:
key: SLACKBOT_API_TOKEN
name: slackbot-secret
kubectl apply -f slackbot-deployment.yaml -n slackbot
Podが稼働したことを確認する。
$ kubectl get po -n slackbot
NAME READY STATUS RESTARTS AGE
slackbot-8544c9454-q5jtc 1/1 Running 0 19s
$
稼働確認
Botにメンションしてkubectl
コマンドを実行できることを確認。
