こんにちは。アスクルの荒木(@news_it_enj)です。
先日投稿したVPCエンドポイントを活用したコスト削減 完全版 - 前編の後編になります。
EC2 その他 料金
前編の最後をおさらいです。
ログ出力構成はCloudWatch Logsを使用せず、コンテナのサイドカーとしてFireLens(Fluent Bit)を使い、Firehoseを経由して S3/New Relic に出力するようになりました。
そして料金はCloudWatchが減りましたが、EC2 その他
が増えました。
EC2 その他
の料金の内訳は次のようにNAT Gatewayの処理データ料金が高いことがわかりました。
ちなみに内訳の確認方法はこちらになります。
(コスト削減芸人への第一歩)
NAT Gatewayの処理データ料金が増加した原因
Firehoseのエンドポイントへの送信は、インターネットへのアウトバウンド通信となります。
そしてログ出力量が多いため、インターネットへのアウトバウンド通信量も多くなり、NAT Gatewayの処理データ料金が増加しました。
公式ドキュメントにはアウトバウンド通信になる旨のような記載が見当たりませんでしたが、次の記事がとても参考になりました。
NAT Gatewayの処理データ料金の増加対策への道のり
直近でAWS SAPの勉強している中で解いた、とある模擬試験で同じような問題に遭遇しており、これはVPCエンドポイントを作成すればどうにかなると考えていました。
また、他社の事例でまさに似たような構成に対するドンピシャな解決方法(VPCエンドポイント作成)を発見したので、さらに確度が高まりました。
VPCエンドポイント作成
アスクルではTerraformを使っているため、次のようなコードでVPCエンドポイントを作成しました。
data "aws_vpc_endpoint_service" "kinesis_firehose" { service = "kinesis-firehose" service_type = "Interface" } resource "aws_vpc_endpoint" "kinesis_firehose" { vpc_id = aws_vpc.this.id service_name = data.aws_vpc_endpoint_service.kinesis_firehose.service_name vpc_endpoint_type = "Interface" # private_dns_enabledがtrueのインターフェイス型VPCエンドポイントは1サービスに付き1つしか作成できない # https://aws.amazon.com/jp/premiumsupport/knowledge-center/vpc-interface-endpoint-domain-conflict/ private_dns_enabled = true # 1つのVPCエンドポイントに紐付けられるVPCサブネットは、1az毎に1つのみ subnet_ids = [ aws_subnet.prod_private[0].id, aws_subnet.prod_private[1].id, aws_subnet.prod_private[2].id, ] security_group_ids = [aws_security_group.vpc_endpoint.id] tags = merge( { Name = "${local.account_name}-vpce-kinesis-firehose" }, local.tags ) } resource "aws_security_group" "vpc_endpoint" { name_prefix = "${local.account_name}-vpce-sg" description = "Security Group for VPC Endpoint" vpc_id = aws_vpc.this.id egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } tags = merge( { "Name" = "${local.account_name}-vpce-sg" }, local.tags, ) } resource "aws_security_group_rule" "vpce_ingress_from_private_subnets" { security_group_id = aws_security_group.vpc_endpoint.id type = "ingress" protocol = "tcp" from_port = 443 to_port = 443 cidr_blocks = concat( local.prod_private_subnets, ) description = "All HTTPS from private subnets for private subnets" }
セキュリティグループのインバウンドルールはコンテナが配置されるプライベートサブネットからの443ポートを許可するのみになります。
(この設定が合っているか不安でしたが、後述の疎通確認や実際に動作していることを確認できたので、これで合っていました)
VPCエンドポイント疎通確認
踏み台からFirehoseエンドポイントへのdigコマンドを実行し、VPCエンドポイントのプライベートIPアドレスが返って来れば疎通OKです。
(踏み台はVPCエンドポイントにルーティング可能なサブネットに配置されている前提)
$ dig +short firehose.ap-northeast-1.amazonaws.com. 10.144.32.7 10.144.34.20 10.144.33.43
VPCエンドポイント作成後のコスト
ちなみにVPCエンドポイントを作成すると、作成した分のコストが発生します。
NAT Gatewayの処理データ量が少ない状態でVPCエンドポイントを作成すると逆にコストが増えるので注意です。
そのあたりの分岐点としては、NAT Gatewayの処理データ量が1ヶ月あたり約800GBがポイントになり、それを超えるとVPCエンドポイントを使ったほうがお安くなります。
詳細はこちらの記事がとても参考になります。
まとめ
おまけ
ログ出力では、Firehoseを使用していますが、ログ量が多かったためにスロットリングが発生していました。
(スロットリングが発生すると、対象のログが連携先(S3/New Relic)に出力されない)
FireLensのログにも上限エラーが出力されていたので、スロットリングに気づけました。
[error] [output:kinesis_firehose:kinesis_firehose.2] Thoughput limits may have been exceeded, example-name [error] [output:kinesis_firehose:kinesis_firehose.2] PutRecordBatch request returned with no records successfully recieved, example-name [error] [output:kinesis_firehose:kinesis_firehose.2] Failed to send log records [error] [output:kinesis_firehose:kinesis_firehose.2] Failed to send records
こちらに関しては、サービス上限緩和申請からDelivery Stream Throughput (MiB/Sec)
の申請をすることで、スロットリングの対応ができました。
これにてハッピーエンド
〜完〜