候補探し

keycloak on k8s https://www.keycloak.org/getting-started/getting-started-kube

locust on k8s https://aws.amazon.com/jp/blogs/news/load-testing-your-workload-running-on-amazon-eks-with-locust/

discord bot + app で通知 ?

「 おうちkubernetes」という用語を調べる

自宅のサーバーに k8s をデプロイして色々メトリクスを収集してる記事 https://eng-blog.iij.ad.jp/archives/11900

色々紹介している記事 https://blog.chatagiriii.com/?p=110

Discord Bot 作る記事 https://gammalab.net/blog/ypbnb4q8qap6h/ →これが割と自分の興味をひいた

Discord Bot を作成してみる。

Discord Bot on k8s

https://gammalab.net/blog/ypbnb4q8qap6h/ を参考に色々やってみる。

Cloud9 環境作成

手元の環境が汚れるのが嫌なので、 Cloud9 上で実施 ツールのインストール

curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
./aws/install -i /usr/local/aws-cli -b /usr/local/bin

curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
sudo mv /tmp/eksctl /usr/local/bin


curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x ./kubectl
sudo mv ./kubectl /usr/local/bin/kubectl

C9権限ではなく、EC2 権限を使いたいので IAM Role アタッチ後、画面右江から use aws temporary credential のチェックを外す

aws sts get-caller-identity --query 'Arn' --output text

kubeconfを更新する

eksctl get clusters
NAME                            REGION          EKSCTL CREATED
ekshandson                      ap-northeast-1  True

aws eks update-kubeconfig --region ap-northeast-1 --name ekshandson
kubectl get pods --all-namespaces

Container

mkdir ws
cd ws
touch main.py

コードを分析

Python Code

import os
import discord
import aiohttp
import asyncio

BOT_TOKEN  = os.getenv('BOT_TOKEN')
CHANNEL_ID = int(os.getenv('CHANNEL_ID'))

client = discord.Client(intents=discord.Intents.default())

async def channel_send_dog(channel):
    print('Invoke Dog Post')
    async with aiohttp.ClientSession() as session:
        response = await session.get('https://dog.ceo/api/breeds/image/random')
        dog = await response.json()
    await channel.send(dog['message'])
    print('Sending Complete!')

@client.event
async def on_ready():
    channel = client.get_channel(CHANNEL_ID)
    while True:
        await channel_send_dog(channel)
        await asyncio.sleep(6000)

client.run(BOT_TOKEN)

python3 main.py
Traceback (most recent call last):
  File "main.py", line 2, in <module>
    import discord
ModuleNotFoundError: No module named 'discord'

できれば一括で入れたいので requirements.txt を用意する

touch requirements.txt
echo """discord
aiohttp
asyncio""" > requirements.txt

Python v3.8 移行なので準備

wget https://www.python.org/ftp/python/3.8.16/Python-3.8.16.tgz
tar -xvf Python-3.8.16.tgz
cd Python-3.8.16

./configure
make 
make test
sudo make install
cd ws
pip3 install -r requirements.txt

Discord 登録

https://discord.com/developers/applications

以下が必要

  • Bot Token
  • Channnel ID

手順

  • Application 作成
    • Public Bot にチェックを入れない場合、プライベートになる
  • Bot 作成
  • OAuth2 URL を生成
    • アクセスすることで、自分が作成したサーバーに bot を追加できる
export BOT_TOKEN=***
export CHANNEL_ID=773500548347330613
python main.py 2022-12-31 14:10:56 INFO     discord.client logging in using static token
2022-12-31 14:10:57 INFO     discord.gateway Shard ID None has connected to Gateway (Session ID: fd3df738732cdab7e399d57fee3c0af6).
Invoke Dog Post
Sending Complete!

永続化するっぽい

Docker File 作成

https://hub.docker.com/_/python

touch Dockerfile
echo '''
FROM python:3.8-buster

COPY src/* ./

RUN pip3 install -r requirements.txt

CMD ["python3", "main.py"]
''' > Dockerfile
mkdir src
mv main.py src/main.py
mv requirements.txt src/requirements.txt

docker build ./ -t discordbot

起動

docker run -e CHANNEL_ID=$CHANNEL_ID -e BOT_TOKEN=$BOT_TOKEN --rm discordbot

これまでのイメージ整理

docker ps --all
docker system prune

ECR へ image を push

manifest ファイルで参照するために、プライベートリポジトリへ image をプッシュする

aws ecr create-repository --repository-name discord
discord_repo=$(aws ecr describe-repositories --repository-names discord --query 'repositories[0].repositoryUri' --output text)


AWS_ACCOUNT_ID=$(aws sts get-caller-identity --output text --query Account)
AWS_REGION=$(aws configure get default.region)
aws ecr get-login-password | docker login --username AWS --password-stdin https://${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com

docker tag discordbot:latest ${discord_repo}:latest
docker push ${discord_repo}:latest

k8s deploy (マニフェスト作成)

cat <<EOF > dog-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: discord-dogbot
spec:
  replicas: 1
  selector:
    matchLabels:
      name: discord-dogbot 
  template:
    metadata:
      labels:
        name: discord-dogbot
    spec:
      containers:
      - name: discord-dogbot
        image: ${discord_repo}:latest
        imagePullPolicy: Always
        envFrom:
          - secretRef:
              name: dogbot-secrets
EOF
kubectl create namespace discord

kubectl apply -f dog-deployment.yaml -n discord

多分 secret ないのでそれでエラー

kubectl get deployment -n discord

kubectl get pod -n discord
NAME                              READY   STATUS                       RESTARTS   AGE
discord-dogbot-66689d49fb-jqrpw   0/1     CreateContainerConfigError   0          45s

kubectl logs discord-dogbot-66689d49fb-jqrpw -n discord                               
Error from server (BadRequest): container "discord-dogbot" in pod "discord-dogbot-66689d49fb-jqrpw" is waiting to start: CreateContainerConfigError

kubectl describe deployment -n discord
cat <<EOF > dog-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: dogbot-secrets
stringData:
  BOT_TOKEN: "************************************************************************"
  CHANNEL_ID: "******************"

EOF
kubectl apply -f dog-secret.yaml -n discord

kubectl get pod -n discord
NAME                              READY   STATUS    RESTARTS   AGE
discord-dogbot-66689d49fb-jqrpw   1/1     Running   0          4m23s

無事成功!!!!

なんとなく、Podがどのノードで立ち上がってるのかみたいです

kubectl get nodes                                                             
NAME                                               STATUS   ROLES    AGE   VERSION
ip-192-168-14-42.ap-northeast-1.compute.internal   Ready    <none>   45h   v1.24.7-eks-fb459a0
ip-192-168-33-5.ap-northeast-1.compute.internal    Ready    <none>   45h   v1.24.7-eks-fb459a0
ip-192-168-4-202.ap-northeast-1.compute.internal   Ready    <none>   45h   v1.24.7-eks-fb459a0

kubectl get pods -o wide -n discord
NAME                              READY   STATUS    RESTARTS   AGE   IP            NODE                                               NOMINATED NODE   READINESS GATES
discord-dogbot-66689d49fb-jqrpw   1/1     Running   0          20m   192.168.3.2   ip-192-168-14-42.ap-northeast-1.compute.internal   <none>           <none>

なるほど判明しました。