機能フラグを手軽に管理!AWS AppConfig の CDK L2 コンストラクトを活用した機能フラグのデプロイ

帰省先での生活にも少しずつ慣れてきました。つい最近、AWS AppConfig の Private Link に関するブログを書いたばかりですが、CDK の L2 コンストラクトが利用可能になったことも見逃せないトピックとなります。

aws.amazon.com

AWS AppConfig の機能フラグを AWS CDK in TypeScript の L2 コンストラクトでプロビジョニングしてみたので、その使用感を共有します。

読者の前提条件

  • ✅ AWS AppConfig、AWS CDKを概要レベルで理解している必要があります。

Terraform で AWS AppConfig のプロビジョニングを行う際に抱えていた違和感

まず、最初にTerraformの話を少し触れておきます。私はAWS AppConfigのプロビジョニングをTerraformで記述していたのですが、機能フラグをTerraformで更新する際に、「aws_appconfig_hosted_configuration_version」のバージョンがインクリメントされない現象と、機能フラグの「content」が常に差分検出され、replaceとマークされることに違和感を感じていました。

contentの値が常に差分検出され、replaceとマークされる現象

この現象については、(2024年5月26日時点で) GitHubにIssueが上がっているものの、未だにOpenのままです。

github.com

私が AWS AppConfig の機能フラグを活用する上で満たしたい要件は以下の通りです。

  1. 機能フラグの設定内容を Git リポジトリのコミット履歴で履歴管理できる。
  2. 機能フラグの更新時に自動でバージョンをインクリメントする。
  3. 機能フラグを削除する際に、古いバージョンの影響でエラーが出ない。
  4. 手動または自動で機能フラグをロールアウトできる。
  5. AWS マネジメントコンソールを利用せずにロールアウトできる。

上記要件を満たすために AWS AppConfig L2 コンストラクトで実現できるか試しました。結論として、上記全ての要件を満たすことができました!!

AWS AppConfig L2 コンストラクトを利用した機能フラグの記述例

それでは、AWS AppConfig の L2 コンストラクトを利用した機能フラグの記述例をご紹介します。

まず、ディレクトリ構成は下記の画像のように、libディレクトリに機能フラグ本体となるJSONファイルとIaCのソースコードを配置しています。

ディレクトリ構成

AppConfig L2コンストラクトの記述は以下の通りです。とても簡潔に記述することができて素晴らしいですね!!

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { aws_appconfig as appconfig } from 'aws-cdk-lib'

export class TryAppconfigWithCdkStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // AppConfig Application
    const app = new appconfig.Application(this, 'MyApp', {
      applicationName: "MyApp"
    })

    // AppConfig Environment
    const env = new appconfig.Environment(this, 'MyEnv', {
      application: app,
      environmentName: "MyEnv"
    })

    // AppConfig Deployment Strategy
    // 即時範囲になるようfinalBakeTimeの値を調整
    const strategy = new appconfig.DeploymentStrategy(this, "MyDeploymentStrategy", {
      rolloutStrategy: appconfig.RolloutStrategy.linear({
        deploymentDuration: cdk.Duration.minutes(0),
        growthFactor: 100,
        finalBakeTime: cdk.Duration.minutes(0),
      }),
      deploymentStrategyName: "MyDeploymentStrategy"
    })

    // AppConfig HostedConfiguration
    // contentはJSONファイルを参照するよう記述
    new appconfig.HostedConfiguration(this, "MyHostedConfig", {
      application: app,
      content: appconfig.ConfigurationContent.fromFile("./lib/feature_flag.json"),
      type: appconfig.ConfigurationType.FEATURE_FLAGS,
      name: "MyHostedConfig",
      deploymentStrategy: strategy,
      deployTo: [
        env
      ],
    })
  }
}

L2 コンストラクタの注目ポイント

L2 コンストラクタの注目ポイントは、HostedConfiguration の deployTo オプションです!! このオプションを指定することで、機能フラグの値を更新した時に即座にデプロイするよう CDK を構成することができます!!

    // deployToオプションのみ抜粋した例
    new appconfig.HostedConfiguration(this, "MyHostedConfig", {
      deployTo: [
        env
      ],
    })

機能フラグ本体のJSONファイル

機能フラグは以下のシンプルなフラグのみとしました。

{
    "version": "1",
    "flags": {
        "featureA": {
          "name": "featureA"
        }
      },
      "values": {
        "featureA": {
          "enabled": true
        }
      }
}

AppConfig L2コンストラクタをプロビジョニングする

プロビジョニングすると、以下のようなリソースが作成されます。

まず、機能フラグが正しく作成され、バージョンは1になっています。

機能フラグの作成結果

次に、作成された環境に対して機能フラグがデプロイされていることを確認できました。

環境に対してのデプロイ結果の確認

機能フラグの切り替えを実践する

次に機能フラグの値を変更して、CDKでデプロイしてみます。機能フラグの値は、JSONファイルの値をfalseに変更したのみです。

{
    "version": "1",
    "flags": {
        "featureA": {
          "name": "featureA"
        }
      },
      "values": {
        "featureA": {
          "enabled": false
        }
      }
}

デプロイすると、以下のように期待した通りの動作になっています。 まず、バージョンが2にインクリメントされ、機能フラグの値がfalseになりました。

機能フラグの更新結果の確認

そして、環境に対してバージョン2の機能フラグがデプロイされています。

環境に対してのバージョン2の機能フラグのデプロイ結果

おわりに

AWS AppConfig L2 コンストラクトを活用した機能フラグの更新方法についてご紹介しました。私は AWS AppConfig の CDK については L1 をあまり触らずに L2 から入ってしまったのですが、やりたいことが簡単に実現できてよかったです。もし CDK でやりたいことが実現できない場合は、ツールを自作しようかとも思っていました。 早速、私が個人開発しているアプリケーションにも適用していきたいと思います。参考になれば幸いです。