AWS CDKを使えばNAT Instanceの設定が一瞬で完了するよという話
はじめに
AWS CDK、最近触り始めたのですが超便利です!
普段Cloudformationで実装している人はわかると思うのですが、awsのドキュメントとにらめっこしながら必要な設定項目を一つ一つ確認しながら実装していくのは非常に時間がかかります。
CDKを使えばコード補完の恩恵を受けつつ、Cloudformationよりも抽象化された最低限の設定で必要なリソースを作成することができます。
今回は、CDKの便利さを伝える好例としてNAT Instanceの設定について説明します。
NAT Instanceとは?NAT Gatewayとの違い
NAT Gatewayとは、VPC内のプライベートサブネットからインターネットに接続するためのサービスです。
AWSが提供するNAT Gatewayはそこらへんをうまくやってくれるマネージドサービス(適当)で、こちら側でサーバー管理などする必要がない代わりにそれなりに月額料金がかかります。個人開発でAWSのインフラ周りを使用するとき、お金がかかるのはだいたいDBかNAT Gatewayになってくるんじゃないでしょうか。
2022年9月18日時点で、サービスを利用する場合は実際に通信を行わなくても30日間で約45USDかかります。[1](0.062USD * 24 * 30 = 44.64USD)
対してNAT Instanceは、自分でEC2インスタンスを立ててNATゲートウェイとして機能するための設定をすべて自分で行います。管理する手間はかかりますが、NAT Gatewayと比較して安く済みます(※シチュエーションによってそうではない場合があるかもしれません。実際に使用する際はご自身でコストシミュレーションすることをおすすめします)。
2022年9月18日時点で、t3.nano2台であれば固定費で月額15USDもかからずに利用することができます。ケチって1台にしてしまえばさらにその半額です。[1:1]
作成するリソース
今回作成するのはざっくり以下のリソース
- VPC
-
インターネットゲートウェイ
-
Public Subnet
- Route Table
- 設定
- out bound: デフォルト(0.0.0.0/0)の向け先をインターネットゲートウェイにする
- 設定
- EC2インスタンス(NAT Instance)
- 設定
- NAT用のAMIを指定する
- security group
- すべてのアクセスを許可
- IAMロール
- すでに作成済みのキーペアと紐付ける
- 設定
- Route Table
-
Private Subnet
- Route Table
- out bound: デフォルト(0.0.0.0/0)の向け先をNAT Instanceにする
- Route Table
-
実装してみる
ディレクトリ構成
$ npx cdk init --language typescript
すると、以下のようなフォルダ、ファイルが自動生成されます。(ファイル名はルートのフォルダ名によって変動します)
.
├── README.md
├── bin
│ └── app.ts
├── cdk.json
├── jest.config.js
├── lib
│ └── app-stack.ts
├── package-lock.json
├── package.json
├── test
│ └── app.test.ts
└── tsconfig.json
package.json
{
"name": "cdk",
"version": "0.1.0",
"bin": {
"cdk": "bin/cdk.js"
},
"scripts": {
"build": "tsc",
"watch": "tsc -w",
"test": "jest",
"cdk": "cdk"
},
"devDependencies": {
"@types/jest": "^27.5.2",
"@types/node": "10.17.27",
"@types/prettier": "2.6.0",
"aws-cdk": "2.42.0",
"jest": "^27.5.1",
"ts-jest": "^27.1.4",
"ts-node": "^10.9.1",
"typescript": "^4.8.3"
},
"dependencies": {
"aws-cdk-lib": "2.42.0",
"constructs": "^10.0.0",
"source-map-support": "^0.5.21"
}
}
実装内容
bin配下のapp.tsに実行時の処理を記述し、lib配下のapp-stack.tsには作りたいstackの定義を書いていきます。
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { CdkStack } from '../lib/cdk-stack';
const app = new cdk.App();
const env = { region: "ap-northeast-1", account: "xxxxxxxxxxxx" }
new CdkStack(app, 'CdkStack', {
env
});
import * as cdk from 'aws-cdk-lib';
import { InstanceType, SubnetType, Vpc, NatInstanceImage, NatProvider } from 'aws-cdk-lib/aws-ec2';
import { Construct } from 'constructs';
export class CdkStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
new Vpc(this, "vpc", {
subnetConfiguration: [
{
cidrMask: 24,
name: "public",
subnetType: SubnetType.PUBLIC,
},
{
cidrMask: 24,
name: "private-with-egress",
subnetType: SubnetType.PRIVATE_WITH_EGRESS,
},
],
// お金がないので、今回は片方のAZにのみNATを配置する
natGateways: 1,
natGatewayProvider: NatProvider.instance({
instanceType: new InstanceType("t3.nano"),
machineImage: new NatInstanceImage(),
keyName: "xxxx",
}),
});
}
}
今回は費用をできるだけ抑えたいのでNAT Instance1台構成に。そこらへんのカスタマイズもCDKであれば1行追加するだけでOK。
実装が終わったら、$ npx cdk synth
します。そうすると、cdk.out配下にCloudformationのテンプレートファイルが追加されます。
準備が完了したら$ npx cdk deploy
で実際にデプロイしてみましょう!(初回デプロイ時は先に$ npx cdk bootstrap
を実行する必要があります)
$ npx cdk deploy
~~~~~~~
CdkStack: deploying...
[0%] start: Publishing xxxxxxxxxxxxx:xxxxxxxxxxxxx-ap-northeast-1
[100%] success: Published xxxxxxxxxxxxx:xxxxxxxxxxxxx-ap-northeast-1
CdkStack: creating CloudFormation changeset...
✅ CdkStack
✨ Deployment time: 215.57s
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxxx:stack/CdkStack/xxxxxx
✨ Total time: 224.48s
これですべて完了。マネジメントコンソールからCloudformationの画面を開くと無事に作成されていることを確認できます。
今回は遊びで作ったので$ npx cdk destroy
でサクッと削除しておきます。
$ npx cdk destroy
Are you sure you want to delete: CdkStack (y/n)? y
CdkStack: destroying...
✅ CdkStack: destroyed
おわりに
私はもともとインフラのコードを書くときは生Cloudformationのyamlファイルを地道に編集していたのですが、CDKと出会ったことでようやくその苦痛から開放されました😇
今回は紹介しきれませんでしたが、CDKのStackをデプロイするCodePipelineの設定もめちゃめちゃ記述量が少ないシンプルなコードで作ることができます。まじで便利です。
一方で、細かく設定したい項目があればあるほどCDKで書くのが厳しいシチュエーションも存在するので、適切なユースケースで利用しましょう(当たり前)
-
あくまで費用感のイメージを掴んでいただくためのものであり、実際に請求される料金について保証するものではありません。正確な料金を知りたい場合はAWS公式の料金計算ツール(https://calculator.aws/#/)を使用しましょう! ↩︎ ↩︎
Discussion