ゼロダウンタイム展開戦略: 更新中もアプリケーションを実行し続ける

Blue-Green、ローリング、カナリア戦略を使用して、ダウンタイムゼロの導入を実装します。データベースの移行、ヘルスチェック、自動ロールバック パターンについて説明します。

E
ECOSIRE Research and Development Team
|2026年3月16日4 分で読める804 語数|

ゼロダウンタイム展開戦略: 更新中もアプリケーションを実行し続ける

計画的なダウンタイムにより、企業は 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

導入時:

  1. v2.1.0 をアイドル (グリーン) 環境にデプロイします。
  2. 緑色に対してスモークテストを実行する
  3. ロードバランサーをグリーンに切り替えます
  4. 青色がアイドル状態になります (即時ロールバックが可能)

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: 1maxUnavailable: 0 を使用したローリング更新プロセス:

  1. v2.1.0 で新しいポッドを 1 つ作成します (合計 6 ポッド: 古いポッド 5 個 + 新しいポッド 1 個)
  2. 新しいポッドの準備プローブが通過するのを待ちます
  3. 1 つの古いポッドを終了します (5 つのポッド: 古いポッド 4 + 新しいポッド 1 つ)
  4. 別の新しいポッドを作成します (6 つのポッド: 古いポッド 4 個 + 新しいポッド 2 個)
  5. すべてのポッドが 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

カナリアの漸進的ロールアウト

フェーズカナリアトラフィック期間成功基準
11%10分エラー率 <0.1%、遅延 <500ms
25%30分エラー率 <0.1%、遅延 <500ms
325%1時間エラー率 <0.5%、遅延 <1s
450%2時間エラー率 <0.5%、遅延 <1s
5100%完全展開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 が発行 -- ビジネスを中断することなく導入できるよう支援します。

E

執筆者

ECOSIRE Research and Development Team

ECOSIREでエンタープライズグレードのデジタル製品を開発。Odoo統合、eコマース自動化、AI搭載ビジネスソリューションに関するインサイトを共有しています。

WhatsAppでチャット