Prefect Echo: PrefectによるTelegramチャットボットシステム
概要
真面目な記事ばかりだと面白くないのでPrefectを使ってチャット一個に対してDockerコンテナ一個起動するという極めて無駄が多いTelegramチャットボットシステムを作ります。
Warning
この記事を読む方は何か起きてもソースコードを読んで自力で解決できるくらいの方を想定しています!
方針
- Githubのモノレポ構成です。
- DockerコンテナイメージレジストリにGithub Packages Container Registryを使用します。(Docker Registryではないので注意)
- CI/CDにGithub Actionsを使用しDockerコンテナのビルドとPrefectのデプロイを自動化します。ActionsRunnerにはGithub hosted Runnerを使用します。
- Prefectワークフローを使ってチャットに応答します。Telegramチャットをシリアライズし、Prefectワークロードに処理を引き渡します。
開発フロー
GithubActionsを使用し、Prefectワークフローの開発インターフェースをGithubに統一します。
sequenceDiagram
participant Developer
participant Github
participant ActionsRunner
participant GithubContainerRegistry
participant PrefectCloud
Developer->>Github:Push Code Changes
Github->>ActionsRunner:Detect Code Changes
alt Github CI pipeline
ActionsRunner->>GithubContainerRegistry:DepolyDocker
ActionsRunner->>PrefectCloud:Depoly Prefect
end
運用フロー
TelegramからのチャットはPrefectCloudを経由してPrefectWorkerに引き渡されます。
sequenceDiagram
participant User
participant Telegram
participant PrefectCloud
participant PrefectWorker
participant GithubContainerRegistry
User->>Telegram: Send Chat
Telegram->>PrefectCloud: WebHook Event
PrefectCloud->>PrefectWorker: Run Deployment (Automation)
GithubContainerRegistry->>PrefectWorker: Pull Latest Code
PrefectWorker->>Telegram: Send Reply
Telegram->>User: Send Reply
通信フロー
sequenceDiagram
participant telegram client
participant telegram server
participant prefect cloud
participant prefect worker
telegram client->>telegram server: MTProto
telegram server->>prefect cloud: HTTPS
prefect cloud->>prefect worker: WebSocketSecure
prefect worker->>telegram server: HTTPS
telegram server->>telegram client: MTProto
環境
- Telegram: 無料版アカウント 1個
- PrefectCloud: prefect.cloud 無料版アカウント 1個
- Github: github.com 無料版アカウント privateリポジトリ 1個
- 開発マシン: Linux系 amd64ビット系 PC 1台
- PrefectWorker: 無料のVPS 2台
- OracleCloudInfrastructure Compute #1: VM.Standard.E2.1.Micro
- CPU: 1コア(OCPU), メモリ: 1GB, OS: AlmaLinux9
- Dockerインストール済
- OracleCloudInfrastructure Compute #2: VM.Standard.E2.1.Micro
- CPU: 1コア(OCPU), メモリ: 1GB, OS: AlmaLinux9
- Dockerインストール済
- OracleCloudInfrastructure Compute #1: VM.Standard.E2.1.Micro
環境準備
Telegram
- https://telegram.me/BotFather からBOTを作成し、
Telegram BOT API Key
を取得する。
PrefectCloud
- https://app.prefect.cloud/auth/sign-up からアカウント登録する。
- defaultワークスペース→API Keysから
Prefect Cloud API Token
を取得する。Warning
セキュリティの観点でPrefect APIキーは開発マシン、PrefectWorker#1,#2の分として3つ作って使い分けること。
開発マシン
- 環境変数をセット。
export PREFECT_API_KEY="Prefect Cloud API Token"
- https://docs.astral.sh/uv/#getting-started の通りuvをインストール。
curl -LsSf https://astral.sh/uv/install.sh | sh echo 'source $HOME/.local/bin/env' >> ~/.bashrc . $HOME/.bashrc
- uvで仮想環境
prefects
を作成mkdir -p $HOME/prefects uv init --native-tls $HOME/prefects cd $HOME/prefects uv --native-tls python install 3.11 uv --native-tls python pin 3.11
Prefect Cloud API Token
を使用しprefect cloudにログイン。echo "prefect" > requirements.txt echo "prefect-docker" >> requirements.txt uv add --native-tls -r requirements.txt uv run --native-tls prefect cloud login -k $PREFECT_API_KEY # $HOME/.prefect/profiles.toml が作成されます
- prefect work-poolを作成。
uv run --native-tls prefect work-pool create oci-pool --set-as-default -t docker --overwrite
- 実際に https://prefect.cloud/ からWork-Poolが作成されていることを確認。
Warning
ここで、CloudManagedのWork-Poolを無効化することを推奨します。
PrefectWorker(#1,#2 共通)
- https://docs.astral.sh/uv/#getting-started の通りuvをインストール。
curl -LsSf https://astral.sh/uv/install.sh | sh echo 'source $HOME/.local/bin/env' >> ~/.bashrc . $HOME/.bashrc
- uvで仮想環境
prefects
を作成。mkdir -p $HOME/prefects uv init --native-tls $HOME/prefects cd $HOME/prefects uv python --native-tls install 3.11 uv python --native-tls pin 3.11
Prefect Cloud API Token
を使用しprefect cloudにログイン。echo "httpx" > requirements.txt echo "prefect" > requirements.txt echo "prefect-docker" >> requirements.txt uv add --native-tls -r requirements.txt uv run --native-tls prefect cloud login -k $PREFECT_API_KEY # $HOME/.prefect/profiles.toml が作成されます
- prefect workerを起動
nohup uv run --native-tls prefect worker start --pool "oci-pool" --name oci01 >~/prefect.log 2>&1 & # nohup uv run --native-tls prefect worker start --pool "oci-pool" --name oci02 >~/prefect.log 2>&1 & #二号機は名前をoci02にしよう
Warning
prefect workerを動かすユーザはDockerグループに所属するなど、dockerコマンドが使える状態にしてください。最初は1号機のみで試験動作をした方が、問題があった際にみるべきprefect.logを特定するのに困りません。
- 実際に https://prefect.cloud/ からWorkerが登録されていることを確認
以降、PrefectWorker側は一切触りません!
Github
- prefects.templateをクローンし、
prefects
という名前でGithubプライベートリポジトリを作成する。(名前は何でも良い) - 自身のアカウントの
Github Personal Access Token
を取得しておく。権限は以下。read:packages
: Dockerコンテナレジストリの利用に必要。
Warning
今回Dockerコンテナ内にソースコードもパッケージングするので、暗にread:repo権限も含む点にご注意ください。発行するGithub Personal Access Tokenの種類はTokens (classic)を選択してください。本記事執筆時点で、Fine-grained TokensはGithub Packagesに対応していません。
prefects
リポジトリ→Settings→Actions→General→Workflow permisiionsから、GithubワークフローがGITHUB_TOKEN
環境変数を使ってGithub Container Registryにアクセス可能にします。prefects
リポジトリ→Settings→Secrets and Variables→Actions→Secretsから、CLASSIC_PAT_GITHUB
という名前で取得したGithub Personal Access Token
を登録します。prefects
リポジトリ→Settings→Secrets and Variables→Actions→Secretsから、PREFECT_API_KEY
という名前で取得したPrefect Cloud API Token
を登録します。GithubワークフローがPREFECT_API_KEY
環境変数を使ってPrefectCloudにアクセスできるようにします。prefects
リポジトリ→Settings→Secrets and Variables→Actions→Secretsから、TG_BOT_TOKEN
という名前で取得したTelegram BOT API Key
を登録します。
PrefectCloud
- Automationを作成する
補足: aiogramの主要な機能
- メッセージのpin: message.pin()
- メッセージの応答: message.reply(“pong”)
- メッセージへのリアクション:
- aiogram.types.reaction_type_emoji.ReactionTypeEmoji
まとめ
20秒くらいかかるやんけ!