CDKのデプロイ先アカウントはどう定義すればいいの?

2023.12.08
CDKのデプロイ先アカウントはどう定義すればいいの?
この記事をシェアする

本記事は、株式会社ギークフィードのアドベントカレンダー2023の8日目の記事となります。

はじめに

こんにちは、スカイアーチHRソリューションズのsugawaraです。

今回はCDKのデプロイ先の情報をどう定義すればいいかについて紹介します。プロジェクトによって書き方は異なると思いますが、いくつかパターンをまとめてみました。最近CDKを学び始めた誰かの参考になると幸いです。

なお前提として、CDKはTypeScriptで書いており、下記のcdkコマンドでプロジェクトを作成済みの状態でスタートとします。

$ cdk init app --language typescript

ハードコーディング

もっともシンプルな方法は、bin配下のスタックファイルにアカウント情報をハードコーディングすることです。propsのenvにハードコーディングすることで、デプロイするアカウントとリージョンを定義できます。

#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { SampleCdkStack } from '../lib/sample-cdk-stack';

const app = new cdk.App();
new SampleCdkStack(app, 'SampleCdkStack', {
  env: {
      account: 'XXXXXXXXXXXX',
      region: 'ap-northeast-1'
  }
});

個人の検証アカウントにすばやくデプロイしたい場合には有効な方法だと思います。

また、下記のように複数のenvを定義することで、複数リージョンにそれぞれスタックをデプロイすることも可能です。

#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { SampleCdkStack } from '../lib/sample-cdk-stack';

const app = new cdk.App();
const envTokyo  = { account: 'XXXXXXXXXXXX', region: 'ap-northeast-1' };
const envOsaka = { account: 'XXXXXXXXXXXX', region: 'ap-northeast-3' };

new SampleCdkStack(app, 'SampleCdkStackTokyo', { env: envTokyo });
new SampleCdkStack(app, 'SampleCdkStackOsaka', { env: envOsaka });

この場合、デプロイ時にはスタック名を指定するか、–allですべてのスタックをデプロイします。

// すべてのスタックをデプロイ
$ cdk deploy --all

// 東京リージョンのスタックのみデプロイ
$ cdk deploy SampleCdkStackTokyo

// 大阪リージョンのスタックのみデプロイ
$ cdk deploy SampleCdkStackOsaka

東京リージョンと大阪リージョンにそれぞれ異なるAWSリソースをデプロイしたいときには、このようにリージョンごとにスタックを分けるといいかもしれません。

環境変数

シェルの環境変数

実行環境の環境変数からアカウント情報を取得することもできます。まずはシェルの環境変数にアカウント情報などを設定します。

$ export CDK_DEFAULT_ACCOUNT=XXXXXXXXXXXX
$ export CDK_DEFAULT_REGION=ap-northeast-1

bin配下のファイルでは、process.envオブジェクトで環境変数を取得するようにします。そうすることで、ハードコーディングせずにデプロイ先のアカウント情報とリージョンを取得することができます。

#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { SampleCdkStack } from '../lib/sample-cdk-stack';

const app = new cdk.App();

// 環境変数からアカウントとリージョンの情報を取得
const account = process.env.CDK_DEFAULT_ACCOUNT;
const region = process.env.CDK_DEFAULT_REGION;

new SampleCdkStack(app, 'SampleCdkStack', {
  env: {
    account: account,
    region: region
  }
});

アカウント情報をコードに書かないため、セキュリティリスクは軽減されます。ただし、環境変数は実行環境に依存するため、チームでCDKを利用する場合には注意が必要です。

なお、aws configureコマンドで作成されるプロファイルのデフォルトプロファイルを使用したい場合には、下記のようなコマンドで設定可能です。

$ export CDK_DEFAULT_ACCOUNT=$(aws sts get-caller-identity --query "Account" --output text)
$ export CDK_DEFAULT_REGION=$(aws configure get region)

下記のコードは、exportコマンドでCDK_DEV_ACCOUNTを定義した場合には開発環境アカウントへ、CDK_DEFAULT_ACCOUNTを定義した場合には個人の検証アカウントへデプロイします。

#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { SampleCdkStack } from '../lib/sample-cdk-stack';

const app = new cdk.App();

const account = process.env.CDK_DEV_ACCOUNT || process.env.CDK_DEFAULT_ACCOUNT;
const region = process.env.CDK_DEV_REGION || process.env.CDK_DEFAULT_REGION;

new SampleCdkStack(app, 'SampleCdkStack', { 
  env: { 
    account: account,
    region: region 
 }
});

dotenvパッケージ

環境変数とは別に、dotenvを利用するやり方もあります。dotenvとはNode.jsのパッケージであり、プロジェクトのルートにある.envファイルから環境変数を読み込んで、process.envオブジェクトで取得することができます。これにより、環境変数を簡単に管理でき、開発やステージング、本番環境の間で異なる設定を使い分けることが可能になります。

まず下記のコマンドを実行してdotenvパッケージをインストールします。

$ npm install dotenv

次に、プロジェクトのルートに.envファイルを作成してアカウント情報やリージョンを記述します。

CDK_DEFAULT_ACCOUNT=XXXXXXXXXXXX
CDK_DEFAULT_REGION=ap-northeast-1

bin配下のファイルに下記の2行を追加します。

import * as dotenv from 'dotenv';
dotenv.config();

下記が2行追加したものコードの全体です。dotenvが読み込まれ、.envファイルの内容をprocess.envで取得します。

#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { SampleCdkStack } from '../lib/sample-cdk-stack';
// ここに追加
import * as dotenv from 'dotenv';
// ここに追加
dotenv.config();

const app = new cdk.App();

const account = process.env.CDK_DEFAULT_ACCOUNT;
const region = process.env.CDK_DEFAULT_REGION;

new SampleCdkStack(app, 'SampleCdkStack', {
  env: {
    account: account,
    region: region
  }
});

また、異なる環境(開発、ステージング、本番)をアカウントごとにデプロイするために複数の.envファイルを使い分けることも可能です。

各環境に合わせて以下のような.envファイルを用意し、それぞれの環境用のアカウント情報とリージョンを設定を記述します。

  • 開発環境用    : .env.dev
  • ステージング環境用: .env.stg
  • 本番環境用    : .env.prd
DEV_ACCOUNT=XXXXXXXXXXXX
DEV_REGION=ap-northeast-1
STG_ACCOUNT=YYYYYYYYYYYY
STG_REGION=ap-northeast-1
PRD_ACCOUNT=ZZZZZZZZZZZZ
PRD_REGION=ap-northeast-1

次に、bin配下のファイルのdotenv.configにpathを記述します。NODE_ENVはNode.jsアプリケーションの実行環境を指定するための環境変数です。

#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { SampleCdkStack } from '../lib/sample-cdk-stack';
import * as dotenv from 'dotenv';

// NODE_ENVに基づいて適切なファイルを読み込む
dotenv.config({
  path: `.env.${process.env.NODE_ENV}`
});

const app = new cdk.App();

let account = process.env.CDK_DEFAULT_ACCOUNT;
let region = process.env.CDK_DEFAULT_REGION;

// 環境に応じた設定
switch (process.env.NODE_ENV) {
  case 'prd':
    account = process.env.PRD_ACCOUNT;
    region = process.env.PRD_REGION;
    break;
  case 'stg':
    account = process.env.STG_ACCOUNT;
    region = process.env.STG_REGION;
    break;
  case 'dev':
    account = process.env.DEV_ACCOUNT;
    region = process.env.DEV_REGION;
    break;
  default:
    account = process.env.CDK_DEFAULT_ACCOUNT;
    region = process.env.CDK_DEFAULT_REGION;
}

new SampleCdkStack(app, 'SampleCdkStack', {
  env: {
    account: account,
    region: region
  }
});

デプロイしたい環境にあわせて環境変数を設定します。

// dev環境へデプロイ
$ export NODE_ENV=dev

// stg環境へデプロイ
$ export NODE_ENV=stg

// prd環境へデプロイ
$ export NODE_ENV=prd

これで環境ごとにアカウントを変更してデプロイすることができます。また、ソースコードからアカウント情報を分離できるため、セキュリティが向上します。

ただし、.envファイルはGitにはプッシュしないように.gitignoreへ記述する必要があります。もしチームでCDKを利用する場合には、.env.exampleなどを作成しておいてアカウント情報の記載ルールを統一したほうがいいでしょう。

例えば、下記のようにアカウント情報のキーとダミーの値だけ記載するなど。

SAMPLE_ACCOUNT=ACCOUNT_NUMBER
SAMPLE_REGION=ap-northeast-1

コンテキスト変数

最後はcdk.jsonを用いたコンテキスト変数からアカウント情報を取得するやり方です。

自分がCDKを学習し始めたとき(2023年2月頃)はたしかこれが推奨されていましたが、いつのまにか非推奨となっていました。AWS公式としては非推奨ではありますが、個人の検証などであれば使いやすいのでこちらも載せておきます。

まずcdk.jsonのcontextにアカウント情報を定義します。

{
  "context": {
    "account": "XXXXXXXXXXXX",
    "region": "ap-northeast-1"
..}
}

アプリ内のコンテキスト変数の値を取得するには、tryGetContext()を使用します。下記のコードでcdk deployすれば、指定のアカウントへデプロイされます。

#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { SampleCdkStack } from '../lib/sample-cdk-stack';

const app = new cdk.App();

const account = app.node.tryGetContext('account');
const region = app.node.tryGetContext('region');

new SampleCdkStack(app, "SampleCdkStack", {
  env: {
    account: account,
    region: region
  }
});

また、複数環境であってもcdk.jsonにすべて記述できます。下記のようにcontextに各環境のアカウント情報を定義します。デフォルトはdev環境を指定し、別環境にデプロイする場合にはコマンドで明示的に指定します。

{
...
    "context": {
      "target": "dev",
      "dev": {
        "account": "YOUR_DEV_ACCOUNT",
       "region": "ap-northeast-1",
      },
      "stg": {
        "account": "YOUR_STG_ACCOUNT",
       "region": "ap-northeast-1",
      },
      "prd": {
        "account": "YOUR_PRD_ACCOUNT",
       "region": "ap-northeast-1",
      },
...
}

cdk.jsonのcontext内で値を上書きするには、cdkコマンドの–contextオプション(-c)を使用します。下記はprd環境へのデプロイコマンドになります。

$ cdk deploy --context target=prd

コンテキスト変数は環境以外にも定義が可能です。もし環境の他にも複数定義している場合、–contextを重ねてコマンドにすれば実行できます。

$ cdk deploy --context XXXX=XXXX --context YYYY=YYYY

また、–allですべてのスタックに適用したり、特定のスタックのみを指定したりすることも可能です。

$ cdk deploy --context XXXX=XXXX --context YYYY=YYYY mySampleStack

ただし、上記のコマンド例からもわかる通り、cdk.jsonに色々記述するとcdkコマンドが煩雑になりやすいです。コマンドミスもなども起こり得るため、実行時には注意が必要かと思われます。

おわりに

デプロイ先のアカウント情報の定義方法として、ハードコーディング、環境変数、コンテキスト変数を見ていきました。プロジェクトによって、採用する手法はそれぞれ異なると思いますが、個人的にはdotenvの環境変数を気に入っています。まだまだCDK学習中のため、今後もCDKについての記事を書いていきたいと思います!

この記事をシェアする
著者:sugawara
元高校英語教員。2023 Japan AWS All Certifications Engineers。IaCやCI/CD、Platform Engineeringに興味あり。