インクリメントロールアウトとフューチャーフラグ
(トップページはこちら) - (アプリケーションのデプロイとリリースを始める)
本番環境へのデプロイメントで最も恐れられているのは、「全ユーザーに影響を与える障害」です。新機能のリリースやアプリケーションの更新が、予期しないエラーやパフォーマンス低下を引き起こし、ビジネスに深刻な影響を与える可能性があります。
本記事では、GitLabが提供する2つの段階的デプロイメント手法を解説します。これらを適切に組み合わせることで、デプロイメントリスクを大幅に削減し、問題が発生しても影響範囲を最小限に抑えられます。
本記事で学べること
- インフラレベルとアプリケーションレベルの段階的デプロイメント手法
- 各手法の使い分けと組み合わせ方
- 実運用で必要となる監視とロールバックの実践知識
1. 2つのアプローチ:インフラとアプリケーション
GitLabは、異なるレイヤーで動作する2つの段階的デプロイメント機能を提供しています。
1.1. インクリメンタルロールアウト(インフラレベル)
対象: Kubernetesクラスタ上のPod
制御単位: インフラストラクチャ(コンテナ)
適用タイミング: デプロイメント時
アプリケーション全体を段階的に新バージョンに置き換えます。例えば、10個のPodで構成されるアプリケーションの場合、10% → 25% → 50% → 100%と段階的にPodを更新していきます。
主な用途
- アプリケーション全体のバージョンアップ
- インフラ構成の変更
- 依存ライブラリの更新
1.2. フィーチャーフラグ(アプリケーションレベル)
対象: アプリケーションの特定機能
制御単位: ユーザーまたはユーザーグループ
適用タイミング: 実行時(動的切り替え可能)
デプロイ済みのアプリケーション内で、特定の機能のオン・オフを制御します。コードはすでに本番環境に存在していますが、フラグによって実行を制御します。
主な用途
- 新機能の段階的公開
- A/Bテスト
- 緊急時の機能無効化
1.3. 両者の比較と使い分け
| 項目 | インクリメンタルロールアウト | フィーチャーフラグ |
|---|---|---|
| 制御対象 | インフラ(Pod) | 機能(コード) |
| 切り替え速度 | 遅い(数分〜数十分) | 即座(秒単位) |
| ロールバック | 前バージョンへの再デプロイ | フラグのオフ |
| 適用範囲 | アプリケーション全体 | 特定機能のみ |
| 前提条件 | Kubernetes環境 | クライアントライブラリの統合 |
| 運用コスト | 低(CI/CD設定のみ) | 中(フラグ管理が必要) |
推奨される使い分け
2. インクリメンタルロールアウトの実装
2.1. 基本的な考え方
インクリメンタルロールアウトでは、以下の段階を経てデプロイメントを進めます。
推奨される段階設定
| 段階 | 割合 | 目的 | 監視期間の目安 |
|---|---|---|---|
| カナリア | 10% | 致命的なバグの早期発見 | 15〜30分 |
| 初期展開 | 25% | パフォーマンス影響の確認 | 30分〜1時間 |
| 中間展開 | 50% | 負荷分散の検証 | 1〜2時間 |
| 完全展開 | 100% | 全ユーザーへの提供 | 継続監視 |
この割合は、アプリケーションの特性やユーザー数に応じて調整してください。重要なのは、各段階で十分な監視期間を設けることです。
2.2. 手動ロールアウトの実装
.gitlab-ci.ymlでの設定例です。
# 共通テンプレート
.rollout_template: &rollout_template
image: registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:latest
script:
- auto-deploy rollout $ROLLOUT_PERCENTAGE
# 手動ロールアウト用テンプレート
.manual_rollout_template: &manual_rollout_template
<<: *rollout_template
stage: production
when: manual
allow_failure: false
# 各段階の定義
rollout 10%:
<<: *manual_rollout_template
variables:
ROLLOUT_PERCENTAGE: 10
rollout 25%:
<<: *manual_rollout_template
variables:
ROLLOUT_PERCENTAGE: 25
rollout 50%:
<<: *manual_rollout_template
variables:
ROLLOUT_PERCENTAGE: 50
rollout 100%:
<<: *manual_rollout_template
variables:
ROLLOUT_PERCENTAGE: 100
運用フロー
2.3. 時間指定ロールアウトの実装
自動的に段階を進める設定です。
# 時間指定ロールアウト用テンプレート
.timed_rollout_template: &timed_rollout_template
<<: *rollout_template
when: delayed
start_in: 5 minutes # 待機時間を設定
# 各段階の定義
timed rollout 10%:
<<: *timed_rollout_template
stage: timed rollout 10%
variables:
ROLLOUT_PERCENTAGE: 10
timed rollout 25%:
<<: *timed_rollout_template
stage: timed rollout 25%
start_in: 10 minutes # 段階ごとに待機時間を変更可能
variables:
ROLLOUT_PERCENTAGE: 25
timed rollout 50%:
<<: *timed_rollout_template
stage: timed rollout 50%
start_in: 15 minutes
variables:
ROLLOUT_PERCENTAGE: 50
timed rollout 100%:
<<: *timed_rollout_template
stage: timed rollout 100%
start_in: 30 minutes
variables:
ROLLOUT_PERCENTAGE: 100
待機時間の設定指針
- 10%段階: 5〜10分(致命的なバグの検出)
- 25%段階: 10〜15分(パフォーマンス影響の確認)
- 50%段階: 15〜30分(負荷テスト)
- 100%段階: 30分〜1時間(最終確認)
時間指定ロールアウトでも、カウントダウン中に手動でトリガーできます。問題を検知した場合は、待機時間中に介入してロールバックを実行できます。
2.4. Blue-Greenデプロイメントとの組み合わせ
Blue-Greenデプロイメントは、2つの本番環境を用意し、トラフィックを切り替える手法です。インクリメンタルロールアウトと組み合わせることで、さらに安全性が向上します。
基本構成
実装のポイント
- 環境の完全分離: Blue環境とGreen環境は、データベース接続以外は完全に独立させます
- 段階的な検証: Green環境内で段階的ロールアウトを実施し、十分に検証します
- 瞬時の切り替え: 検証完了後、ロードバランサーの設定変更でトラフィックを切り替えます
- 即座のロールバック: 問題発生時は、再度Blue環境にトラフィックを戻します
3. フィーチャーフラグの実装
3.1. フィーチャーフラグの基本設定
フィーチャーフラグの作成手順
- プロジェクトで「デプロイ」→「フィーチャーフラグ」を選択
- 「新しいフィーチャーフラグ」をクリック
- 命名規則に従って名前を入力(例:
enable_new_dashboard) - 説明を追加(例: 「新しいダッシュボードUIの有効化」)
- ストラテジーを選択
- 対象環境を指定
命名規則のベストプラクティス
-
enable_プレフィックス: 機能の有効化(例:enable_new_search) -
disable_プレフィックス: 機能の無効化(例:disable_legacy_api) -
rollout_プレフィックス: 段階的展開中(例:rollout_payment_v2)
3.2. ストラテジーの選択ガイド
GitLabは5つのストラテジーを提供しています。それぞれの特性と使い分けを理解することが重要です。
| ストラテジー | 対象 | 一貫性 | 主な用途 | 実装難易度 |
|---|---|---|---|---|
| 全ユーザー | 全員 | - | 機能の完全有効化/無効化 | 低 |
| パーセントロールアウト | ページビュー | 設定可能 | 段階的な機能公開 | 中 |
| ユーザーの割合 | 認証ユーザー | 高 | 認証ユーザーへの段階展開 | 中 |
| ユーザーID | 特定ユーザー | 高 | 内部テスト、VIPユーザー | 低 |
| ユーザーリスト | ユーザーグループ | 高 | ベータテスター、部門別展開 | 中 |
3.2.1. 全ユーザー(All Users)
最もシンプルなストラテジーです。フラグのオン・オフで、全ユーザーに対して機能を有効化または無効化します。
使用例
- 緊急時の機能無効化
- メンテナンスモードの切り替え
- 完全に検証済みの機能の恒久的な有効化
3.2.2. パーセントロールアウト(Percent Rollout)
ページビューの一定割合に対して機能を有効化します。一貫性(スティッキネス)の基準を選択できます。
一貫性の選択肢
| 基準 | 動作 | 適用シーン |
|---|---|---|
| ユーザーID | 同じユーザーには常に同じ結果 | ログインユーザー向け機能 |
| セッションID | 同じセッションには常に同じ結果 | 匿名ユーザー向け機能 |
| ランダム | 毎回ランダムに判定 | A/Bテスト(統計的分析) |
| 利用可能なID | ユーザーID → セッションID → ランダムの順で判定 | 汎用的な段階展開 |
設定例: 段階的な機能公開
# 週次での段階的展開計画
第1週: 5% # 早期フィードバック収集
第2週: 15% # 初期問題の修正後
第3週: 30% # パフォーマンス検証
第4週: 50% # 大規模検証
第5週: 75% # 最終確認
第6週: 100% # 完全展開
注意点: 「ランダム」を選択すると、同じユーザーでもアクセスごとに機能の有効/無効が変わるため、ユーザー体験が一貫しません。特別な理由がない限り、「利用可能なID」を推奨します。
3.2.3. ユーザーの割合(Percent of Users)
認証済みユーザーの一定割合に対して機能を有効化します。ユーザーIDに基づくため、同じユーザーには常に同じ結果が返されます。
使用例
- 会員向け新機能の段階的公開
- プレミアムユーザー向け機能のテスト
注意: このストラテジーは、パーセントロールアウトで「ユーザーID」を選択した場合と同じ動作をします。より柔軟なパーセントロールアウトの使用を推奨します。
3.2.4. ユーザーID(User IDs)
特定のユーザーIDを指定して、そのユーザーにのみ機能を有効化します。
使用例
- 開発チームメンバーへの先行公開
- 特定顧客向けのカスタム機能
- VIPユーザーへの優先提供
設定例
yamada@example.com, suzuki@example.com, tanaka@example.com
または
user001, user002, user003
3.2.5. ユーザーリスト(User List)
事前に作成したユーザーリストに対して機能を有効化します。ユーザーIDストラテジーと似ていますが、リストを再利用できる点が異なります。
使用例
- ベータテスターグループ
- 部門別の段階展開
- 地域別の機能公開
ユーザーリストの管理
- 「デプロイ」→「フィーチャーフラグ」→「ユーザーリストを表示」
- 「新しいユーザーリスト」で作成(例:
beta_testers、tokyo_office) - リストにユーザーIDを追加
- 複数のフィーチャーフラグで同じリストを再利用可能
実践的な活用例
リスト名: beta_testers
用途: 新機能のベータテスト
メンバー: 社内テスター20名 + 外部協力者10名
リスト名: premium_users
用途: プレミアム機能の先行提供
メンバー: 有料プラン契約者
リスト名: exclude_problematic_users
用途: 特定機能の除外(バグ回避)
メンバー: 問題が発生する環境のユーザー
3.3. アプリケーションへの統合
フィーチャーフラグを使用するには、アプリケーションにクライアントライブラリを統合する必要があります。
3.3.1. 認証情報の取得
- 「デプロイ」→「フィーチャーフラグ」→「設定」を選択
- 以下の情報を取得
-
API URL:
https://gitlab.com/api/v4/feature_flags/unleash/42 -
インスタンスID:
29QmjsW6KngPR5JNPMWx -
アプリケーション名:
production(環境名を指定)
-
API URL:
3.3.2. Go言語での実装
package main
import (
"io"
"log"
"net/http"
"github.com/Unleash/unleash-client-go/v3"
)
func init() {
unleash.Initialize(
unleash.WithUrl("https://gitlab.com/api/v4/feature_flags/unleash/42"),
unleash.WithInstanceId("29QmjsW6KngPR5JNPMWx"),
unleash.WithAppName("production"),
unleash.WithRefreshInterval(15 * time.Second), // ポーリング間隔
)
}
func dashboardHandler(w http.ResponseWriter, req *http.Request) {
// ユーザーIDを含むコンテキストを作成
ctx := context.Context{
UserId: getUserIdFromRequest(req), // リクエストからユーザーIDを取得
}
if unleash.IsEnabled("enable_new_dashboard", unleash.WithContext(ctx)) {
// 新しいダッシュボードを表示
renderNewDashboard(w)
} else {
// 従来のダッシュボードを表示
renderLegacyDashboard(w)
}
}
func getUserIdFromRequest(req *http.Request) string {
// セッションやJWTからユーザーIDを取得する実装
// 例: セッションから取得
session, _ := store.Get(req, "session-name")
if userId, ok := session.Values["user_id"].(string); ok {
return userId
}
return ""
}
3.3.3. Rubyでの実装
require 'unleash'
require 'unleash/context'
# 初期化(アプリケーション起動時に1回実行)
UNLEASH = Unleash::Client.new({
url: 'https://gitlab.com/api/v4/feature_flags/unleash/42',
app_name: 'production',
instance_id: '29QmjsW6KngPR5JNPMWx',
refresh_interval: 15 # 秒単位
})
# コントローラーでの使用例
class DashboardController < ApplicationController
def index
context = Unleash::Context.new(
user_id: current_user&.id&.to_s, # ユーザーIDは文字列で渡す
session_id: session.id.to_s,
remote_address: request.remote_ip
)
if UNLEASH.is_enabled?('enable_new_dashboard', context)
render :new_dashboard
else
render :legacy_dashboard
end
end
end
3.3.4. デフォルト値の設定
フィーチャーフラグが取得できない場合(ネットワークエラーなど)に備えて、デフォルト値を設定します。
// Go言語の例
func isFeatureEnabled(featureName string, ctx context.Context) bool {
// フラグが取得できない場合はfalseを返す(安全側に倒す)
return unleash.IsEnabled(featureName,
unleash.WithContext(ctx),
unleash.WithFallback(false),
)
}
# Rubyの例
def feature_enabled?(feature_name, context)
# フラグが取得できない場合はfalseを返す
UNLEASH.is_enabled?(feature_name, context, false)
end
デフォルト値の選択指針
-
新機能の場合:
false(無効)を推奨。問題発生時に従来の動作に戻ります -
既存機能の無効化フラグの場合:
false(機能は有効)を推奨 - 重要な機能の場合: ビジネス要件に応じて慎重に判断
3.4. Unleash Proxyの活用
大規模なアプリケーションや、多数のクライアントがある場合は、Unleash Proxyの使用を推奨します。
Unleash Proxyのメリット
- レート制限の回避: 複数のクライアントからのリクエストを集約
- レスポンスの高速化: プロキシ側でキャッシュを保持
- クライアント側の実装簡素化: 軽量なProxyクライアントを使用可能
Docker Composeでの起動例
version: '3.8'
services:
unleash-proxy:
image: unleashorg/unleash-proxy:latest
ports:
- "3000:3000"
environment:
UNLEASH_PROXY_SECRETS: "your-secret-key-here"
UNLEASH_URL: "https://gitlab.com/api/v4/feature_flags/unleash/42"
UNLEASH_INSTANCE_ID: "29QmjsW6KngPR5JNPMWx"
UNLEASH_APP_NAME: "production"
UNLEASH_API_TOKEN: "not-used-but-required"
UNLEASH_FETCH_INTERVAL: "15000" # ミリ秒単位(15秒)
restart: unless-stopped
クライアント側の実装(JavaScript例)
import { UnleashClient } from 'unleash-proxy-client';
const unleash = new UnleashClient({
url: 'http://unleash-proxy:3000/proxy',
clientKey: 'your-secret-key-here',
appName: 'my-webapp',
refreshInterval: 15, // 秒単位
});
unleash.start();
// 機能の有効/無効を確認
if (unleash.isEnabled('enable_new_dashboard')) {
renderNewDashboard();
} else {
renderLegacyDashboard();
}
4. 監視とロールバック
段階的デプロイメントの成功には、適切な監視とロールバック基準が不可欠です。
4.1. 監視すべきメトリクス
各段階で以下のメトリクスを監視します。
| カテゴリ | メトリクス | 正常範囲の例 | アラート基準 |
|---|---|---|---|
| エラー率 | HTTP 5xx エラー率 | < 0.1% | > 1% |
| アプリケーションエラー率 | < 0.5% | > 2% | |
| パフォーマンス | 平均レスポンス時間 | < 200ms | > 500ms または 前バージョンの2倍 |
| 95パーセンタイルレスポンス時間 | < 500ms | > 1000ms | |
| リソース | CPU使用率 | < 70% | > 85% |
| メモリ使用率 | < 80% | > 90% | |
| データベース接続数 | < 80% | > 90% | |
| ビジネス | コンバージョン率 | 前バージョンと同等 | 10%以上の低下 |
| トランザクション成功率 | > 99% | < 98% |
4.2. ロールバック基準
以下のいずれかに該当する場合、即座にロールバックを実行します。
即座にロールバック(Critical)
- HTTP 5xxエラー率が1%を超える
- データ損失やデータ破損が発生
- セキュリティ脆弱性が発見される
- 決済処理など重要な機能が動作しない
監視を強化して判断(Warning)
- レスポンス時間が前バージョンの1.5倍を超える
- CPU/メモリ使用率が想定より高い
- 一部のユーザーから問題報告がある
段階を進めない(Hold)
- メトリクスが安定しない
- 監視データが不十分
- ビジネス指標が低下傾向
4.3. ロールバックの実行手順
4.3.1. インクリメンタルロールアウトのロールバック
# 前バージョンへのロールバックジョブ
rollback:
<<: *rollout_template
stage: rollback
when: manual
variables:
ROLLOUT_PERCENTAGE: 100
ROLLBACK: "true" # 前バージョンを指定
script:
- auto-deploy rollback
手順
- GitLabのパイプライン画面で「rollback」ジョブを実行
- 全Podが前バージョンに戻るまで監視(通常5〜10分)
- メトリクスが正常に戻ったことを確認
- インシデントレポートを作成
4.3.2. フィーチャーフラグのロールバック
フィーチャーフラグは即座にロールバック可能です。
手順
- GitLabで「デプロイ」→「フィーチャーフラグ」を選択
- 該当フラグのステータストグルを「無効」に切り替え
- 数秒以内に全クライアントに反映される(ポーリング間隔に依存)
- メトリクスが正常に戻ったことを確認
段階的なロールバック
全ユーザーへの影響を避けるため、段階的にロールバックすることも可能です。
100% → 50% → 25% → 10% → 0%
パーセントロールアウトストラテジーの割合を徐々に下げることで、影響範囲を限定しながらロールバックできます。
4.4. 監視ダッシュボードの構築
Grafanaなどの監視ツールで、デプロイメント専用のダッシュボードを構築します。
推奨される構成
┌─────────────────────────────────────────┐
│ デプロイメント監視ダッシュボード │
├─────────────────────────────────────────┤
│ 現在のロールアウト状況 │
│ ├ 現在の段階: 25% │
│ ├ 開始時刻: 2025-01-15 10:30 │
│ └ 経過時間: 15分 │
├─────────────────────────────────────────┤
│ エラー率(リアルタイム) │
│ ├ 新バージョン: 0.05% ✓ │
│ └ 旧バージョン: 0.03% ✓ │
├─────────────────────────────────────────┤
│ レスポンス時間(P95) │
│ ├ 新バージョン: 180ms ✓ │
│ └ 旧バージョン: 175ms ✓ │
├─────────────────────────────────────────┤
│ リソース使用率 │
│ ├ CPU: 65% ✓ │
│ ├ メモリ: 72% ✓ │
│ └ DB接続: 45% ✓ │
├─────────────────────────────────────────┤
│ ビジネスメトリクス │
│ ├ トランザクション成功率: 99.8% ✓ │
│ └ コンバージョン率: 3.2% ✓ │
└─────────────────────────────────────────┘
5. 実践的な運用パターン
5.1. パターン1: 新機能の段階的リリース
最も一般的なパターンです。フィーチャーフラグとインクリメンタルロールアウトを組み合わせます。
タイムライン例
| 日 | アクション | 対象 |
|---|---|---|
| 1日目 | コードデプロイ(フラグ無効) | インフラ: 10% → 100% |
| 2日目 | 内部テスト | 社内ユーザー10名 |
| 3日目 | 外部ベータテスト | ベータテスター50名 |
| 5日目 | 段階的公開開始 | 一般ユーザー: 10% |
| 7日目 | 拡大 | 一般ユーザー: 25% |
| 10日目 | 拡大 | 一般ユーザー: 50% |
| 14日目 | 完全展開 | 一般ユーザー: 100% |
| 28日目 | フラグ削除 | コードクリーンアップ |
5.2. パターン2: 緊急修正のリリース
セキュリティパッチなど、迅速なリリースが必要な場合のパターンです。
特徴
- 時間指定ロールアウトで自動化
- 待機時間を短縮(5〜10分)
- 自動監視とアラートを強化
- 問題検知時は即座に自動ロールバック
5.3. パターン3: A/Bテスト
ビジネス指標を比較するためのパターンです。
# フィーチャーフラグ設定
名前: ab_test_new_checkout_flow
ストラテジー: パーセントロールアウト
割合: 50%
一貫性: ユーザーID
実装例(Go言語)
func checkoutHandler(w http.ResponseWriter, req *http.Request) {
ctx := context.Context{
UserId: getUserId(req),
}
variant := "control" // デフォルトは従来版
if unleash.IsEnabled("ab_test_new_checkout_flow", unleash.WithContext(ctx)) {
variant = "treatment" // 新版
renderNewCheckoutFlow(w)
} else {
renderLegacyCheckoutFlow(w)
}
// アナリティクスにバリアントを記録
analytics.Track("checkout_started", map[string]interface{}{
"user_id": getUserId(req),
"variant": variant,
})
}
分析期間
- 最低2週間のデータ収集を推奨
- 統計的有意性を確認(サンプルサイズ計算)
- 曜日や時間帯の偏りを考慮
5.4. パターン4: 段階的な廃止(Deprecation)
古い機能を段階的に廃止するパターンです。
段階的廃止のタイムライン
| フェーズ | 期間 | アクション |
|---|---|---|
| 告知 | 1ヶ月前 | 廃止予定を告知、移行ガイド公開 |
| 並行稼働 | 開始 | 新旧両方が利用可能 |
| 段階的移行 | 1〜2ヶ月 | フラグで新機能に誘導 |
| 完全移行 | 移行完了後 | 全ユーザーが新機能を使用 |
| 監視期間 | 2週間 | 旧機能の利用がないことを確認 |
| クリーンアップ | 最終 | 旧コードとフラグを削除 |
6. トラブルシューティング
6.1. よくある問題と対処法
問題1: フィーチャーフラグが反映されない
症状: フラグを有効化したが、アプリケーションで機能が有効にならない
原因と対処法
| 原因 | 確認方法 | 対処法 |
|---|---|---|
| ポーリング間隔が長い | クライアントの設定確認 |
refreshIntervalを短縮(最小15秒推奨) |
| 環境名の不一致 | API URLとアプリの環境名を確認 |
app_nameを正しい環境名に修正 |
| ユーザーIDが渡されていない | ログでコンテキストを確認 | ユーザーID取得処理を実装 |
| キャッシュの問題 | ブラウザキャッシュを確認 | ハードリフレッシュまたはキャッシュクリア |
デバッグ用コード(Go言語)
// フラグの状態をログ出力
func debugFeatureFlag(featureName string, ctx context.Context) {
enabled := unleash.IsEnabled(featureName, unleash.WithContext(ctx))
log.Printf("Feature: %s, Enabled: %v, UserID: %s",
featureName, enabled, ctx.UserId)
}
問題2: ロールアウト中にパフォーマンスが低下
症状: 新バージョンのPodでレスポンス時間が増加
原因と対処法
| 原因 | 確認方法 | 対処法 |
|---|---|---|
| リソース不足 | CPU/メモリ使用率を確認 | Podのリソース制限を増やす |
| データベースクエリの非効率 | スロークエリログを確認 | クエリを最適化、インデックスを追加 |
| 外部API呼び出しの遅延 | APMツールでトレース確認 | タイムアウト設定、リトライ処理を追加 |
| コールドスタート | Pod起動直後のメトリクス確認 | ウォームアップ処理を実装 |
問題3: ロールバックが完了しない
症状: ロールバックジョブを実行したが、一部のPodが更新されない
対処法
# Kubernetesで直接確認
kubectl get pods -n production
kubectl describe pod <pod-name> -n production
# 強制的に再起動
kubectl rollout restart deployment/<deployment-name> -n production
# ロールアウト履歴を確認
kubectl rollout history deployment/<deployment-name> -n production
# 特定のリビジョンにロールバック
kubectl rollout undo deployment/<deployment-name> --to-revision=2 -n production
6.2. パフォーマンス最適化
6.2.1. レート制限への対処
GitLab.comでは、フィーチャーフラグAPIに対してレート制限があります。
制限値
- 未認証トラフィック: 同一IPから1分あたり500リクエスト
対処法
- ポーリング間隔の調整
// 推奨設定
unleash.Initialize(
unleash.WithRefreshInterval(30 * time.Second), // 30秒以上を推奨
)
- Unleash Proxyの使用
複数のアプリケーションインスタンスがある場合、Unleash Proxyを経由させることでリクエスト数を削減できます。
クライアント数: 100
ポーリング間隔: 15秒
直接接続の場合:
100 × (60秒 / 15秒) = 400リクエスト/分 → OK
Proxy経由の場合:
1 × (60秒 / 15秒) = 4リクエスト/分 → 大幅に削減
- フェッチ間隔の増加
# Unleash Proxy設定
environment:
UNLEASH_FETCH_INTERVAL: "30000" # 30秒(ミリ秒単位)
6.2.2. クライアント側のキャッシュ
フィーチャーフラグの評価結果をクライアント側でキャッシュすることで、パフォーマンスを向上させます。
type FeatureFlagCache struct {
cache map[string]bool
mu sync.RWMutex
ttl time.Duration
}
func (c *FeatureFlagCache) IsEnabled(featureName string, ctx context.Context) bool {
c.mu.RLock()
if cached, ok := c.cache[featureName]; ok {
c.mu.RUnlock()
return cached
}
c.mu.RUnlock()
// キャッシュにない場合はUnleashに問い合わせ
enabled := unleash.IsEnabled(featureName, unleash.WithContext(ctx))
c.mu.Lock()
c.cache[featureName] = enabled
c.mu.Unlock()
// TTL後にキャッシュをクリア
time.AfterFunc(c.ttl, func() {
c.mu.Lock()
delete(c.cache, featureName)
c.mu.Unlock()
})
return enabled
}
7. ベストプラクティス
7.1. フィーチャーフラグのライフサイクル管理
フィーチャーフラグは一時的なものです。恒久的に残すと、コードの複雑性が増大します。
推奨されるライフサイクル
作成 → テスト → 段階的展開 → 完全展開 → 安定稼働 → 削除
↓ ↓ ↓ ↓ ↓ ↓
1日 3日 1-2週間 即座 2週間 即座
フラグの削除タイミング
- 100%展開後、2週間の安定稼働を確認
- ビジネスメトリクスが正常
- ユーザーからの問題報告なし
- ロールバックの必要性が低い
削除手順
- GitLabで「コード参照を検索」を実行(Premium/Ultimate)
- コード内のフラグ判定を削除し、新機能のコードのみを残す
- テストを実行して動作確認
- GitLabでフィーチャーフラグを削除
7.2. 命名規則とドキュメント
フラグ名の命名規則
<プレフィックス>_<機能名>_<バージョン>
例:
enable_new_dashboard_v2
rollout_payment_gateway_stripe
disable_legacy_search_api
説明欄の記載内容
説明: 新しいダッシュボードUIの有効化
目的: ユーザビリティ向上、レスポンス時間の短縮
担当者: @yamada
関連イシュー: #1234
作成日: 2025-01-15
削除予定日: 2025-02-15
7.3. セキュリティ考慮事項
機密情報の扱い
- フィーチャーフラグ名に機密情報を含めない
- ユーザーIDは暗号化せずに使用可能(GitLabに送信されるのはハッシュ値)
- API URLとインスタンスIDは環境変数で管理
アクセス制御
- フィーチャーフラグの作成・編集権限を制限
- 本番環境のフラグ変更には承認プロセスを設ける
- 変更履歴を監査ログで記録
7.4. チーム運用
責任の明確化
| 役割 | 責任 |
|---|---|
| 開発者 | フラグの実装、テスト、削除 |
| SRE | インフラロールアウトの実行、監視 |
| プロダクトマネージャー | フラグの有効化判断、ビジネスメトリクス確認 |
| QA | 各段階での品質確認 |
コミュニケーション
- デプロイメント前にチーム全体に通知
- 各段階の進行状況を共有チャンネルで報告
- 問題発生時のエスカレーションパスを明確化
8. まとめ
GitLabのインクリメンタルロールアウトとフィーチャーフラグは、本番環境へのデプロイメントリスクを大幅に削減する強力なツールです。
重要なポイント
-
レイヤーの理解: インフラレベル(ロールアウト)とアプリケーションレベル(フラグ)の違いを理解し、適切に使い分ける
-
段階的なアプローチ: 10% → 25% → 50% → 100%のような段階を設け、各段階で十分な監視を行う
-
監視とロールバック: 明確なメトリクスとロールバック基準を設定し、問題発生時は躊躇なくロールバックする
-
ライフサイクル管理: フィーチャーフラグは一時的なものとして扱い、安定稼働後は速やかに削除する
-
チーム運用: 責任を明確化し、コミュニケーションを密にすることで、スムーズな運用を実現する
これらの手法を適切に活用することで、ユーザーへの影響を最小限に抑えながら、継続的に価値を提供できるデプロイメントプロセスを確立できます。小さく始めて、徐々に洗練させていくことをお勧めします。