こんにちは
今回は ECS Fargate でVPCエンドポイントを使ってみたので、そちらのまとめとなります
■動機
これまでに Fargate は実務でもそれなりに触ってきましたが、どの構成も基本的には NatGateway を利用したもので、ECRからのイメージプルもNatGateway経由でした
そのため、VPCエンドポイントを触ったことがないことに対する不安が募ってきたので、これを機に勉強してみました
■やったこと
ECS on Fargate の構成でVPCエンドポイントを利用して、ECRイメージのプル + 起動確認をしてみる
■構成
今回はTerraformですべて作ったのですが、VPCエンドポイントの個所は下記のようになりました
##VPC Endpoint for S3
resource "aws_vpc_endpoint" "s3" {
vpc_id = aws_vpc.vpc.id
service_name = "com.amazonaws.${var.region}.s3"
vpc_endpoint_type = "Gateway"
route_table_ids = var.dmz_route_table_ids
}
##VPC Endpoint for ecr-dkr
resource "aws_vpc_endpoint" "ecr-dkr" {
vpc_id = aws_vpc.vpc.id
service_name = "com.amazonaws.${var.region}.ecr.dkr"
vpc_endpoint_type = "Interface"
private_dns_enabled = true
subnet_ids = var.dmz_subnet_ids
security_group_ids = [var.internal_sg_id]
}
##VPC Endpoint for ecr-api
resource "aws_vpc_endpoint" "ecr-api" {
vpc_id = aws_vpc.vpc.id
service_name = "com.amazonaws.${var.region}.ecr.api"
vpc_endpoint_type = "Interface"
private_dns_enabled = true
subnet_ids = var.dmz_subnet_ids
security_group_ids = [var.internal_sg_id]
}
##VPC Endpoint for logs
resource "aws_vpc_endpoint" "logs" {
vpc_id = aws_vpc.vpc.id
service_name = "com.amazonaws.${var.region}.logs"
vpc_endpoint_type = "Interface"
private_dns_enabled = true
subnet_ids = var.dmz_subnet_ids
security_group_ids = [var.internal_sg_id]
}
→ S3, ecr-dkr, ecr-api はFargate を利用する場合は必須であり、logs はFargateのログをCloudWatchLogsに転送するために必要となります
また、ecr-dkr, ecr-api , logs は後述しますがプライベートDNSを有効化しています
なお、var.internal_sg_id については、VPC のCIDR(10.0.0.0/16) が送信元IPアドレスであれば、すべての通信を許可するように設定しています
下記が構成図(ClaudeCodeで作成したのでちょっと微妙ですが、、、)となり、動作確認はブラウザ上からドメイン(example.com)へアクセスするような形となります
■動作確認
それでは、実際に動作を見てみます
まずは、問題なくコンテナが起動するかを確認します
→ 特に問題なく起動してそうですね
次にブラウザから動作確認してみます
→ こちらも問題なくECSコンテナ内のコンテンツが見えてそうです
なお、今回はブラウザ上からの確認はすべてALBを経由する構成となっており、
ECSコンテナからのレスポンスはALB宛て(直接インターネットではない)のVPC内で完結するので、NATGatewayなしでもコンテンツ画面の表示確認が可能となります
もし、コンテナを起点に外部APIの取得やDocker-hubから直接イメージをプルする場合は、ECSコンテナから外部ネットワークへ直接出る必要があるので、基本的にはNatGatewayが必要となります
この辺りが少しややこしいところではあります
■おまけ
少し話はそれますが、もし VPCエンドポイントとNATGatewayが両方とも存在する場合、ECRからイメージをプルするときはどちらが利用されるのか気になりました
結論としては、おそらくVPCエンドポイントが優先されると思うで、なぜそう思ったのか説明します
まず、ECRからイメージをプルするためには S3, ecr-dkr, ecr-api のエンドポイントが必要なるので、それぞれ確認していきます
・S3
S3は Gateway 型のエンドポイントとなり、紐づけたサブネットのルーティングテーブルに pl-XXXXXX のようなプレフィックスリストの宛先で自動的に登録されます
そのうえで、AWSのルーティングではトラフィックと一致する最も具体的なルート(最長プレフィックス一致)を利用するため、
すべてのインターネットトラフィック (0.0.0.0/0) をインターネットゲートウェイに送信するルートがある場合においても、より具体的な数値が設定されているエンドポイントのルーティングが優先されます
なので、S3 用エンドポイントが NATGatewayよりも優先されることになります
この辺りは公式ドキュメントにも記載がありますので併せてご確認ください
・ecr-dkr, ecr-api
ecr-dkr と ecr-api はインターフェース型のエンドポイントとなり、サブネットのルーティングではなく、プライベートDNSを利用したアクセスとなります
プライベートDNSについては、エンドポイントを作成するタイミングで有効化する必要があり、
有効化後は「vpce-xxxxxxxxxxxxxxxx.api.ecr.ap-northeast-1.vpce.amazonaws.com」のようなDNS名の割り当てとAWSの内部的にプライベートIPが割り振られるそうです(公式ドキュメント)
※念のためCloudShellからdigを引いてみたところ、下記ようにプライベートIPアドレスが割り当てられていました(既に削除済みです)
# dig +noall +answer vpce-xxxxxxxxxxxxxx.api.ecr.ap-northeast-1.vpce.amazonaws.com vpce-xxxxxxxxxxxxxx.api.ecr.ap-northeast-1.vpce.amazonaws.com. 60 IN A 10.0.40.253 vpce-xxxxxxxxxxxxxx.api.ecr.ap-northeast-1.vpce.amazonaws.com. 60 IN A 10.0.20.98
そのため、ECSコンテナからそれぞれのエンドポイントへアクセスする際は、プライベートIPでの名前解決となり、
すべてのインターネットトラフィック (0.0.0.0/0)はそもそも参照されないので、実質的にNATGatewayも利用されないことになると考えています
まとめるとそれぞれ下記のようなアクセス方法となり、ECRからのイメージプルであれば NATGateway は利用されないかなと思いました
S3 → 最長プレフィックス一致のルーティングにより、エンドポイント側を参照
ecr-dkr, ecr-api → プライベートIPでの名前解決となり、0.0.0.0/0 のルーティングは参照されないため NATGateway の利用はなし
■やってみて
ある程度ECSを利用した構成になれていればそこまで難しくなく、料金面でもかなりメリットがあるかなと思いました
また、VPCエンドポイントを通して、AWSではルーティングに最長プレフィックス一致を利用するなどを改めて学ぶことができたので、大きな収穫となりました
ただ、ECSからインターネットに直接出れないのは、現実的な構成では考えられないので、NATGatewayは引き続き利用することになるとも思いました
今度はもう少し大きめの構成でやってみます


