ゼロダウンタイム展開戦略: 更新中もアプリケーションを実行し続ける
計画的なダウンタイムにより、企業は 1 分あたり平均 5,600 ドルのコストがかかります。 しかし、企業の 43% は依然として展開中にアプリケーションをオフラインにしています。ダウンタイムゼロの展開は贅沢ではなく、期待です。顧客、検索エンジン、統合パートナーはすべて、たとえ一時的であってもアプリケーションがオフラインになるとペナルティを課します。
このガイドでは、3 つの主要なゼロ ダウンタイム展開戦略、稼働時間を維持するデータベース移行テクニック、および自動ロールバック メカニズムについて説明します。
重要なポイント
- Blue-Green デプロイメントは最も安全な戦略です。トラフィックを以前のバージョンに切り替えることで即座にロールバックします。
- データベースの移行には下位互換性がある必要があります --- 古いアプリケーション バージョンが新しいスキーマで動作する必要があります
- ヘルスチェックと準備プローブにより、サービスを提供する準備ができていないポッドへのトラフィックのルーティングを防止します
- エラー率監視に基づいた自動ロールバックにより、平均回復時間が 2 分未満に短縮されます
戦略の比較
| 戦略 | 複雑さ | ロールバック速度 | インフラストラクチャのコスト | 最適な用途 |
|---|---|---|---|---|
| 青緑 | 低い | インスタント (秒) | 導入時に 2 倍 | 重要なアプリケーション、頻繁に展開されない |
| ローリングアップデート | 中 | 分 | 導入中は 1.25 倍 | Kubernetes、頻繁なデプロイ |
| カナリア | 高 | 速い (秒) | 導入中は 1.05 倍 | トラフィックが多く、リスクに敏感 |
| 機能フラグ | 中 | インスタント | 1x | 段階的な機能ロールアウト |
ブルーグリーン展開
アーキテクチャ
Load Balancer
|
|--- [ACTIVE] Blue environment (v2.0.0) <-- receives 100% traffic
|
|--- [IDLE] Green environment (v2.1.0) <-- deployed, tested, waiting
導入時:
- v2.1.0 をアイドル (グリーン) 環境にデプロイします。
- 緑色に対してスモークテストを実行する
- ロードバランサーをグリーンに切り替えます
- 青色がアイドル状態になります (即時ロールバックが可能)
Nginx による実装
# /etc/nginx/conf.d/app.conf
upstream blue {
server 10.0.1.10:3000;
server 10.0.1.11:3000;
}
upstream green {
server 10.0.2.10:3000;
server 10.0.2.11:3000;
}
# Active environment - change this during deployment
map $host $active_upstream {
default blue; # Change to 'green' to switch
}
server {
listen 443 ssl;
server_name app.example.com;
location / {
proxy_pass http://$active_upstream;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
デプロイメントスクリプト
#!/bin/bash
set -e
CURRENT=$(cat /etc/nginx/active-env) # "blue" or "green"
TARGET=$( [ "$CURRENT" = "blue" ] && echo "green" || echo "blue" )
echo "Current: $CURRENT, deploying to: $TARGET"
# Deploy to inactive environment
ssh "deploy@$TARGET-1" "cd /opt/app && git pull && pnpm install --frozen-lockfile && pnpm build && pm2 restart all"
ssh "deploy@$TARGET-2" "cd /opt/app && git pull && pnpm install --frozen-lockfile && pnpm build && pm2 restart all"
# Wait for health checks
for i in 1 2; do
echo "Checking $TARGET-$i health..."
for attempt in $(seq 1 30); do
if curl -sf "http://$TARGET-$i:3000/health" > /dev/null; then
echo "$TARGET-$i is healthy"
break
fi
sleep 2
done
done
# Run smoke tests
pnpm test:smoke --base-url "http://$TARGET-1:3000"
# Switch traffic
sed -i "s/default $CURRENT/default $TARGET/" /etc/nginx/conf.d/app.conf
nginx -s reload
echo "$TARGET" > /etc/nginx/active-env
echo "Traffic switched to $TARGET. Rollback: change active-env back to $CURRENT"
ローリングアップデート
ローリング アップデートによりインスタンスが段階的に置き換えられ、一定の容量が常に利用可能になります。
Kubernetes ローリング アップデート
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # Create 1 extra pod during update
maxUnavailable: 0 # Never reduce below desired replicas
template:
spec:
containers:
- name: api
image: registry.example.com/api:v2.1.0
readinessProbe:
httpGet:
path: /health
port: 3001
initialDelaySeconds: 5
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 3001
initialDelaySeconds: 15
periodSeconds: 10
maxSurge: 1 と maxUnavailable: 0 を使用したローリング更新プロセス:
- v2.1.0 で新しいポッドを 1 つ作成します (合計 6 ポッド: 古いポッド 5 個 + 新しいポッド 1 個)
- 新しいポッドの準備プローブが通過するのを待ちます
- 1 つの古いポッドを終了します (5 つのポッド: 古いポッド 4 + 新しいポッド 1 つ)
- 別の新しいポッドを作成します (6 つのポッド: 古いポッド 4 個 + 新しいポッド 2 個)
- すべてのポッドが v2.1.0 になるまで繰り返します。
カナリアのデプロイメント
トラフィック分割
# Istio VirtualService for canary routing
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: api-canary
spec:
hosts:
- api.example.com
http:
- route:
- destination:
host: api-stable
port:
number: 3001
weight: 95
- destination:
host: api-canary
port:
number: 3001
weight: 5
カナリアの漸進的ロールアウト
| フェーズ | カナリアトラフィック | 期間 | 成功基準 |
|---|---|---|---|
| 1 | 1% | 10分 | エラー率 <0.1%、遅延 <500ms |
| 2 | 5% | 30分 | エラー率 <0.1%、遅延 <500ms |
| 3 | 25% | 1時間 | エラー率 <0.5%、遅延 <1s |
| 4 | 50% | 2時間 | エラー率 <0.5%、遅延 <1s |
| 5 | 100% | 完全展開 | 24時間安定 |
ダウンタイムなしのデータベース移行
ゼロダウンタイム展開における最大の課題は、データベース スキーマの変更です。アプリケーションの古いバージョンは新しいスキーマで動作する必要があり、その逆も同様です。
展開-契約パターン
フェーズ 1: 拡張 (スキーマ変更のデプロイ)
-- Add new column (nullable, no default)
ALTER TABLE orders ADD COLUMN shipping_method VARCHAR(50);
古いアプリケーション コードは新しい列を無視します。新しいアプリケーション コードは、古い列と新しい列の両方に書き込みます。
フェーズ 2: データの移行
-- Backfill existing data
UPDATE orders SET shipping_method = 'standard' WHERE shipping_method IS NULL;
フェーズ 3: 契約 (新しい列のみを使用するコードをデプロイ)
すべてのアプリケーション インスタンスが新しい列を使用した後、次のようになります。
-- Make column required
ALTER TABLE orders ALTER COLUMN shipping_method SET NOT NULL;
ALTER TABLE orders ALTER COLUMN shipping_method SET DEFAULT 'standard';
危険な移行パターン
| パターン | リスク | 安全な代替品 |
|---|---|---|
| 列の名前を変更 | 古いコードを壊す | 新しい列の追加、移行、古い列の削除 |
| 列をドロップ | 古いコードを壊す | 使用を中止し、次のリリースにドロップしてください。 |
| NOT NULL 列を追加 | ロックテーブル | NULL 可能、バックフィル、NOT NULL への変更を追加 |
| 列のタイプを変更する | テーブルをロックし、クエリを中断します。新しいタイプの新しい列を追加し、移行 | |
| 一意のインデックスを追加する | 大きなテーブル上のテーブルをロックする | コード0 |
自動ロールバック
エラー率に基づくロールバック
#!/bin/bash
# post-deploy-monitor.sh
DEPLOY_TIME=$(date +%s)
MONITOR_DURATION=300 # 5 minutes
ERROR_THRESHOLD=0.02 # 2%
while [ $(($(date +%s) - DEPLOY_TIME)) -lt $MONITOR_DURATION ]; do
ERROR_RATE=$(curl -s "http://prometheus:9090/api/v1/query?query=rate(http_requests_total{status=~'5..'}[2m])/rate(http_requests_total[2m])" | jq -r '.data.result[0].value[1]')
if (( $(echo "$ERROR_RATE > $ERROR_THRESHOLD" | bc -l) )); then
echo "ERROR: Rate $ERROR_RATE exceeds threshold $ERROR_THRESHOLD"
echo "Initiating rollback..."
kubectl rollout undo deployment/api
exit 1
fi
sleep 15
done
echo "Deployment healthy for $MONITOR_DURATION seconds"
よくある質問
どの戦略から始めるべきでしょうか?
ブルーグリーン展開から始めます。これは実装が最も簡単で、即時のロールバックを提供し、あらゆるアプリケーション アーキテクチャで動作します。ローリング アップデートは、多数のレプリカがある Kubernetes 環境に適しています。 Canary デプロイメントは、完全なロールアウトの前に実際のトラフィックで変更を検証する高トラフィックのアプリケーション向けです。
展開中に長時間実行されるバックグラウンド ジョブをどのように処理すればよいですか?
正常なシャットダウンを使用します。ポッドが終了信号を受信すると、新しいジョブの受け入れを停止し、進行中のジョブを (タイムアウト付きで) 終了してからシャットダウンします。 Kubernetes では、ジョブが完了するのに十分な時間を確保できるように terminationGracePeriodSeconds を構成します。猶予期間よりも長い時間がかかるジョブの場合は、失敗したジョブを生き残ったワーカーで再試行するジョブ キュー (Redis、RabbitMQ) を使用します。
展開中の WebSocket 接続はどうなりますか?
WebSocket 接続は長期間存続するため、慎重に扱う必要があります。ローリング アップデート中、古いポッド上の既存の接続は、ポッドが終了するまでアクティブのままになります。クライアントは自動再接続ロジックを実装する必要があります。 Blue-Green デプロイメントの場合、新しい接続を新しい環境に切り替えながら、既存の接続をタイムアウトで古い環境で排出できるようにします。
ゼロダウンタイム展開をテストするにはどうすればよいですか?
導入中に負荷テストを実行します。 k6 または同様のツールを使用して継続的なトラフィックを生成し、デプロイメントをトリガーします。ロールオーバー中にエラー、遅延の増加、接続の切断がないか確認してください。実装の詳細については、負荷テスト ガイド を参照してください。
次に何が起こるか
ダウンタイムゼロの展開は、頻繁に確実にリリースを行うための前提条件です。完全なデプロイ パイプラインには CI/CD 自動化、デプロイ後の検証には モニタリング と組み合わせます。
導入戦略のコンサルティングについては ECOSIRE にお問い合わせ、完全なインフラストラクチャ ロードマップについては DevOps ガイド をご覧ください。
ECOSIRE が発行 -- ビジネスを中断することなく導入できるよう支援します。
執筆者
ECOSIRE TeamTechnical Writing
The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.
関連記事
ウェブアプリケーションのための AWS EC2 デプロイメントガイド
完全な AWS EC2 デプロイ ガイド: インスタンスの選択、セキュリティ グループ、Node.js デプロイ、Nginx リバース プロキシ、SSL、自動スケーリング、CloudWatch モニタリング、コストの最適化。
Drizzle ORM によるゼロダウンタイムのデータベース移行
Drizzle ORM を使用して、ダウンタイムなしでデータベース移行を実行します。エキスパンド コントラクト パターン、下位互換性のあるスキーマ変更、ロールバック戦略、PostgreSQL の CI/CD 統合について説明します。
Monorepo プロジェクトの GitHub アクション CI/CD
Turborepo モノリポジトリ用の完全な GitHub Actions CI/CD ガイド: 影響を受けるのみのビルド、並列ジョブ、キャッシュ戦略、環境ベースのデプロイ、およびセキュリティのベスト プラクティス。