はじめに
これまでは、ホロライブの配信スケジュールと YouTube の動画情報を収集して MongoDB へ登録する holocollect を、Ubuntu VM 上で動かしていました。
ただ、しばらく運用していると、次のような点が気になってきました。
- Ubuntu VM 自体の管理が地味に面倒
- MongoDB も含めて面倒を見る必要がある
- アプリの更新や再デプロイが手作業寄りになりやすい
- バッチ処理なのに VM を常時維持する構成が少し重い
そこで今回は、次のように構成を見直しました。
- MongoDB をオンプレ環境から MongoDB Atlas の無料プランへ移行
- holocollect を Docker イメージ化
- Azure Container Apps Job で定期実行する構成へ変更
- 必要に応じて NAT Gateway で送信元 IP を固定できるようにする
この記事では、holocollect 編として、考え方と Azure デプロイ手順をまとめます。
対象のリポジトリはこちらです。
holocollect の役割
holocollect は Web API ではなく、定期実行のバッチアプリです。
主な処理は次のとおりです。
- ホロジュールのページを取得する
- Selenium + headless Chrome で配信予定を収集する
- YouTube Data API v3 で動画情報を取得する
- MongoDB に保存する
この役割を考えると、常駐サーバーとして動かすより、必要なタイミングだけ起動する実行基盤のほうが自然です。
そこで Azure では Azure Container Apps Job を使うことにしました。
移行前後の構成
移行前
- Ubuntu VM
- Python バッチとして holocollect を実行
- MongoDB も自前で管理
- ジョブ管理や更新作業も VM 側で実施
移行後
- MongoDB Atlas を利用
- holocollect を Docker 化
- Azure Container Registry へイメージを登録
- Azure Container Apps Job で定期実行
- 必要なら VNet + NAT Gateway で送信元 IP を固定
オンプレ寄りの構成から移行してよかったこと
1. VM を維持する負担が減った
Ubuntu VM で運用していると、アプリ以外にも見るものが増えます。
- OS アップデート
- 常駐プロセスの確認
- SSH 前提の保守作業
- 再デプロイ時の手順確認
バッチ処理のためだけに VM を抱えるのは、少しオーバーでした。
2. バッチ処理としての形がきれいになった
holocollect は定期実行して結果を保存したら終わるアプリです。
Container Apps Job に移すと、
- スケジュール実行しやすい
- 実行単位が明確
- 失敗時の切り分けがしやすい
- 常時起動の前提がなくなる
というメリットがありました。
3. DB の管理対象を減らせた
MongoDB Atlas に移したことで、MongoDB サーバー自体の管理からかなり解放されました。
- DB サーバー保守を減らせる
- 接続先をクラウド前提にできる
- コンテナ側から接続しやすい
- アプリと DB を疎結合にしやすい
なぜ Azure Container Apps Job にしたのか
holocollect は HTTP リクエストを待ち受けるアプリではありません。
そのため、Azure Container Apps の通常の常駐アプリよりも Job のほうが用途に合っていました。
Job を選んだ理由は次のとおりです。
- cron で定期実行できる
- コンテナをその都度起動できる
- バッチ処理の責務と一致する
- ログを Azure 側で確認しやすい
今回は 1 日 4 回実行するスケジュールを既定値にしています。
0 0,6,12,18 * * *
Container Apps Job の cron は UTC 基準で評価されるので、その点は注意が必要です。
MongoDB Atlas との接続で考えたこと
MongoDB Atlas を使うときに気になるのが、接続元 IP の扱いです。
今回のデプロイスクリプトは、次の 2 パターンを用意しています。
NAT なし構成
- スクリプト: infra/deploy-container-app-job.ps1
- 送信元 IP を固定せず構成が軽い
- Atlas 側では一時的に 0.0.0.0/0 許可などが必要
検証や低コスト運用向けです。
NAT あり構成
- スクリプト: infra/deploy-container-app-job-nat.ps1
- VNet / Subnet / NAT Gateway / 固定 Public IP を構成
- Atlas 側に固定送信元 IP を Allow List 登録できる
本番寄りに運用したい場合は、こちらのほうがわかりやすいです。
事前準備
まずはローカル環境と Azure 側の前提を用意します。
ローカル環境
- Windows 11
- PowerShell 7
- Azure CLI
- Docker Desktop もしくは az acr build を使える環境
- Git
- このリポジトリの取得
Azure 側
- Azure アカウント
- リソース作成権限
- Azure CLI でログイン済み
ログイン確認:
az login
az account show
MongoDB Atlas 側
- クラスター作成済み
- 接続用ユーザー作成済み
- 接続文字列を取得済み
.env の準備
このプロジェクトでは、ローカル実行、Docker 実行、Azure デプロイで、できるだけ同じ設定を使えるようにしています。
.env の例:
MONGO_URI="mongodb+srv://[user]:[password]@[cluster-url]/holoduledb"
YOUTUBE_API_KEY="[YouTube API Key]"
YOUTUBE_API_SERVICE_NAME="youtube"
YOUTUBE_API_VERSION="v3"
YOUTUBE_URL_PATTERN="^https://www.youtube.com/watch\?v=.*$"
HOLODULE_URL="https://schedule.hololive.tv/"
LOG_TO_FILE=false
CHROME_BIN=/usr/bin/google-chrome
ポイントは次のとおりです。
- KEY=VALUE 形式で書く
- = の前後に空白を入れない
- クォートはあってもなくてもよい
- .env は Git にコミットしない
デプロイスクリプトは、MONGO_URI や YOUTUBE_API_KEY を .env から自動で読み込めます。
Docker 化で意識したこと
holocollect は Selenium と headless Chrome を使うため、コンテナ化ではそこがポイントになります。
今回は次のような方針にしました。
- アプリは Docker イメージとして実行する
- Chrome は Linux コンテナ側で利用する
- ログは標準出力寄りにする
- .env を起点に Azure の secret / env-vars へ流し込む
コンテナ環境では、ローカルのようにログファイルを主に見るより、標準出力を Azure 側で集める形のほうが扱いやすいです。
Azure デプロイ手順
ここからは、NAT ありの本番寄りフローをベースに、手順を丁寧にまとめます。
1. デプロイスクリプトを確認する
利用するスクリプトは次のファイルです。
- infra/deploy-container-app-job-nat.ps1
このスクリプトは大きく 5 フェーズに分かれています。
- Azure CLI 拡張やプロバイダー登録
- VNet / Subnet / NAT Gateway の準備
- ACR の作成とイメージビルド
- Container Apps Environment の作成
- Container Apps Job の作成
2. 最小コマンドで実行する
最小実行例は次のとおりです。
.\infra\deploy-container-app-job-nat.ps1 `
-ResourceGroup rg-holocollect `
-RegistryName holocollectacr
このとき、MONGO_URI と YOUTUBE_API_KEY は .env から自動で読み込まれます。
3. スクリプトが行うこと
このスクリプトは次の処理をまとめて実行します。
- Resource Group を作成
- Azure Container Registry を作成または更新
- az acr build で Docker イメージをビルド
- VNet / Subnet を作成または再利用
- Subnet を Microsoft.App/environments に委任
- NAT Gateway と固定 Public IP を構成
- Container Apps Environment を VNet 統合で作成
- Container Apps Job を作成
4. Container Apps Job の設定内容
作成される Job には、主に次の設定が入ります。
- trigger-type: Schedule
- cron-expression: 0 0,6,12,18 * * *
- image: ACR に push した holocollect イメージ
- CPU / Memory 指定
- MONGO_URI や YOUTUBE_API_KEY を secrets 経由で注入
- CHROME_BIN=/usr/bin/google-chrome
特に secrets と env-vars を分けているのがポイントです。
- 機密値は secrets に格納
- アプリ側では secretref として参照
5. 実行後に NAT Public IP を Atlas に登録する
スクリプトの最後に NAT Public IP が表示されます。
表示例:
NAT Public IP : x.x.x.x
この IP を MongoDB Atlas の Network Access に /32 で追加します。
例:
x.x.x.x/32
もし検証のために一時的に 0.0.0.0/0 を許可していた場合は、最後に削除します。
6. Job を手動実行して初回確認する
デプロイ直後は、まず手動で動かして確認すると切り分けしやすいです。
az containerapp job start --name holocollect-job --resource-group rg-holocollect
az containerapp job execution list --name holocollect-job --resource-group rg-holocollect
ここで、実行履歴が作成されていることを確認します。
よく使う主なパラメーター
必要に応じて、次の値を上書きできます。
- -Location
- -CronExpression
- -ContainerAppsEnvironment
- -JobName
- -ImageName
- -ImageTag
- -Cpu
- -Memory
- -VnetName
- -SubnetName
- -NatGatewayName
- -NatPublicIpName
- -ForceRecreateJob
たとえば cron を変更したい場合は、次のように実行できます。
.\infra\deploy-container-app-job-nat.ps1 `
-ResourceGroup rg-holocollect `
-RegistryName holocollectacr `
-CronExpression "0 3,9,15,21 * * *"
既存 Job を作り直したい場合は、次のようにします。
.\infra\deploy-container-app-job-nat.ps1 `
-ResourceGroup rg-holocollect `
-RegistryName holocollectacr `
-ForceRecreateJob
ハマりやすかったポイント
実際に進める中で、注意したほうがよい点もありました。
1. cron は UTC 基準
日本時間の感覚でそのまま設定するとズレます。
2. Atlas 側の IP 制御をどうするか先に決める
- まずは低コスト重視で NAT なしにするのか
- 固定 IP を使って Allow List 管理するのか
ここは構成とコストに直結します。
3. .env の書式崩れ
単純ですが、.env に空白が入っていると値が取れず、原因がわかりにくいです。
4. コンテナでは標準出力中心で考える
VM 時代のログファイル前提のままだと、クラウド上で見づらくなります。
おわりに
今回は、Ubuntu VM で動かしていた holocollect を、MongoDB Atlas と Azure Container Apps Job を使う構成へ移行しました。
今回の移行で大きかったのは、単に Azure へ載せ替えたことではなく、バッチ処理としての実行基盤をきちんと分けられたことです。
- DB は MongoDB Atlas
- バッチ処理は Container Apps Job
- イメージは ACR
- 必要なら NAT Gateway で固定送信元 IP
という形に整理できたことで、VM 中心の運用よりかなり見通しがよくなりました。
同じように、定期実行の Python バッチを VM 上で運用していて、少し管理が重くなってきた場合は、Azure Container Apps Job はかなり相性のよい選択肢だと思います。
次の記事では、同じく Ubuntu VM で動かしていた holoservice を、Azure Container Apps 上の FastAPI API として公開した内容をまとめます。