検証時にサクッと設定できるNAT GatewayをCDKで作ってみた
はじめに
こんにちは!
クラウド事業本部コンサルティング部のぐっさんです。
NAT Gatewayのコストが意外と嵩むことがあります。
私は個人のアカウントでつけっぱなしにしていた時に$100近くの請求が来て驚いた経験があります・・・
開発環境などでは、使うときだけサッと作って使用後もサクッと削除できると良いですよね。
コンソールから作ると、毎回ルートテーブルとの紐付けが地味に面倒だなあと思います。
そんな時に使えそうな、NAT Gateway+ルートテーブルへのルート作成が可能なCDKを作ってみました。
今回はPythonで書いていますが、TypeScriptも勉強のためにまた作ってみたいと思います。
作ったもの
使い方
パラメータ設定
cdk.jsonにパラメータを設定します。
※各IDはダミーの値です。
▼一部抜粋(「dev」環境用パラメータ)
"environments": {
"dev": { # デプロイ環境
"vpc_id": "vpc-123456789abcdefgh", # デプロイ先のVPC ID
"public_subnet_id": "subnet-123456789abcdefgh", # デプロイ先のパブリックサブネットID
"route_table_ids": [ # 紐付けを行うルートテーブルリスト
"rtb-123456789abcdefgh", # ルートテーブルID 1
"rtb-012345678abcdefgh" # ルートテーブルID 2
],
"account": "123456789123", # デプロイ先のアカウントID
"region": "ap-northeast-1" # デプロイリージョン
},
・環境名は任意に変更可能です。複数環境(アカウント)の設定を一つのプロジェクトで管理しておくことが可能です。
・NAT Gatewayは1つ作成、ルートテーブルは複数追加可能です。
・デプロイの際に、オプションで環境名を指定します。
デプロイ
プロジェクトディレクトリでデプロイ準備のコマンドを実行します。
python3 -m venv .venv # Python仮想環境作成
source .venv/bin/activate # Python仮想環境のアクティベート
pip install -r requirements.txt # ライブラリのインストール
cdkコマンドでデプロイする際には、下記のオプションをつけます。
パラメータに設定した環境名に当たる部分です。
これにより、環境に設定済みのパラメータでデプロイされます。
cdk deploy --context env=dev
結果
デプロイ前のVPC設定
デプロイ後のVPC設定
NAT Gatewayが作成され、2つのルートテーブルが紐づいているのがわかります。
app.pyの設定内容
TryGetContextメソッドを使用することで、cdkのコマンド引数にenvを指定するとcdk.jsonに記載した対応する環境の設定でパラメータが読み込まれるようにしています。
# CDKコマンド引数から環境を取得(デフォルトは'dev')
env_name = app.node.try_get_context("env") or "dev" # コマンド引数からコンテキスト値を取得
# 環境固有の設定を取得
environments = app.node.try_get_context("environments") or {} # cdk.jsonからコンテキスト値を取得
env_config = environments.get(env_name, {}) # コマンド引数の値を元にcdk.jsonの「environments」に設定された環境の各パラメータを取得する
※コンテキスト値は、CDKアプリに渡すことのできるキーと値のペアです。
CDKがコンテキスト値を探す場所について、AWSドキュメントには下記のように記載されており、
今回の環境分離に関してはcdkコマンドのオプションとプロジェクトのcdk.jsonを使用しています。
現在の AWS アカウントから自動的に。
cdk コマンドの --context オプションを通して (これらの値は常に文字列です)
プロジェクトの cdk.context.json ファイル
プロジェクトの cdk.json ファイルの context キー
~/.cdk.json ファイルの context キー
construct.node.setContext() メソッドを使用した AWS CDK アプリ内。
なお評価の優先順位に関しては、aws-cdkのREADMEに記載がありました。
アプリケーションコードに直接書くnode.setContext()
が最優先されるようですが、今回のように柔軟にパラメータを変えたい場合などはコマンドやファイルで渡す方法が良さそうです。
stack.pyの設定内容
for文を使えるため、複数のルートテーブルにも対応できます。
また、念の為add_dependencyを使用してNAT Gatewayの作成が完了したのちにルートテーブルの紐付けを行うように書きました。
# 複数のルートテーブルにNATゲートウェイを関連付け
for idx, route_table_id in enumerate(route_table_ids, start=1):
# ルートテーブルにデフォルトルートを追加
route = ec2.CfnRoute(
self,
f"NatRoute{idx}",
route_table_id=route_table_id,
destination_cidr_block="0.0.0.0/0",
nat_gateway_id=nat_gateway.ref
)
# ルートがNATゲートウェイに依存するように設定
route.add_dependency(nat_gateway)
悩んだ・改良したい点
本当はNAT Gatewayも複数作成できればと思っていましたが、for文で作成すると1つ目が作成できた段階で各ルートの紐付けが走ってしまい上手くマッピングが出来ませんでした。。
このあたり良さげな方法があるかまた調べてみようと思います。
使い終わったら
開発環境などで使用する想定のため、NAT Gatewayを使い終わったらスタックごと削除します。
ルートテーブルの紐付けも解除されます!
cdk destroy --context env=dev
以上、ちょっとした手間を省けたら幸いです。
ではまた〜!