【AWS CDK】「CDKにおけるパラメータの外だし方法 ~自前TypeScript実装編~」

## はじめに
IaCを作成する時は、環境依存になるようなパラメータは外出ししてまとめて管理したいですよね？
パラメータを外出ししてまとめて管理しておくと、読み込む外出しパラメータ情報を切り替えるだけで、色々な環境をDeploy出来るので、構築コスト的にも好ましいですよね。

CDKには、パラメータを外出ししてまとめて管理する方法はいくつかあるんですが、その中から個人的に使っている以下2つをご紹介させて頂きます。
- node-configを利用する方法
- 自前TypeScriptで実装する方法

本記事では、「自前TypeScriptで実装する方法」に関してご紹介させて頂きます。

「自前TypeScriptで実装する方法」に関しては、以下のリンクの記事をご確認ください。
[node-configを利用する方法](https://qiita.com/akwayne/items/de660d83c9a443c5f7aa)

※ 本ブログに記載した内容は個人の見解であり、所属する会社、組織とは全く関係ありません。

## 自前TypeScriptでの実装方法
この方法では、パラメータ定義をTypeScriptの「object型」で定義したモジュールファイルとして作成して、CDKアプリケーションコードにインポートする実装する方法となります。
実装は以下4ステップに分かれます。
- パラメータファイルを作成する
- APPコードでパラメータファイルの読み込み準備
- Stackコードに引き渡す
- Stackコードからパラメータを受領する

それぞれのセクションに分けてご紹介させて頂きます。

### パラメータファイルを作成する
特に置く場所に制約はありませんが、管理上以下ように専用のディレクトリを作成することをお勧めします。
サンプルでは、configという名前のディレクトリを作成し、そこに配置しています。
~~~console
$ mkdir ./config
~~~~

パラメータファイルは環境毎等個別に作成することを想定しているため、今回はサンプルとして「Dev.ts」という名前で作成します。
node-configの魅力な点を取り込んでいるため、このファイル名が重要な要素となります。
環境毎等の名前にしてしまうのが、使いやすいかと思われます。
~~~typescript:Dev.ts
//共通パラメータ
export const common = {
  project: "parama-sample",
  envPrefix: "dev",
  accountId: "xxxxx"
};
//NW系パラメータ
export const nw = {
  vpcCider: "10.0.0.0/24",
  vpcMaxAZs: 2,
  vpcPublicSubnetCidrMask: 27,
  vpcPrivateSubnetCidrMask: 27,
};

//Aurora1用パラメータ
export const aurora1 = {
  clusterParam: {
    timezone: "Asia/Tokyo",
  },
  maxAurora: 4,
  minAurora: 2, 
};
~~~

上記のイメージのように目的毎に箱を作っていく形になります。
箱の中はkey:value形式であれば自由に組むことができ、Auora1の箱のClusterParamのようにネストされた構造を組むこともできます。

### APPコードでパラメータファイルの読み込み準備
ここでは、作成したパラメータファイルの読み込みを実施しています。

~~~typescript:sample-app.ts
//実行環境の環境変数読み込み
const envName = process.env.TS_ENV;
if (envName == null) {
  console.error(
    "Error: 環境変数'TS_ENV'にパラメータファイル名となる環境名を設定してください。\n \
    　例: export TS_ENV=Dev"
  );
  process.exit(1);
}

//StackコードへのnodeEnv引き渡し
const SampleStack = new SampleStack(app, "SampleStack", {
  tsEnv: envName,
});
~~~

**const envName = process.env.TS_ENV;**
process.envを用いてTS_ENVという環境変数の値を取得し、envNameに代入しています。
このenvNameはパラメータファイルを読み込む場所で利用します。

### Stackコードに引き渡す
このサンプルでは、パラメータファイルを読み込み、後段のConstructコードに引き渡しています。
~~~typescript:sample-stack.ts
export interface SampleStackProps extends cdk.StackProps {
  nodeEnv: string;
}


export class SampleStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props: cSampleStackProps) {
    super(scope, id, props);

    // パラメータファイル読み込み
    const config = require("../config/" + props.tsEnv);
    
    //NW系Contructクラス
    const nw = new Nw(this, "Nw", {
      envName: config.common.envPrefix,
      vpcCider: config.nw.vpcCider,
      vpcMaxAZs: config.nw.vpcMaxAZs,
      vpcPublicSubnetCidrMask: config.nw.vpcPublicSubnetCidrMask,
      vpcPrivateSubnetCidrMask: config.nw.vpcPrivateSubnetCidrMask,
      });

    //Aurora1用Constructクラス
    const aurora1 = new aurora1(this, "aurora1", {
      vpc: nw.myVpc,
      envName: config.common.envPrefix,
      clusterParam: config.aurora1.clusterParam,
      maxAurora: config.aurora1.maxAurora,
      minAurora: config.aurora1.minAurora,
~~~

**const config = require("../config/" + envName);**
require() を用いて、../config/とenvNameの値を組み合わせて、対応するパラメータファイルを読み込んでいます。
本サンプルの場合、../config/Devとなります。
 
**envName: config.common.envPrefix,**
configとして読み込んだパラメータファイルのobjectをたどり、データを取得しています。

## Stackコードからパラメータを受領する
ここからは、パラメータの引き渡しは関係ありません。
Stackから各Constructsのコードにパラメータは渡されているので、それを受領する部分となります。

~~~typescript:sample-constructs.ts
export interface NwProps {
  envName: string;
  vpcCider: string;
  vpcMaxAZs: number;
  vpcPublicSubnetCidrMask: number;
  vpcPrivateSubnetCidrMask: number;
}

export class Nw extends Construct {
  public myVpc: ec2.Vpc;

  constructor(scope: Construct, id: string, props: NwProps) {
    super(scope, id);

    // VPCの作成
    this.myVpc = new ec2.Vpc(this, "Vpc", {
      vpcName: `${props.envName}-Vpc`,
      ipAddresses: ec2.IpAddresses.cidr(props.vpcCider), 
      maxAzs: props.vpcMaxAZs, 
      subnetConfiguration: [
        {
          cidrMask: props.vpcPublicSubnetCidrMask, 
          name: "Public",
          subnetType: ec2.SubnetType.PUBLIC,
        },
        {
          cidrMask: props.vpcPrivateSubnetCidrMask, 
          name: "Private",
          subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
        },
      ],
    });
~~~
**export interface NwProps {**
ここでは、このConstructsのインターフェースを定義しています。
Stackコードでは、このインターフェースを満たすように引数のセットを渡してあげる必要があります。

**public myVpc: ec2.Vpc;**
StackコードのAurora1はNWからmyVpcが引き渡されています。
これを実現するためにここでpublicしています。
    
**ipAddresses: ec2.IpAddresses.cidr(props.vpcCider),**
Stackコードから渡されたvpcCiderを引き渡しています。

## 自前TypeScriptを用いたパラメータファイル外だしでの実行方法
外だししたパラメータファイルからパラメータマップを行うために、環境変数TS_ENVに環境名を設定します。
環境名はconfig/配下に作成するパラメータファイル名(Dev.ts)と同一のものを設定します。
~~~console
$ export TS_ENV=Dev
~~~~

これで、StackコードのconfigにDev.tsが渡され、Dev.tsのパラメータをCDK実行時にマップすることができます。

パラメータ外だしに関連する作業は以上になります。
ここから先は、普段のCDK deploy時と同じ作業をして頂ければ問題ありません。


## まとめ
以上が、自前TypeScriptでのパラメータファイルの外だし方法になります。
意図的にnode-configに似せているので、ポイントが違うだけで概ね一緒です。
これにより、node-configで魅力的だった部分を取り込んでいます。
ご利用されたい場合は、ご紹介させて頂いた内容を参考にして頂けると幸いです。

この方式の元ネタとなったnode-configを使ったパラメータ外だし方法は以下のリンクの記事でご紹介させて頂いてます。
[node-configを利用する方法](https://qiita.com/akwayne/items/de660d83c9a443c5f7aa)

ご興味がありましたら、こちらも併せて参照して頂けますと幸いです。

※ 本ブログに記載した内容は個人の見解であり、所属する会社、組織とは全く関係ありません。