開発環境のNAT Gatewayをfck-natに変えたら月額$45が$4になった話
こんにちは。サービス開発室の武田です。
開発環境のAWSコストを見直していたところ、NAT Gatewayが月額約$45も占めていることに気付きました。本番環境ならまだしも、ほとんど使っていない開発環境で毎月$45は結構大きいですね。
そこで、NAT Gatewayの代替として fck-nat をAWS CDKで導入してみました。結果として開発環境のNATコストを月額$4まで削減できました。今回はその実装方法をまとめます。
NAT Gatewayは存在するだけでお金がかかる
東京リージョン(ap-northeast-1)でのNAT Gatewayの料金は次のようになっています。
| 項目 | 料金 |
|---|---|
| 時間課金 | $0.062/時間(約$45/月) |
| データ処理 | $0.062/GB |
時間課金がそのまま固定費となります。開発環境で1つ、本番環境で2つ(冗長構成)配置していると、それだけで月額$135です。
| 環境 | NAT Gateway数 | 月額(固定費のみ) |
|---|---|---|
| 開発 | 1 | ~$45 |
| 本番 | 2 | ~$90 |
| 合計 | 3 | ~$135 |
開発環境は通信量がほとんどないにもかかわらず、本番と同じ固定費がかかります。これだとちょっともったいないですね。
そもそもなぜNAT Gatewayが必要かというと、プライベートサブネット上のリソース(ECSタスク、Lambda関数など)から外向きの通信をするためです。具体的にはECRからのイメージ取得、外部APIの呼び出し、CloudWatch Logsへのログ送信などですね。
fck-natとは
fck-natは、NAT Gatewayの代替としてEC2インスタンスで動作するNATソリューションです。Gravitonインスタンス(t4g系)に対応していて、最小構成のt4g.nanoを使うとかなり安く運用できます。
公式の説明によると、t4g.nanoでも最大5Gbpsのバーストトラフィックに対応するとのこと。開発環境の通信量であれば十分でしょう。
コストを比較するとこうなります。
| 方式 | インスタンス | 月額 |
|---|---|---|
| マネージドNAT Gateway | - | ~$45 |
| fck-nat | t4g.nano | ~$4 |
| fck-nat | t4g.micro | ~$6 |
10倍以上の差ですね。しかもcdk-fck-natというCDK向けのパッケージが用意されているので、導入もそんなに難しくありません。Auto Scaling Groupでインスタンスを管理してくれるため、障害時にも自動的に再作成されます。
CDKでの実装
パッケージのインストール
npm install cdk-fck-nat
環境別にNAT方式を切り替える
開発環境ではfck-nat、本番環境ではマネージドNAT Gatewayを使い分けるのがよさそうです。実際に書いてみたコードがこちらです。
import * as cdk from 'aws-cdk-lib'
import * as ec2 from 'aws-cdk-lib/aws-ec2'
import { FckNatInstanceProvider } from 'cdk-fck-nat'
import type { Construct } from 'constructs'
export interface NetworkStackProps extends cdk.StackProps {
environment: string
}
export class NetworkStack extends cdk.Stack {
public readonly vpc: ec2.Vpc
constructor(scope: Construct, id: string, props: NetworkStackProps) {
super(scope, id, props)
// dev環境: fck-nat(t4g.nano)でコスト削減($45→$4/月)
// prod環境: マネージドNAT Gateway(高可用性)
const natGatewayProvider =
props.environment === 'dev'
? new FckNatInstanceProvider({
instanceType: ec2.InstanceType.of(
ec2.InstanceClass.T4G,
ec2.InstanceSize.NANO
),
})
: undefined
this.vpc = new ec2.Vpc(this, 'Vpc', {
maxAzs: 2,
natGateways: props.environment === 'prod' ? 2 : 1,
// dev環境のみfck-natを使用
...(natGatewayProvider && { natGatewayProvider }),
subnetConfiguration: [
{
cidrMask: 24,
name: 'Public',
subnetType: ec2.SubnetType.PUBLIC,
},
{
cidrMask: 24,
name: 'Private',
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
},
],
})
// fck-natのセキュリティグループ設定
// VPC内からの全トラフィックを許可(NATとして動作するために必要)
if (natGatewayProvider instanceof FckNatInstanceProvider) {
natGatewayProvider.securityGroup.addIngressRule(
ec2.Peer.ipv4(this.vpc.vpcCidrBlock),
ec2.Port.allTraffic()
)
}
}
}
FckNatInstanceProviderはCDKのNatProviderインタフェースを実装しているので、VPCのnatGatewayProviderにそのまま渡せます。natGatewayProviderを指定しなければ通常のマネージドNAT Gatewayが使われます。そこで条件付きスプレッド(...(natGatewayProvider && { natGatewayProvider }))を使い、環境ごとに切り替えています。
ハマりやすいポイントは最後のセキュリティグループ設定です。fck-natはEC2インスタンスで動作するため、VPC内からのトラフィックを受け付けるルールを明示的に追加する必要があります。マネージドNAT Gatewayではここの設定は不要(AWSが裏でやってくれる)ですが、fck-natでは自前で設定しないとパケットがとおりません。
なお、instanceofでチェックすることで、本番環境(fck-natを使わない環境)ではこの処理がスキップされるようになっています。
デプロイ
コンテキスト値で環境を切り替えてデプロイします。
# 開発環境(fck-natが使われる)
npx cdk deploy --context environment=dev
# 本番環境(マネージドNAT Gatewayが使われる)
npx cdk deploy --context environment=prod
導入後のコスト
実際に置き換えてみた結果がこちらです。
| 環境 | 変更前 | 変更後 | 削減額 |
|---|---|---|---|
| 開発 | NAT Gateway $45/月 | fck-nat(t4g.nano) $4/月 | $41/月 |
| 本番 | NAT Gateway x2 $90/月 | 変更なし $90/月 | $0 |
年間で約$492の削減です。複数の開発環境(feature環境やステージング)があればさらに大きなインパクトが出ます。
どんな環境に向いているか
fck-natは何でもかんでも置き換えればよいというものではありません。今回の検証を踏まえて、向き不向きを整理してみます。
向いているのは、開発・ステージング環境のようにコスト最適化が重要で、多少のダウンタイムが許容できるケースです。t4g.nanoのバースト帯域(最大5Gbps)で十分な通信量であり、単一AZ構成で問題ない開発環境ならばっちりはまります。
逆に本番環境では向いていないと言えます。インスタンス障害時にAuto Scaling Groupによる復旧で数分のダウンタイムが発生します。NAT Gatewayは最大100Gbpsのスループットに対応しているため、高スループットが必要な場面でもマネージド版が無難です。コンプライアンス要件でマネージドサービスの使用が必須の場合も同様ですね。
そもそもNATがいらないケースもある
ちなみに、アーキテクチャによってはNAT自体を廃止できる場合もあります。たとえば次のようなケースです。
- ECSタスクをパブリックサブネットに配置している
- 外部通信がVPC Endpointで代替できる(S3、ECR、STS、CloudWatch Logsなど)
- Lambda関数をVPC外で動作させている
VPC Endpointの追加コストとNATのコストを比較し、最適な構成を選ぶとよいでしょう。
まとめ
cdk-fck-natを使えば、CDKコードのちょっとした変更だけで開発環境のNATコストを削減できました。コンテキスト値で環境を切り替える形にしておくと、開発と本番で構成の差分を一元管理できて運用も楽です。
開発環境のAWSコストに悩んでいる方は、まずNAT Gatewayの置き換えから試してみてはいかがでしょうか。





