はじめに
よくAWSを触るものです。
今回はECSでコンピューティングエンジンとしてFargateを用いて痛い目を見た話をします。
ちなみにFargateを使うことが悪いのではなく、ちゃんと動作を理解しておこうねというものです。
Fargateとは
FargateはAWSのサーバーレスコンピューティングエンジンとして知られています。
ECSやEKSでEC2の代わりに選択できるコンピューティングタイプでメンテナンスフリーであること、細かい設定などはすべてAWS側で持ってくれることが売りのものです。
ECSでEC2を使う場合、タスクのスケーリングに合わせてインスタンスのスケーリングも考えなくてはいけなかったり、インスタンスタイプやネットワーキングなど考慮する点が多いですが、Fargateを選択すると自動でインスタンスリソースを確保してよしなに動いてくれるのでとても楽です。
最近だと、Fargate Spotも発表され、より採用されやすいものになりました。
何が起きたの?
結論から言うと、費用がめちゃくちゃかかりました。
Fargateって最適な量でリソースが動いてくれるから、EC2なんかよりも安いんじゃないのと思いますが、それは時と場合です。
とあるサービスのバッチをECSスケジュールタスクで作成してのですが、それのコンピューティングエンジンとしてFargateをしていました。
「バッチなら常時起動しているわけではないのでFargateを使うという選択は間違っていないじゃん。」
👆そのとおりです。あっています。
ですが、その認識だけではいけなくて、ちゃんとFargateの動作を理解しておく必要がありました。
Fargateでの起動
ECSスケジュールタスクはCloudWatch Eventを使ってcron定義で動作します。
実際にバッチのジョブが起動する時(以下でもスケジュールタスクで起動するタスクはジョブと言います)、Fargateは必要なインスタンスリソースを確保してホストが起動します。そのホスト上でジョブが起動するわけです。
そのジョブを起動する際にタスク定義を元に起動するわけですが、その過程でECRからイメージをdocker pullします。
"イメージをdocker pullします"
ここです。今回の根本原因は。
ECRはVPC外に存在しているため、ジョブを起動するCloudWatchでプライベートサブネットを指定する場合、NAT Gateway経由でインターネットを介してECRにアクセスします。
このNAT Gatewayが高いのです。
作成したバッチは数もイメージの容量も頻度も多くあり、そのせいで頻繁に大容量イメージをECRからNAT Gateway 経由でdocker pullしていました。
例えばこれがEC2を使っていた場合、タスク定義のリビジョンが変わらない限りはインスタンスのローカルに残るイメージを使ってdocker runするので、バッチを更新しない限りはそのような問題は起こりません。
これは困った。
対策
なんとかなります。
その際にAWSが用意してくれているソリューションはこれ
AWS PrivateLink
参考:
https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/vpc-endpoints.html
※上記ドキュメントを読むと、今回のパターンは↓
Fargate 起動タイプおよびプラットフォームバージョン 1.3.0 以前を使用する Amazon ECS タスクでは、この機能を活用するために必要なのは com.amazonaws.region
.ecr.dkr Amazon ECR VPC エンドポイントおよび Amazon S3 ゲートウェイエンドポイントのみです。
PrivateLinkはAWSサービスへの直接的でプライベートなエンドポイントを作成してくれます。
この2つ
・インターフェイスエンドポイント
・ゲートウェイエンドポイント
今回のECRでPrivateLinkを用いる場合はECRのインターフェイスエンドポイント、S3のゲートウェイエンドポイントを作成します
今回でいうと
インターフェイスエンドポイント
・VPC
・プライベートサブネット
・接続先はECR
・セキュリティーグループ(プライベートサブネットの範囲で許可)
S3のゲートウェイエンドポイント
・VPC
・ルートテーブル
・接続先はECR
を設定しました。
これによってプライベートサブネット領域に存在するリソースからECRへNat Gatewayを通らずにアクセスできます。
料金もPrivateLinkのほうが格段に安いので、問題は解決です。
終わりに
最初なんでNAT Gatewayの値段が大幅にかかるのか全くわからなかったですが、Fargateの特性を考えてみれば結構当たり前な問題でした。
AWSの便利な機能を使うときほど気をつけましょう。