## 1. デプロイのたびに止まるサーバ、何が問題なのか? {#sec-4f4fee2fcd28} 個人プロジェクトを運営していると、スペックが限られた環境(GCP の超小型インスタンスや Raspberry Pi など)に直面します。 私は複数のサーバーマシンを管理しており、AI 推論・学習用の高スペックマシンから、名前解決だけがかろうじて動く VM まで、さまざまなマシンを運用しています。 特に Raspberry Pi 5 が好きです。24 時間稼働しても電気代がほとんどかからず、性能も十分だと思っています。 他のサーバーが家畜のように管理対象だと感じるなら、Raspberry Pi は愛着の湧くペットのような存在と言えるでしょう。 しかし、このペットに負荷をかけすぎると、デプロイ時に CPU が 100% に達してしまう問題が起きました。原因は Celery Worker でした。 ゼロダウンタイムデプロイのために Blue と Green のグループを同時に立ち上げると、一瞬で Worker の数が 2 倍になり、システムが耐え切れなくなったのです。 Worker の数を減らすと処理速度が落ち、逆にそのままにしておくとサーバがクラッシュする——ジレンマに陥っていました。 ![低スペック PC で自動化スクリプトを象徴する画像](/media/editor_temp/6/feadd998-56ed-4ccb-9fca-acbb54ef62f2.png) この問題を解決すべく、リソース消費を最小限に抑えつつ安定性を確保した **カスタム Blue‑Green デプロイスクリプト** を作成しました。 --- ## 2. 解決戦略:リソースは節約し、安定性は向上させる {#sec-84df4175f98f} シンプルな Blue‑Green デプロイは 2 環境を同時に稼働させますが、私は **CPU 負荷を下げる** ために次の戦略を取りました。 1. **バックグラウンドサービス(Celery)を先に停止**:新バージョンの Web サーバが CPU を確保できるよう、古いバージョンの負荷の高いバックグラウンドタスク(Worker、Beat)を先に止めます。 2. **段階的起動**:すべてのサービスを一度に立ち上げるのではなく、`Web + Redis` を先に起動しヘルスチェックを実施します。 3. **Human‑in‑the‑loop**:自動化が完了した後、管理者が目視で確認し、最終的に古いバージョンを削除する ‘最終承認’ ステップを設けました。 CPU が逼迫してクラッシュする原因は、冒頭で簡単に触れた通り、Celery Worker が再起動時に大量のタスクを即座に受け取り実行しようとするためです。Concurrency 設定を下げれば解決できますが、デプロイ中に非同期タスクの処理速度が遅くなるのは望みません。 そこで思いついたアイデアは、再デプロイ時にゼロダウンタイムを保ちつつ、既存の Celery を一時停止して CPU を確保し、新コードをデプロイするというものです。 --- ## 3. キーコードの紹介 {#sec-049262c64613} 全コードは私の [GitHub リポジトリ](https://github.com/mikihands/linuxscript/tree/main/zero-downtime) で確認できます。ここではスクリプトの主要ロジックをいくつかピックアップします。 ### ① Docker Compose を使ったプロジェクト分離 {#sec-31c03a8ae526} `docker compose -p` オプションで、同じ設定ファイルから `blue` と `green` という別々のプロジェクト(名前空間)を作成します。 ```bash dc() { # プロジェクト名(-p)を動的に指定して環境を分離 docker compose -f "$COMPOSE_FILE" "$@" } ``` ### ② 徹底したヘルスチェック {#sec-d10311b76a14} 新バージョンが完全に準備できるまで、トラフィックの切り替えは行いません。 ```bash health_check() { # 特定ポートが 200 OK を返すか 10 回リトライ if curl -fsSIL --max-time "$HEALTH_TIMEOUT" "$url"; then ok "Health check passed" return 0 fi } ``` ### ③ 失敗時の即時ロールバック {#sec-53e921d110b5} 新バージョンに問題があれば、停止させていた旧バージョンをすぐに復活させ、ユーザーに障害が影響しないようにします。 古い Celery Worker と Beat を `rm -f` で完全に終了させず、緊急時にすぐ復旧できるよう `stop` コマンドで CPU を確保しました。そのおかげで障害時に `up -d` だけでスムーズに元の状態に戻すことができました。 --- ## 4. 運用ノウハウ:"確認後削除" の美学 {#sec-cbbf7ab93b4f} スクリプトの最後は、旧バージョンを自動で削除せず、管理者にメッセージを表示して手動で削除させる形で終わります。 > "デプロイは成功しました。ですが直接アクセスして確認してください。問題なければ以下のコマンドをコピーして旧バージョンを整理してください。" この一文の安全装置が、自動化が見落としがちな 1% のミスを防いでくれます。 --- ## 5. まとめ {#sec-942f631956ee} 限られたリソース内で最高の効率を追求するための工夫がこのスクリプトに凝縮されています。決して華やかなコードではありませんが、私が実際に満足して使っているものなので、同じような課題を抱える他の開発者にも役立つはずです。 **関連リンク:** * [GitHub Repository 直接リンク](https://github.com/mikihands/linuxscript/tree/main/zero-downtime) * [GitHub Webhook を活用した自作自動デプロイシステム ⑤ Nginx, HTTPS 設定と最終連携](/ko/whitedec/2025/7/24/github-webhook-final-nginx-https/) * ご質問はコメントまたは GitHub Issue でお寄せください!