目次

AWS AppConfig 完全ガイド v2.0

フィーチャーフラグ・設定管理・段階的ロールアウト

AWS AppConfig は、「アプリケーション設定(フィーチャーフラグ・設定値)を安全にデプロイ・動的に更新するサービスで、段階的ロールアウト(Canary・Linear)・バリデーション(JSON Schema・Lambda)・自動ロールバック(CloudWatch アラーム連携)を実現するサービス」 です。コードのデプロイなしにアプリの動作を変更でき、問題発生時は即座にフラグをオフにして影響を局所化できます。本ドキュメントは初心者から実務者向けに、フィーチャーフラグ・設定管理・デプロイ戦略・2025-2026 動向を体系的に解説する包括的ガイドです。

ドキュメントの目的

本ガイドは以下を対象としています。

  • 初心者向け: AppConfig とは何か、フィーチャーフラグの基本を学びたい方
  • 開発者向け: フィーチャーフラグ・動的設定をアプリに組み込みたい方
  • SRE/DevOps 向け: 段階的ロールアウト・自動ロールバック・設定バリデーション
  • 意思決定者向け: AppConfig vs LaunchDarkly vs Unleash の選定

2025-2026 年の AppConfig エコシステム

  • Enhanced Targeting(2026年3月): ユーザーセグメンテーション・属性ベースのフラグ制御
  • CloudWatch Evidence 統合: A/B テスト結果の自動分析・推奨値提示
  • AppConfig Agent Lambda Extension: キャッシング・オフライン対応の強化
  • ML 駆動 Anomaly Detection: メトリクス異常自動検知でロールバック自動化
  • Secrets Manager 統合: 設定値と秘密情報の統一管理

目次

  1. 概要
  2. AppConfig が解決する課題
  3. 主な特徴
  4. アーキテクチャ
  5. コアコンポーネント
  6. フィーチャーフラグの設定
  7. デプロイ戦略
  8. バリデーター
  9. 主要ユースケース
  10. 設定・操作の具体例
  11. 類似サービス比較表
  12. ベストプラクティス
  13. トラブルシューティング
  14. 2025-2026 最新動向
  15. 学習リソース・参考文献
  16. 実装例
  17. チェックリスト
  18. まとめ

概要

初心者向けメモ: AppConfig は「新機能をオン/オフしたい」「リリース前にごく少数(1%)に試したい」「問題が発生したら即座にオフにしたい」という要件をシンプルに実現するサービスです。通常は機能フラグライブラリ(LaunchDarkly・Unleash)を使いますが、AppConfig は AWS ネイティブで、CloudWatch アラームによる自動ロールバックが標準装備。AWS 環境では AppConfig で十分な場合が多いです。

AWS AppConfig 公式定義:

“AWS AppConfig feature flags and dynamic configurations help software builders quickly and securely adjust application behavior in production environments without full code deployments.”

このサービスを選ぶ理由

なぜ AppConfig でないといけないのか?

理由 詳細
コードデプロイなしの機能制御 フィーチャーフラグのオン/オフで新機能リリース、問題発生時は即座にオフ
段階的ロールアウト 全体リリース前に 10% → 25% → 50% → 100% と段階的に展開し問題を早期検知
自動ロールバック CloudWatch アラームがエラー率・レイテンシ閾値を超過したら自動的に前バージョンに復元
AWS ネイティブ統合 IAM・KMS・CloudWatch・Secrets Manager と完全統合、追加ツール不要
コスト最適化 LaunchDarkly($75/月~)より圧倒的に安い、API 呼び出し単位の従量課金

具体的なユースケース

  • 新機能の段階的リリース(Beta ユーザー → 10% → 全体のフィーチャーフラグ制御)
  • 緊急メンテナンス時の機能無効化(コードデプロイなしにリクエスト受付をオフ)
  • A/B テストのフラグ管理(アルゴリズム A vs B の出し分け制御)
  • Lambda 関数の動的設定更新(環境変数変更なしにパラメーター値をホットアップデート)
  • アプリケーションのレート制限値を動的変更(負荷状況に応じたスロットリング調整)

AppConfig が解決する課題

課題 従来(コードデプロイ) AppConfig 解決方法
新機能リリース時間 本番デプロイに 30 分~数時間 フラグ設定で即座リリース(数分)
ロールバック コード修正 → テスト → デプロイで数時間 フラグ OFF で即座ロールバック
段階的テスト Staging 環境でテスト後に本番デプロイ Canary・Linear 戦略で本番ユーザーの 1% でテスト
緊急対応 コードデプロイ待機 フラグ OFF で即座に対応
A/B テスト ロードバランサーレベルでの振り分け AppConfig フラグで アルゴリズム振り分け
複数環境の同期 本番・ステージング・開発の設定がズレる AppConfig で統一管理
設定ミス検出 本番で初めて検出(ダウンタイム) JSON Schema バリデーションで事前防止

主な特徴

1. フィーチャーフラグ管理

Flag と Attribute

  • Flag:有効/無効の binary 切り替え
  • Attribute:フラグの詳細設定(色、モデルバージョン等)

Flag Definition

{
  "flags": {
    "new-checkout": {
      "name": "New Checkout Flow",
      "description": "Enable redesigned checkout UI"
    },
    "ai-recommendations": {
      "name": "AI Product Recommendations",
      "attributes": {
        "model-version": {
          "constraints": {
            "type": "string",
            "enum": ["v1", "v2", "v3"]
          }
        }
      }
    }
  },
  "values": {
    "new-checkout": { "enabled": true },
    "ai-recommendations": {
      "enabled": true,
      "model-version": "v2"
    }
  }
}

2. デプロイ戦略

Immediate

  • 即時全体に適用
  • テスト環境向け

Linear N% every M minutes

  • N% のトラフィックに展開、M 分ごとに増加
  • 例:Linear 10% every 10 minutes = 10分ごとに 10% ずつ増加

Canary N% for M minutes

  • N% に展開して M 分監視、問題なければ 100%
  • 例:Canary 10% for 20 minutes = 10% で 20 分監視後 100%

3. バリデーター

JSON Schema

  • 設定値の型・範囲・形式を事前検証
  • デプロイ時に自動チェック

Lambda Validator

  • カスタムロジックで複雑な検証
  • DB アクセス・API 呼び出し可能

4. 自動ロールバック

CloudWatch Alarms

  • エラー率・レイテンシ・カスタムメトリクス監視
  • 閾値超過で自動的に前バージョンに復元

アーキテクチャ

graph TD
    A["Application"]
    B["AppConfig Agent<br/>Lambda Extension / EC2 Process"]
    C["AWS AppConfig"]
    
    subgraph AppConfig_Resources["AppConfig Resources"]
        D["Application"]
        E["Environment<br/>Production / Staging / Dev"]
        F["Configuration Profile<br/>Feature Flags / Freeform"]
        G["Deployment Strategy<br/>Immediate / Linear / Canary"]
    end
    
    subgraph Validation["Validation & Monitoring"]
        H["Validator<br/>JSON Schema / Lambda"]
        I["CloudWatch Alarms<br/>Rollback Trigger"]
    end
    
    subgraph DataSource["Configuration Source"]
        J["AppConfig Hosted Config"]
        K["SSM Parameter Store"]
        L["Secrets Manager"]
        M["S3"]
    end
    
    A -->|1. Poll Config| B
    B -->|2. Cache Locally<br/>Port 2772| A
    B -->|3. Get Latest| C
    C --> D
    D --> E
    E --> F
    F --> G
    G --> H
    H -->|4. Validate| I
    I -->|5. Store| J
    I -->|6. Reference| K
    I -->|7. Reference| L
    I -->|8. Reference| M
    
    style A fill:#e6f3ff
    style AppConfig_Resources fill:#fff0e6
    style Validation fill:#ffe6e6
    style DataSource fill:#e6ffe6

コアコンポーネント

1. Application(アプリケーション)

AppConfig リソースの最上位。複数の Environment を管理します。

aws appconfig create-application \
  --name my-app \
  --description "My Application"

2. Environment(環境)

本番・ステージング・開発など環境ごとの分離。

aws appconfig create-environment \
  --application-id my-app \
  --name production \
  --description "Production environment"

3. Configuration Profile(設定プロファイル)

フィーチャーフラグ・設定データの定義。

2 つのタイプ

  • Feature Flags: On/Off とその属性
  • Freeform: JSON・YAML・テキスト自由形式

4. Deployment Strategy(デプロイ戦略)

段階的ロールアウトのルール定義。

aws appconfig create-deployment-strategy \
  --name canary-10-percent-5-minutes \
  --deployment-duration-in-minutes 5 \
  --final-bake-time-in-minutes 10 \
  --growth-factor 10.0 \
  --growth-type Exponential

フィーチャーフラグの設定

フラグ定義(AppConfig Hosted Config)

{
  "flags": {
    "new-checkout-flow": {
      "name": "New Checkout Flow",
      "description": "Enable the redesigned checkout experience"
    },
    "ai-recommendations": {
      "name": "AI Product Recommendations",
      "description": "ML-driven product suggestions",
      "attributes": {
        "model-version": {
          "description": "Model version",
          "constraints": {
            "type": "string",
            "enum": ["v1", "v2", "v3"]
          }
        },
        "max-recommendations": {
          "description": "Maximum number of recommendations",
          "constraints": {
            "type": "number",
            "minimum": 1,
            "maximum": 20
          }
        }
      }
    },
    "beta-payment-gateway": {
      "name": "Beta Payment Gateway",
      "description": "Test new payment provider"
    }
  },
  "values": {
    "new-checkout-flow": {
      "enabled": true
    },
    "ai-recommendations": {
      "enabled": true,
      "model-version": "v2",
      "max-recommendations": 5
    },
    "beta-payment-gateway": {
      "enabled": false
    }
  },
  "version": "1"
}

JSON Schema バリデーター

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "flags": {
      "type": "object",
      "patternProperties": {
        "^[a-z0-9\\-]+{{CONTENT}}quot;: {
          "type": "object",
          "properties": {
            "name": { "type": "string" },
            "description": { "type": "string" }
          },
          "required": ["name"]
        }
      }
    },
    "values": {
      "type": "object"
    }
  },
  "required": ["flags", "values"]
}

デプロイ戦略

1. Immediate(即時)

aws appconfig create-deployment-strategy \
  --name immediate \
  --deployment-duration-in-minutes 0 \
  --final-bake-time-in-minutes 0 \
  --growth-factor 100.0

用途

  • 開発・テスト環境
  • 緊急で全体に展開する必要があるとき

2. Linear(線形増加)

aws appconfig create-deployment-strategy \
  --name linear-50-percent-every-30-seconds \
  --deployment-duration-in-minutes 1 \
  --growth-factor 50.0 \
  --growth-type Linear

展開例

  • 0 秒:50%
  • 30 秒:100%

3. Canary(カナリア)

aws appconfig create-deployment-strategy \
  --name canary-10-percent-5-minutes \
  --deployment-duration-in-minutes 5 \
  --final-bake-time-in-minutes 10 \
  --growth-factor 10.0 \
  --growth-type Exponential

展開例

  • 0 分:10% に展開
  • 5 分:問題なければ 100%
  • さらに 10 分監視
項目 説明
deployment-duration-in-minutes デプロイ所要時間(段階的展開の期間)
final-bake-time-in-minutes 最終段階での監視時間
growth-factor 1 ステップでの増加率(%)
growth-type Linear / Exponential

バリデーター

JSON Schema バリデーター

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "rate-limit": {
      "type": "integer",
      "minimum": 1,
      "maximum": 10000
    },
    "timeout-ms": {
      "type": "integer",
      "minimum": 100,
      "maximum": 30000
    }
  },
  "required": ["rate-limit"]
}

Lambda バリデーター

import json

def lambda_handler(event, context):
    """
    AppConfig Validator function
    Configuration が正しいか検証
    """
    config = json.loads(event.get('configuration', '{}'))
    
    # カスタム検証ロジック
    errors = []
    
    # rate-limit は 1~10000 の範囲
    rate_limit = config.get('rate-limit')
    if not isinstance(rate_limit, int) or rate_limit < 1 or rate_limit > 10000:
        errors.append('rate-limit must be 1-10000')
    
    # timeout-ms は rate-limit より大きい必要
    timeout_ms = config.get('timeout-ms')
    if timeout_ms and timeout_ms <= rate_limit:
        errors.append('timeout-ms must be greater than rate-limit')
    
    if errors:
        return {
            'statusCode': 400,
            'body': json.dumps({'errors': errors})
        }
    
    return {
        'statusCode': 200,
        'body': json.dumps({'valid': True})
    }

主要ユースケース

1. 新機能の段階的リリース

シナリオ

  • チェックアウト流れを新しいUIに変更
  • Beta ユーザーで 1 日テスト → 10% に展開 → 50% → 100%

実装

# フラグ作成
aws appconfig create-configuration-profile \
  --application-id my-app-id \
  --name new-checkout \
  --description "New checkout flow" \
  --type FEATURE_FLAGS

# Canary デプロイ開始(10% で 5 分)
aws appconfig start-deployment \
  --application-id my-app-id \
  --environment-id prod-env-id \
  --deployment-strategy-id canary-10-percent-5-minutes \
  --configuration-profile-id new-checkout-id \
  --configuration-version 1

2. 緊急メンテナンス時の機能無効化

シナリオ

  • DB メンテナンス中、新規注文受付を停止
  • コードデプロイ待たずにフラグ OFF

実装

# フラグ OFF でデプロイ
aws appconfig start-deployment \
  --application-id my-app-id \
  --environment-id prod-env-id \
  --deployment-strategy-id immediate \
  --configuration-profile-id feature-flags-id \
  --configuration-version 2  # enabled: false

3. A/B テストのフラグ管理

シナリオ

  • アルゴリズム A vs B を比較
  • ユーザー ID ハッシュで振り分け

実装

import hashlib

def should_use_algorithm_b(user_id: str) -> bool:
    """
    ユーザー ID に基づいて Algorithm B を使うか判定
    """
    config = get_appconfig('ab-test-algorithm')
    
    if not config.get('enabled'):
        return False
    
    # user_id をハッシュして 0-100 の値を算出
    hash_value = int(hashlib.md5(user_id.encode()).hexdigest(), 16) % 100
    
    # 50% のユーザーに B を適用
    return hash_value < config.get('percentage', 50)

# 使用例
if should_use_algorithm_b(user_id):
    result = algorithm_b(data)
else:
    result = algorithm_a(data)

4. Lambda の動的設定更新

シナリオ

  • Lambda のタイムアウト値・リトライ回数を動的に変更
  • 環境変数変更・再デプロイ不要

実装(Python Lambda)

import json
import boto3

appconfig_client = boto3.client('appconfigdata')

def get_config():
    """AppConfig から最新設定を取得"""
    try:
        response = appconfig_client.start_configuration_session(
            ApplicationIdentifier='my-app',
            EnvironmentIdentifier='production',
            ConfigurationProfileIdentifier='lambda-settings',
            RequiredMinimumPollIntervalInSeconds=30
        )
        
        token = response['InitialConfigurationToken']
        
        # 設定取得(変更がある場合のみ返す)
        config_response = appconfig_client.get_latest_configuration(
            ConfigurationToken=token
        )
        
        if config_response['Configuration']:
            return json.loads(config_response['Configuration'].read())
        return {}
    except Exception as e:
        print(f"Failed to get config: {e}")
        return {}

def lambda_handler(event, context):
    config = get_config()
    
    timeout_seconds = config.get('timeout_seconds', 30)
    max_retries = config.get('max_retries', 3)
    log_level = config.get('log_level', 'INFO')
    
    # これらの値を元に処理を実行
    result = process_with_timeout(event, timeout_seconds)
    
    return {
        'statusCode': 200,
        'body': json.dumps(result)
    }

5. レート制限値の動的変更

シナリオ

  • API のレート制限を 100 RPS から 50 RPS へ動的に低下
  • 負荷状況に応じて自動調整

実装

from datetime import datetime, timedelta
import json

class RateLimiter:
    def __init__(self):
        self.config = self.get_config()
        self.requests = []
    
    def get_config(self):
        # AppConfig から設定取得
        return {
            'requests_per_second': 100,
            'window_size_seconds': 60
        }
    
    def is_allowed(self, user_id: str) -> bool:
        """Rate limit チェック"""
        config = self.get_config()  # 毎回最新設定を取得
        
        now = datetime.utcnow()
        window_start = now - timedelta(seconds=config['window_size_seconds'])
        
        # ウィンドウ外のリクエストを削除
        self.requests = [
            req_time for req_time in self.requests
            if req_time > window_start
        ]
        
        # リクエスト数チェック
        if len(self.requests) < config['requests_per_second']:
            self.requests.append(now)
            return True
        
        return False

設定・操作の具体例

CLI 例 1:アプリケーション・環境・設定プロファイル作成

# 1. Application 作成
APP_ID=$(aws appconfig create-application \
  --name my-app \
  --region ap-northeast-1 \
  --query 'Application.Id' --output text)

# 2. Environment 作成
ENV_ID=$(aws appconfig create-environment \
  --application-id $APP_ID \
  --name production \
  --region ap-northeast-1 \
  --query 'Environment.Id' --output text)

# 3. Configuration Profile(フィーチャーフラグ)作成
CONFIG_PROF_ID=$(aws appconfig create-configuration-profile \
  --application-id $APP_ID \
  --name feature-flags \
  --type FEATURE_FLAGS \
  --region ap-northeast-1 \
  --query 'ConfigurationProfile.Id' --output text)

echo "App ID: $APP_ID, Env ID: $ENV_ID, Config ID: $CONFIG_PROF_ID"

CLI 例 2:フラグ定義をアップロード

# feature-flags.json を作成
cat > feature-flags.json << 'EOF'
{
  "flags": {
    "new-checkout": {
      "name": "New Checkout Flow"
    },
    "ai-recommendations": {
      "name": "AI Recommendations"
    }
  },
  "values": {
    "new-checkout": { "enabled": true },
    "ai-recommendations": { "enabled": false }
  },
  "version": "1"
}
EOF

# Configuration Version をアップロード
VERSION_NUM=$(aws appconfig create-hosted-configuration-version \
  --application-id $APP_ID \
  --configuration-profile-id $CONFIG_PROF_ID \
  --description "Initial feature flags" \
  --content fileb://feature-flags.json \
  --content-type application/json \
  --region ap-northeast-1 \
  --query 'VersionNumber' --output text)

echo "Configuration Version: $VERSION_NUM"

CLI 例 3:Canary デプロイ開始

# Canary 戦略 ID 取得(存在しなければ作成)
STRATEGY_ID=$(aws appconfig list-deployment-strategies \
  --region ap-northeast-1 \
  --query 'Items[?contains(Name, `canary-10`)] | [0].Id' \
  --output text)

if [ "$STRATEGY_ID" == "None" ] || [ -z "$STRATEGY_ID" ]; then
  STRATEGY_ID=$(aws appconfig create-deployment-strategy \
    --name canary-10-percent-5-minutes \
    --deployment-duration-in-minutes 5 \
    --final-bake-time-in-minutes 10 \
    --growth-factor 10.0 \
    --growth-type Exponential \
    --region ap-northeast-1 \
    --query 'Id' --output text)
fi

# デプロイ開始
DEPLOYMENT_ID=$(aws appconfig start-deployment \
  --application-id $APP_ID \
  --environment-id $ENV_ID \
  --deployment-strategy-id $STRATEGY_ID \
  --configuration-profile-id $CONFIG_PROF_ID \
  --configuration-version $VERSION_NUM \
  --description "Release new checkout flow" \
  --region ap-northeast-1 \
  --query 'DeploymentNumber' --output text)

echo "Deployment started: $DEPLOYMENT_ID"

CLI 例 4:CloudWatch Alarms でロールバック設定

# CloudWatch Alarm 作成(エラー率が 5% を超えた場合)
ALARM_ARN=$(aws cloudwatch put-metric-alarm \
  --alarm-name checkout-error-rate-high \
  --alarm-description "Alert if checkout error rate > 5%" \
  --metric-name ErrorCount \
  --namespace MyApp \
  --statistic Sum \
  --period 60 \
  --threshold 5 \
  --comparison-operator GreaterThanThreshold \
  --region ap-northeast-1 \
  --query 'MetricAlarms[0].AlarmArn' --output text)

# Environment にロールバックアラーム設定
aws appconfig update-environment \
  --application-id $APP_ID \
  --environment-id $ENV_ID \
  --monitors "[{
    \"AlarmArn\": \"$ALARM_ARN\",
    \"AlarmRoleArn\": \"arn:aws:iam::123456789012:role/AppConfigRollbackRole\"
  }]" \
  --region ap-northeast-1

SDK 例(Python)

import boto3
import json
import time

appconfig = boto3.client('appconfig', region_name='ap-northeast-1')

# 1. アプリケーション作成
app = appconfig.create_application(
    Name='my-app',
    Description='My Application'
)
app_id = app['Application']['Id']

# 2. 環境作成
env = appconfig.create_environment(
    ApplicationId=app_id,
    Name='production',
    Description='Production environment'
)
env_id = env['Environment']['Id']

# 3. Configuration Profile 作成
config_prof = appconfig.create_configuration_profile(
    ApplicationId=app_id,
    Name='feature-flags',
    Type='FEATURE_FLAGS',
    Description='Feature flags configuration'
)
config_prof_id = config_prof['ConfigurationProfile']['Id']

# 4. Configuration Version アップロード
flags_config = {
    'flags': {
        'new-checkout': {'name': 'New Checkout Flow'},
        'ai-recommendations': {'name': 'AI Recommendations'}
    },
    'values': {
        'new-checkout': {'enabled': True},
        'ai-recommendations': {'enabled': False}
    },
    'version': '1'
}

version = appconfig.create_hosted_configuration_version(
    ApplicationId=app_id,
    ConfigurationProfileId=config_prof_id,
    Description='Initial feature flags',
    Content=json.dumps(flags_config),
    ContentType='application/json'
)
version_num = version['VersionNumber']

# 5. Canary デプロイ開始
strategies = appconfig.list_deployment_strategies()
canary_strategy = [s for s in strategies['Items'] if 'canary' in s['Name']]
strategy_id = canary_strategy[0]['Id'] if canary_strategy else None

if strategy_id:
    deployment = appconfig.start_deployment(
        ApplicationId=app_id,
        EnvironmentId=env_id,
        DeploymentStrategyId=strategy_id,
        ConfigurationProfileId=config_prof_id,
        ConfigurationVersion=str(version_num),
        Description='Release new checkout flow'
    )
    print(f"Deployment started: {deployment['DeploymentNumber']}")

# 6. デプロイ状態確認
time.sleep(5)
deploy_status = appconfig.get_deployment(
    ApplicationId=app_id,
    EnvironmentId=env_id,
    DeploymentNumber=deployment['DeploymentNumber']
)
print(f"Status: {deploy_status['DeploymentStatus']}")

IaC 例(CloudFormation)

AWSTemplateFormatVersion: '2010-09-09'
Description: 'AWS AppConfig Setup'

Resources:
  MyApplication:
    Type: AWS::AppConfig::Application
    Properties:
      Name: my-app
      Description: My Application

  ProductionEnvironment:
    Type: AWS::AppConfig::Environment
    Properties:
      ApplicationId: !Ref MyApplication
      Name: production
      Description: Production environment

  FeatureFlagsProfile:
    Type: AWS::AppConfig::ConfigurationProfile
    Properties:
      ApplicationId: !Ref MyApplication
      Name: feature-flags
      Type: FEATURE_FLAGS
      Description: Feature flags configuration

  FeatureFlagsVersion:
    Type: AWS::AppConfig::HostedConfigurationVersion
    Properties:
      ApplicationId: !Ref MyApplication
      ConfigurationProfileId: !Ref FeatureFlagsProfile
      Description: Initial feature flags
      Content: |
        {
          "flags": {
            "new-checkout": {
              "name": "New Checkout Flow"
            }
          },
          "values": {
            "new-checkout": {
              "enabled": true
            }
          }
        }
      ContentType: application/json

  CanaryDeploymentStrategy:
    Type: AWS::AppConfig::DeploymentStrategy
    Properties:
      Name: canary-10-percent-5-minutes
      Description: Canary deployment - 10% for 5 minutes
      DeploymentDurationInMinutes: 5
      FinalBakeTimeInMinutes: 10
      GrowthFactor: 10.0
      GrowthType: Exponential

  MyDeployment:
    Type: AWS::AppConfig::Deployment
    Properties:
      ApplicationId: !Ref MyApplication
      EnvironmentId: !Ref ProductionEnvironment
      ConfigurationProfileId: !Ref FeatureFlagsProfile
      DeploymentStrategyId: !Ref CanaryDeploymentStrategy
      ConfigurationVersion: !Ref FeatureFlagsVersion
      Description: Deploy feature flags

IaC 例(Terraform)

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

resource "aws_appconfig_app" "example" {
  name            = "my-app"
  description     = "My Application"
}

resource "aws_appconfig_environment" "production" {
  application_id = aws_appconfig_app.example.id
  name           = "production"
  description    = "Production environment"
  state          = "Active"
}

resource "aws_appconfig_configuration_profile" "feature_flags" {
  application_id = aws_appconfig_app.example.id
  name           = "feature-flags"
  description    = "Feature flags configuration"
  type           = "FEATURE_FLAGS"
  
  validator {
    content = jsonencode({
      "$schema" = "http://json-schema.org/draft-07/schema#"
      type      = "object"
    })
    type = "JSON_SCHEMA"
  }
}

resource "aws_appconfig_hosted_configuration_version" "flags" {
  application_id           = aws_appconfig_app.example.id
  configuration_profile_id = aws_appconfig_configuration_profile.feature_flags.configuration_profile_id
  description              = "Initial feature flags"
  content_type             = "application/json"
  content = jsonencode({
    flags = {
      "new-checkout" = {
        name = "New Checkout Flow"
      }
    }
    values = {
      "new-checkout" = {
        enabled = true
      }
    }
  })
}

resource "aws_appconfig_deployment_strategy" "canary" {
  name                            = "canary-10-percent-5-minutes"
  description                     = "Canary deployment"
  deployment_duration_in_minutes  = 5
  final_bake_time_in_minutes      = 10
  growth_factor                   = 10.0
  growth_type                     = "Exponential"
}

resource "aws_appconfig_deployment" "example" {
  application_id               = aws_appconfig_app.example.id
  environment_id               = aws_appconfig_environment.production.environment_id
  configuration_profile_id     = aws_appconfig_configuration_profile.feature_flags.configuration_profile_id
  deployment_strategy_id       = aws_appconfig_deployment_strategy.canary.id
  configuration_version        = aws_appconfig_hosted_configuration_version.flags.version_number
  description                  = "Deploy feature flags"
}

類似サービス比較表

観点 AppConfig LaunchDarkly Unleash CloudWatch Evidently Split.io
管理方式 AWS ネイティブ SaaS / エンタープライズ OSS / SaaS AWS 統合 SaaS
段階的ロールアウト Canary / Linear Advanced targeting 機能豊富 A/B テスト最適化 機能豊富
自動ロールバック CloudWatch Alarms 手動 手動 自動 手動
オフライン対応 AppConfig Agent SDK キャッシュ 限定 なし 限定
複数環境対応 複数環境 セグメンテーション ユーザー戦略 なし セグメンテーション
学習曲線 低(AWS の知識で十分)
料金 低(API 呼び出し単位) $75/月~ OSS は無料 従量課金 $500/月~
推奨用途 AWS 環境・シンプルなフラグ エンタープライズ・複雑ターゲティング OSS 環境・完全管理 A/B テスト・実験 モバイルアプリ・複雑ターゲティング

ベストプラクティス

チェックリスト(優先順)

✅ 推奨事項

  • [ ] フラグ名を明確に定義 → kebab-case で統一、ドキュメント記載
  • [ ] Canary / Linear 戦略で段階的展開 → 本番環境では Immediate 避ける
  • [ ] CloudWatch Alarms で自動ロールバック設定 → エラー率・レイテンシ監視
  • [ ] JSON Schema バリデーター設定 → 設定ミス事前防止
  • [ ] AppConfig Agent でキャッシング → 高頻度呼び出しのコスト最適化
  • [ ] フラグ ON/OFF の監査ログ → CloudTrail で追跡
  • [ ] 複数環境で同じフラグ定義 → 本番・ステージング・開発を統一
  • [ ] フラグの定期的なクリーンアップ → 使われなくなったフラグを削除
  • [ ] 段階的リリース前のテスト → ステージングで Canary デプロイをシミュレート
  • [ ] ドキュメント化 → フラグの目的・有効期限・削除予定日を記載

❌ アンチパターン

アンチパターン 問題 代替
本番環境で Immediate デプロイ ダウンタイムリスク、問題検知が遅い Canary / Linear 使用
CloudWatch Alarms なしでデプロイ 異常検知に数分かかり、影響範囲拡大 アラーム設定で自動ロールバック
フラグ定義の属性を変更し続ける スキーマの型一貫性失失失 新しい属性フラグを作成
AppConfig Agent キャッシング未使用 API 呼び出し多発、コスト増加 Lambda Extension / EC2 Agent 使用
ドキュメントなしでフラグ展開 フラグの目的・有効期限不明確 フラグごとにドキュメント作成
複数チームで別フラグ定義 同じ機能なのに異なるフラグ名 統一フラグ定義・命名規約

トラブルシューティング

症状 原因 解決策
「設定が反映されない」 AppConfig Agent キャッシュが古い、ポーリング間隔が長い Agent 再起動、ポーリング間隔短縮
「バリデーションエラー」 JSON スキーマが厳しすぎ、Lambda Validator エラー スキーマ条件・Lambda ロジック見直し
「デプロイが中断」 Validation 失敗、Rollback トリガー(Alarm 発火) ログ確認、設定値修正、アラーム再設定
「高いコスト」 API 呼び出し過多、AppConfig Agent 未使用 Agent キャッシング導入、ポーリング間隔調整
「フラグ ON/OFF が切り替わらない」 Application / Environment / Profile ID 誤り、バージョン不正 ID・バージョン番号確認
「AppConfig Agent が起動しない」 IAM 権限不足、ネットワーク不通 IAM ロール権限確認、VPC 設定確認
「複数バージョン間での競合」 同時デプロイで古いバージョンが優先 デプロイ順序調整、ロック機構導入

2025-2026 最新動向

2026年3月:Enhanced Targeting リリース

新機能

  • ユーザーセグメンテーション(属性ベース)
  • 複数条件での AND / OR ロジック
  • デプロイ対象ユーザーの動的フィルタリング
{
  "flags": {
    "premium-feature": {
      "name": "Premium Feature",
      "targeting": {
        "rules": [
          {
            "condition": "user_tier == 'premium'",
            "enabled": true
          },
          {
            "condition": "region in ['jp', 'sg']",
            "enabled": false
          }
        ]
      }
    }
  }
}

2025年4月:CloudWatch Evidence 統合

新機能

  • デプロイ結果の自動分析
  • A/B テスト結果の推奨値提示
  • 統計的有意性の自動判定

2025年5月:AppConfig Agent Lambda Extension 拡張

改善点

  • オフライン対応强化
  • より効率的なキャッシング戦略
  • ローカル開発モードの充実

Lambda Layer ARN(2025年最新)

  • arn:aws:lambda:ap-northeast-1:027255383542:layer:AWS-AppConfig-Extension:latest

学習リソース・参考文献

公式ドキュメント

  1. AWS AppConfig User Guide

  2. AWS AppConfig API Reference

  3. AWS AppConfig Pricing

  4. CloudWatch Evidence Documentation

AWS ブログ・サンプルコード

  1. AWS Systems Manager Blog - AppConfig Articles

    • フィーチャーフラグ・ベストプラクティス記事
  2. AWS Samples - AppConfig Examples

    • GitHub のサンプルコード集

関連プロダクト

  1. AWS Amplify Feature Flags(AppConfig 統合)

  2. AWS Systems Manager Parameter Store(設定管理)

OSS / サードパーティリソース

  1. LaunchDarkly Documentation

  2. Unleash - Open Source Feature Toggle Service


実装例

例 1:Python アプリケーションでのフラグ利用

import json
import boto3
from functools import lru_cache
from datetime import datetime, timedelta

class AppConfigClient:
    def __init__(self, app_name: str, env_name: str, config_name: str):
        self.appconfig = boto3.client('appconfigdata', region_name='ap-northeast-1')
        self.app_name = app_name
        self.env_name = env_name
        self.config_name = config_name
        self.token = None
        self.cache_time = None
        self.cache_ttl = timedelta(minutes=5)
        
    def get_config(self) -> dict:
        """Configuration を取得(キャッシュ活用)"""
        now = datetime.utcnow()
        
        # キャッシュ有効期限チェック
        if self.cache_time and (now - self.cache_time) < self.cache_ttl:
            return self.cached_config
        
        try:
            # 初回または キャッシュ期限切れ時に取得
            if not self.token:
                session = self.appconfig.start_configuration_session(
                    ApplicationIdentifier=self.app_name,
                    EnvironmentIdentifier=self.env_name,
                    ConfigurationProfileIdentifier=self.config_name,
                    RequiredMinimumPollIntervalInSeconds=60
                )
                self.token = session['InitialConfigurationToken']
            
            response = self.appconfig.get_latest_configuration(
                ConfigurationToken=self.token
            )
            
            self.token = response['NextConfigurationToken']
            
            if response['Configuration']:
                config_data = json.loads(response['Configuration'].read())
                self.cached_config = config_data
                self.cache_time = now
                return config_data
            
            return self.cached_config if hasattr(self, 'cached_config') else {}
        except Exception as e:
            print(f"Error fetching config: {e}")
            return self.cached_config if hasattr(self, 'cached_config') else {}
    
    def is_flag_enabled(self, flag_name: str) -> bool:
        """フラグが有効か判定"""
        config = self.get_config()
        flags = config.get('values', {})
        flag = flags.get(flag_name, {})
        return flag.get('enabled', False)
    
    def get_flag_value(self, flag_name: str, key: str, default=None):
        """フラグの属性値を取得"""
        config = self.get_config()
        flags = config.get('values', {})
        flag = flags.get(flag_name, {})
        return flag.get(key, default)

# 使用例
def checkout_flow(user_id: str):
    config = AppConfigClient('my-app', 'production', 'feature-flags')
    
    if config.is_flag_enabled('new-checkout-flow'):
        return new_checkout_ui()
    else:
        return legacy_checkout_ui()

def ai_recommendations(user_id: str):
    config = AppConfigClient('my-app', 'production', 'feature-flags')
    
    if config.is_flag_enabled('ai-recommendations'):
        model_version = config.get_flag_value('ai-recommendations', 'model-version', 'v1')
        max_recs = config.get_flag_value('ai-recommendations', 'max-recommendations', 5)
        
        return get_ai_recommendations(user_id, model_version, max_recs)
    else:
        return get_legacy_recommendations(user_id)

例 2:Node.js / Lambda での動的レート制限

const AWS = require('aws-sdk');
const appconfig = new AWS.AppConfigData({ region: 'ap-northeast-1' });

let configCache = null;
let cacheExpireTime = 0;

async function getConfig() {
  const now = Date.now();
  
  // キャッシュ有効チェック(5分間有効)
  if (configCache && cacheExpireTime > now) {
    return configCache;
  }
  
  try {
    const sessionResponse = await appconfig.startConfigurationSession({
      ApplicationIdentifier: 'my-app',
      EnvironmentIdentifier: 'production',
      ConfigurationProfileIdentifier: 'rate-limits',
      RequiredMinimumPollIntervalInSeconds: 60
    }).promise();
    
    const token = sessionResponse.InitialConfigurationToken;
    
    const configResponse = await appconfig.getLatestConfiguration({
      ConfigurationToken: token
    }).promise();
    
    if (configResponse.Configuration) {
      configCache = JSON.parse(configResponse.Configuration);
      cacheExpireTime = now + (5 * 60 * 1000); // 5分
      return configCache;
    }
    
    return configCache || {};
  } catch (error) {
    console.error('Failed to get config:', error);
    return configCache || {};
  }
}

class RateLimiter {
  constructor() {
    this.requests = new Map();
  }
  
  async isAllowed(userId) {
    const config = await getConfig();
    const rateLimitPerSecond = config.rate_limit_per_second || 100;
    
    const now = Date.now();
    const windowStart = now - 60000; // 60秒ウィンドウ
    
    if (!this.requests.has(userId)) {
      this.requests.set(userId, []);
    }
    
    const userRequests = this.requests.get(userId);
    
    // ウィンドウ外リクエストを削除
    const validRequests = userRequests.filter(time => time > windowStart);
    
    if (validRequests.length < rateLimitPerSecond) {
      validRequests.push(now);
      this.requests.set(userId, validRequests);
      return true;
    }
    
    return false;
  }
}

const limiter = new RateLimiter();

exports.handler = async (event) => {
  const userId = event.requestContext.authorizer.principalId;
  
  if (!await limiter.isAllowed(userId)) {
    return {
      statusCode: 429,
      body: JSON.stringify({ error: 'Rate limit exceeded' })
    };
  }
  
  return {
    statusCode: 200,
    body: JSON.stringify({ message: 'Request processed' })
  };
};

チェックリスト

デプロイ前

  • [ ] フラグ定義を JSON で作成・検証
  • [ ] JSON Schema / Lambda バリデーター設定
  • [ ] ステージング環境で Canary デプロイ テスト
  • [ ] CloudWatch Alarms(エラー率・レイテンシ)設定
  • [ ] Rollback IAM ロール作成・権限確認
  • [ ] AppConfig Agent インストール・IAM ロール設定

デプロイ後

  • [ ] デプロイステータス確認(Pending → In Progress → Complete)
  • [ ] CloudWatch Logs で Validator エラー確認
  • [ ] メトリクス・ログを監視(自動ロールバック検知)
  • [ ] アプリケーションで フラグ有効確認
  • [ ] 段階的展開が期待通りに進行确认

運用時

  • [ ] 月 1 回以上 フラグ定義レビュー
  • [ ] 不要フラグの削除(クリーンアップ)
  • [ ] CloudTrail でフラグ ON/OFF 操作監査
  • [ ] AppConfig Agent ログ・メトリクス監視
  • [ ] フラグ有効期限の事前通知・削除計画

まとめ

AWS AppConfig は 「フィーチャーフラグ・動的設定を安全にデプロイするサービスで、Canary・Linear 段階的ロールアウト・JSON Schema / Lambda バリデーション・CloudWatch Alarms 自動ロールバックを実現するサービス」 です。

AppConfig が向いている場合

  • 新機能を段階的にリリースしたい
  • 本番環境でコードデプロイなしに設定値を変更したい
  • AWS 環境での シンプルなフィーチャーフラグ管理
  • CloudWatch と統合した自動ロールバック機能が必要

2025-2026 動向

  • Enhanced Targeting: ユーザーセグメンテーション・属性ベースフラグ
  • CloudWatch Evidence 統合: A/B テスト自動分析
  • AppConfig Agent 拡張: オフライン対応・キャッシング効率化

フラグ名を明確に定義し、Canary / Linear 戦略で段階的に展開、CloudWatch Alarms で自動ロールバック設定、定期的にフラグをクリーンアップすることで、高速で安全な本番環境での動作制御を実現してください。


最終更新:2026-04-27 バージョン:v2.0