AWSコンテナサービスメモ

この記事は ウェブクルー Advent Calendar 2022 17日目の記事です。
昨日は @wc_sangen さんの「 ScalaのバッチプログラムにZIOを導入した話 」でした。

新しいサイトをAWSで構築するにあたって、コンテナマネジメントサービスをいくつか調べたのでその時のメモです。

## サービスたち
### [AWS Fargate](https://aws.amazon.com/jp/fargate/)
コンテナ向けサーバレスコンピューティング
サーバレスでコンテナを使用できる環境を用意してくれる。ホストインスタンスのメンテを気にしなくていいので楽。
WindowsサーバのコンテナかLinuxコンテナが利用可能。オンプレをリファクタリングせずコンテナ化できる模様
公式「AWS Fargate は、AWS でコンテナを起動して実行する最も簡単な方法です。」
ECS,EKSに対応
ssh,docker execが使えないという話があったが、現在はexecできるらしい
https://aws.amazon.com/jp/blogs/news/new-using-amazon-ecs-exec-access-your-containers-fargate-ec2/
リソース×時間による従量課金制

### [AWS Lambda](https://aws.amazon.com/jp/lambda/)
サーバーレスのイベント駆動コンピューティングサービス
イベントトリガーを設定して関数を実行できる
API Gatewayと組み合わせてWeb Rest APIを実装したりも可
コンパクトなサービス・バッチの実装においてはコスパがいい可能性がある
ただし、RDB接続がある場合はRDS Proxyを利用しないとコネクションプールが難しい（不可能ではないかもしれないが調べてない）
RDS ProxyはMySQLとAuroraにしか対応していないっぽいので、それ以外のDBを使っている場合はあきらめた方がよさそう
リクエスト単位の従量課金

### [Amazon ECS](https://aws.amazon.com/jp/ecs/)
コンテナオーケストレーションサービス
FargateかEC2を使ってコンテナを管理する
デフォルトはFargate
利用できるコンテナプラットフォームはDockerのみ
docker composeも利用可能
https://aws.amazon.com/jp/blogs/news/automated-software-delivery-using-docker-compose-and-amazon-ecs/
タスク定義でバッチの実行環境が作れそう
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/scheduling_tasks.html
> Amazon ECS は Fargate によってプロビジョニングされたコンテナを使用して、スケーリング、負荷分散、コンテナ利用のためのスケジューリング管理を自動的に行い、コンテナ化されたアプリケーションの構築や運用を簡略化します。

ということらしい
雑にいうとECS+Fargateでアプリケーションデリバリーに必要なインフラ系の要件はいい感じにあれしてくれるってこと
Amazon ECS Anywhere があるらしく、オンプレとのハイブリッド環境でも使える。

### [Amazon EKS](https://aws.amazon.com/jp/eks/)
コンテナオーケストレーションサービス
FargateかEC2を使ってコンテナを管理する（ECSと同じ）
マネージドKubernetesサービス
Amazon EKS Anywhere があるらしく、オンプレとのハイブリッド環境でも使える。
Kubernetesのサービスなので他サービスに展開したり逆に他サービスから移行しやすいが、学習コストがECSより高い。
また、EKSはバージョンアップの頻度が高いらしくメンテコストも高くなると考えたほうがいいらしい。


### [AWS App Runner](https://aws.amazon.com/jp/apprunner/)
簡単かつ最速でコンテナ化されたアプリケーションをビルド・デプロイできるサービス
Fargateからコンテナを管理している
GithubかECRにプッシュしたら後は全部いい感じにあれしてくれる
コンソールで「apprunner」って入れるとサービスが出てこないので半角スペースが必須らしい
VPCもALBもCI/CDも設定不要
CustomDomain、ヘルスチェックも提供してくれる
VPCはapp runnerの内部で用意してくれる、外部のVPCへの接続も可能（VPC内にあるRDSへのアクセスとか）
これが使えるなら楽だが、いくつか課題もある

課題：
1. ネットワーク・IPアドレスでアクセス制限をできるか（社内向けツールなので）
2. サポートしているランタイムに制限があるため、開発環境次第では対応不可（2022/12現在 Python,Node.js,Java,.NET,PHP,Go,Rubyが対応）→イメージを作成してECRにpushすればできそう
3. WAFに対応していない
4. 少なくともECRからプッシュするタイプのものは複数コンテナの連携ができないっぽい（docker composeの運用ができない）
連携させたいのなら、app runnerのサービスを２つ作成するとかそんな方針になるかなというところ

デモ動画を見ると、ソースコードを用意したらサービス名・image URL・CPUとメモリ・ポート番号 を設定しただけでデプロイできるっぽい
が、docker composeやそれに類する機能が使えないのは結構きつそうで、意外と学習コストが高くなるかもという印象

## glossary
一瞬「あれ…そもそもこれって単語の意味あってるのか？」ってなった言葉たちのメモです  

- コンピューティングとは
https://aws.amazon.com/jp/what-is/compute/
ざっくりいうとプログラムの実行に必要なリソースオブジェクト、あるいはそれを提供するサービス（クラウドコンピューティングとも）のこと

- Amazon EC2 インスタンスとは
AWSコンピューティングサービスが提供する、物理コンピュータと同じ機能を提供する仮想マシン

## 蛇足(app runnerにデプロイしてみた）
ECRにプッシュする方法でApp Runnerからサービスをデプロイできるか実際にやってみた
プッシュしたdocker imageは弊社のデファクトスタンダードになっている[playframework](https://www.playframework.com/documentation/2.8.x/NewApplication)のscala templateです

> $ sbt new playframework/play-scala-seed.g8

これでプロジェクト名 hello-play　と設定して作成したソースをimageにしただけのもの
うまくいけば helloページが表示できるはず

Dockerfile↓
```dockerfile
FROM sbtscala/scala-sbt:graalvm-ce-21.2.0-java8_1.6.2_3.1.2

EXPOSE 9000
RUN mkdir /hello-play
COPY ./ /hello-play
WORKDIR /hello-play
CMD ["sbt", "run"]
```

### 結果
デプロイに失敗
ヘルスチェックに失敗したらしい
ポート番号の設定は9000で指定しているのだが、ダメでした
ヘルスチェックのパスの指定が間違っているのか、playframeworkのビルドは有効なパスへのリクエストが来てから実行されるのでエントリポイントでhttpリクエストか何かを設定しないといけないのか
原因がわかって解消できたら追記します

とはいえ、sbt run自体はできているようなのでイメージを作ればランタイムに対応している言語以外のものでもなんとかなりそうというのはわかった

以下、サービス設定のスクショやログ
サービスロールは勝手に作成してくれたり、コンテナイメージURIはECRに上げてあるものを「参照」ボタンから簡単に選べるようになっている

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268923/62327eda-3c45-18e6-62b4-f78903e2adcf.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268923/e86545f2-b1d9-a00a-d4c7-5bf8cee3e919.png)


イベントログ
```
12-16-2022 08:28:14 PM [AppRunner] Deployment with ID : f930de77d49c4ca79c6a354707cf5fcb failed. Failure reason : Health check failed.
12-16-2022 08:28:09 PM [AppRunner] Health check failed on port '9000'. Check your configured port number. For more information, read the application logs.
12-16-2022 08:21:48 PM [AppRunner] Performing health check on port '9000'.
12-16-2022 08:21:37 PM [AppRunner] Provisioning instances and deploying image for publicly accessible service.
12-16-2022 08:21:24 PM [AppRunner] Successfully copied the image from ECR.
12-16-2022 08:17:23 PM [AppRunner] Deployment Artifact :- Repo Type: ECR; Image URL : 152256447188.dkr.ecr.ap-northeast-1.amazonaws.com/app-runner-test; Image Tag : latest
12-16-2022 08:17:22 PM [AppRunner] Deployment with ID : f930de77d49c4ca79c6a354707cf5fcb started. Triggering event : SERVICE_CREATE
```

アプリケーションログ
```
12-16-2022 08:27:53 PM [info] 
12-16-2022 08:27:53 PM [info] https://www.playframework.com/sponsors
12-16-2022 08:27:53 PM [info] Play is run entirely by the community. Please consider contributing and/or donating:
12-16-2022 08:27:53 PM [info] 
12-16-2022 08:27:53 PM [info] Version 2.8.18 running Java 1.8.0_302
12-16-2022 08:27:53 PM [info] 
12-16-2022 08:27:53 PM [info]       /_/               /____/
12-16-2022 08:27:53 PM [info]   /_/  / .___//_/ \__,_/ \__, /
12-16-2022 08:27:53 PM [info]    / /  / /_/ // // /_/ // /_/ /
12-16-2022 08:27:53 PM [info]    \ \   / __ \ / // __ `// / / /
12-16-2022 08:27:53 PM [info]   \ \     ____   / /____ _ __  __
12-16-2022 08:27:53 PM [info]   __              __
12-16-2022 08:27:53 PM [info] loading settings for project root from build.sbt ...
12-16-2022 08:27:24 PM [info] loading project definition from /hello-play/project
12-16-2022 08:27:22 PM [info] loading settings for project hello-play-build from plugins.sbt ...
12-16-2022 08:27:11 PM [info] welcome to sbt 1.7.2 (GraalVM Community Java 1.8.0_302)
12-16-2022 08:27:08 PM [info] [launcher] getting Scala 2.12.16 (for sbt)...
12-16-2022 08:26:57 PM [info] [launcher] getting org.scala-sbt sbt 1.7.2  (this may take some time)...
12-16-2022 08:23:13 PM [info] loading project definition from /hello-play/project
12-16-2022 08:23:09 PM [info] loading settings for project hello-play-build from plugins.sbt ...
12-16-2022 08:22:54 PM [info] welcome to sbt 1.7.2 (GraalVM Community Java 1.8.0_302)
12-16-2022 08:22:50 PM [info] [launcher] getting Scala 2.12.16 (for sbt)...
12-16-2022 08:22:37 PM [info] [launcher] getting org.scala-sbt sbt 1.7.2  (this may take some time)...
```

2022/12/23 追記
application.confで設定するAllowed hosts filter の設定をしていないので、[公式ドキュメント](https://www.playframework.com/documentation/2.8.x/AllowedHostsFilter#Configuring-allowed-hosts)に載ってたデフォルト値が適用されたのか？と思ってローカルで再現してみましたが出力されるログが違うのでこれではなさそう

```
[info] compiling 7 Scala sources and 1 Java source to /hello-play/target/scala-2.12/classes ...
[info] Non-compiled module 'compiler-bridge_2.12' for Scala 2.12.16. Compiling...
[info]   Compilation completed in 10.63s.
2022-12-23 00:42:46 INFO  play.api.http.EnabledFilters  Enabled Filters (see <https://www.playframework.com/documentation/latest/Filters>):

    play.filters.csrf.CSRFFilter
    play.filters.headers.SecurityHeadersFilter
    play.filters.hosts.AllowedHostsFilter
    play.filters.csrf.CSRFFilter
    play.filters.headers.SecurityHeadersFilter
    play.filters.hosts.AllowedHostsFilter
2022-12-23 00:42:46 INFO  play.api.Play  Application started (Dev) (no global state)
2022-12-23 00:42:46 WARN  p.filters.hosts.AllowedHostsFilter  Host not allowed: 172.23.160.1:9000
2022-12-23 00:42:47 WARN  p.filters.hosts.AllowedHostsFilter  Host not allowed: 172.23.160.1:9000
```

2023/7 追記
AWSのサポートへ連絡したところ、やっぱりエラーも起きてないしヘルスチェックにおいてレスポンスの時間がかかっていることが原因なのではという旨の返信があった。
sbt runって起動に時間がかかるので、試しに sbt dist で実行用ファイルを作成し、そちらを利用して起動したところうまくいった。
起動から初回のレスポンスの際に時間がかかるタイプのフレームワークはもしかしたら同様の事象が発生するかもしれません。
実は結構前にこの回避策がわかっていたのですが、記事に追記するのが遅くなりました…。

修正後のDockerfile

```dockerfile
FROM sbtscala/scala-sbt:graalvm-ce-21.2.0-java8_1.6.2_3.1.2
RUN microdnf install unzip
EXPOSE 9000
RUN mkdir /hello-play
COPY ./ /hello-play
WORKDIR /hello-play
RUN sbt "compile; dist"
RUN mkdir /app
WORKDIR /app
RUN unzip /hello-play/target/universal/hello-play-1.0-SNAPSHOT.zip -d /app
RUN rm -rf /hello-play
ENTRYPOINT ["hello-play-1.0-SNAPSHOT/bin/hello-play"]
```

## 参考
https://zenn.dev/yoshinori_satoh/articles/2021-02-13-eks-ecs-compare
https://gallery.ecr.aws/aws-containers/hello-app-runner

明日は @wc_shibawan さんの記事です