Spring Boot 2 アプリケーションを Fargate Graviton2 で起動する

2021.11.26

AWS Fargate の Graviton2 対応が GA になりました。従来のコンピュートリソースより 20% 安く、最大 40% 高性能なリソースを利用できます。

https://aws.amazon.com/jp/about-aws/whats-new/2021/11/aws-fargate-amazon-ecs-aws-graviton2-processors/

弊社が提供する Prismatix は Spring Boot 2 アプリケーションを AWS Fargate にデプロイして提供しています。 Prismatix を従来の Fargate から Graviton2 ベースの Fargate に移行するだけで AWS 利用費を下げることができ、AWS 利用費を下げることは顧客のサービス利用費を下げることになり、顧客の満足度向上にもつながります。

ぜひとも提供したい。早速 Graviton2 で動作するために何が必要なのか試してみました。

Fargate Graviton 2 で動かすために必要だったこと

  • ベースとなる Docker Image を arm64 のイメージに変える
  • タスク定義で Graviton 2 を利用するように指定してデプロイする

この 2つだけでした。

ベースとなる Docker Image を arm64 のイメージに変える

Docker Image は動作する OS/CPU アーキテクチャに合わせて Docker Image を選択する必要があります。 x86/amd64 ベースのイメージは Graviton2 では動作しません。

arm64 ベースの Docker Image を作成するためには起点となる Docker Image を arm64 ベースにするだけです。

Prismatix の Docker Image は amazoncorret をベースに構成しています。

amazoncorret:11 => Prismatix ベースイメージ => 各マイクロサービスのイメージ という 2段階のビルドで作成しています。

amazoncorret の Docker Image は amd64/arm64 に対応しているので arm64 のベースイメージから Docker Image を作成するだけです。

普段は CircleCI で Docker Image をBuild&Pushしているのですが、実際にコマンド叩きながら理解したかったので Docker Desktop for Mac(Intel Macbook)で Docker Image を作成しました。 Docker Desktop はエミュレータを利用して、Intel Macbook でも arm64 ベースのコンテナを動作できます。

ベースイメージ

現状 Dockerfile の FROM は以下のように指定しています。

FROM amazoncorretto:11

そのままでは端末の CPU アーキテクチャ(amd64)のイメージを Pull してしまうので arm64 のイメージの hash を追加します。

FROM amazoncorretto:11@sha256:4da750ebb075e53d3bc6594d675df097918fb7e745a0b64a967d14cbfed43130

hash は DockerHub のページや後述する Buildx の imagetool コマンドで確認できます。

https://hub.docker.com/layers/amazoncorretto/library/amazoncorretto/11/images/sha256-4da750ebb075e53d3bc6594d675df097918fb7e745a0b64a967d14cbfed43130?context=explore

あとはいつもどおりに Build & Push します。

docker build -t xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/testbaseimage:arm64 .
docker push xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/testbaseimage:arm64

マイクロサービスのイメージ

マイクロサービスの Build & Push も FROM を作成したベースイメージに変えるだけです。

FROM xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/testbaseimage:arm64

あとはいつもどおりに Build & Push します。

docker build -t xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/microservice:arm64 .
docker push xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/microservice:arm64

以上で arm64 ベースのマイクロサービスの Docker Image 作成が完了しました。 ベースとなる Docker Image を arm64 ベースにしただけです。 Java は "Write once, run anywhere" なので Intel Macbook 上でビルドしたものを置いています(※性能に関わる可能性がある話は後述)

タスク定義で Graviton 2 を利用するように指定してデプロイする

デプロイに必要なことはタスク定義に以下を追記して、今回作成したイメージタグを指定するだけです。

    "runtimePlatform": {
        "cpuArchitecture": "ARM64",
        "operatingSystemFamily": "LINUX"
    },

あとは ECS サービスで新しく作ったリビジョンを指定してデプロイするだけです。

起動するか

タスクの Architecture が ARM64 であれば Graviton2 です。 起動は成功しています。

API リクエスト成功するか

わかりやすく Spring Boot Actuator の health エンドポイントにリクエストします。

curl https://example.com/health
{"status":"UP"}

エラーログあるか

エラーレベルのログ出力はなく、起動ログが今まで通り出力しているので問題なさそうです。

ちなみに違う CPU アーキテクチャのイメージを起動すると

x86 ベースのイメージを Graviton2 で起動すると以下のエラーログを吐いてコンテナが落ちます。

standard_init_linux.go:228: exec user process caused: exec format error

性能どうなった?

マイクロサービスの CPU がボトルネックとなる性能試験シナリオを従来の Fargate/Graviton2 の Fargate で実施してみました。

結果はそんなに変わりませんでした。

従来 : 536rps Graviton2 : 533rps

このあたりは調べてみると、Graviton2 で Java アプリケーションが暗号化や圧縮のライブラリでネイティブライブラリ使用する場合があるので CPU アーキテクチャ向けにビルドすることを推奨しています。

他にも Java アプリケーションを Graviton 2 で動作させる時の推奨・注意事項を AWS から提供されているのでこのあたりを調査・検証すれば結果が変わりそうです。

https://github.com/aws/aws-graviton-getting-started/blob/main/java.md

このあたりはまた検証してブログにしてみたいと思います。

マルチ CPU アーキテクチャイメージの管理

上記やり方だとイメージタグとアーキテクチャが 1:1 なので実行環境とタグをあわせないといけません。 Prismatix はシングルテナントで顧客に提供しているので運用が辛くなります。 実際にリリース・運用に持っていくなら実行環境とイメージタグを意識したくないのでマルチ CPU アーキテクチャのイメージ管理が必要です。

ECR もマルチ CPU アーキテクチャのイメージ管理をサポートしています。

https://aws.amazon.com/jp/blogs/news/introducing-multi-architecture-container-images-for-amazon-ecr/

マルチ CPU アーキテクチャの Build だったり、マニフェスト管理を簡単にするのが Buildx です。※ Experimental

https://docs.docker.jp/docker-for-mac/multi-arch.html#id5

Buildx を使ってマイクロサービスの Docker Image をマルチ CPU アーキテクチャの

docker buildx create --name mybuilder
docker buildx use mybuilder
docker buildx inspect --bootstrap

利用する amazoncorret イメージを hash なしに戻して

FROM amazoncorretto:11

ベースイメージの Build & Push

docker buildx build --platform linux/amd64,linux/arm64 -t xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/testbaseimage:buildx --push .

docker buildx imagetools inspect xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/testbaseimage:buildx

Name:      xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/testbaseimage:buildx
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest:    sha256:92200ef6a58809248c9639e44c71f27d71d90aef3915100032e6af2533e64b04

Manifests:
  Name:      xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/testbaseimage:buildx@sha256:d90e6083ee529c364232c8afb851298e9f315982b7f5b8325b50bab25fc925a6
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/amd64

  Name:      xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/testbaseimage:buildx@sha256:04f2774b06cbeb7bba5cc596f97754272c20d39780e1d4baa99792ada1e9b053
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm64

マイクロサービスの Build & Push

docker buildx build --platform linux/amd64,linux/arm64 -t xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/microservice:buildx --push .

docker buildx imagetools inspect xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/microservice:buildx

Name:      xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/microservice:buildx
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest:    sha256:dc6b9a372d6128c6ffc6abd9ce700a8b912ee15d50d5319507048a462365d9ad

Manifests:
  Name:      xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/microservice:buildx@sha256:4187b8f208a6d27962160f296b125eaaf58cc90ed688eb2ac268c03cb431bd15
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/amd64

  Name:      xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/microservice:buildx@sha256:2aad76c2b610e3bf85fbc57f070adf028ebb18c7b74da3a5c6b7a69b3ee536b1
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm64

タスク定義に作成したイメージタグを指定してデプロイします。

curl https://example.com/health
{"status":"UP"}

まとめ

  • Prismatix の Spring Boot アプリケーションも少しの変更で Fargate Graviton 2 で起動できた
    • Fargate コストを 20% カットできる
  • 性能向上はもっと調査・検証が必要
  • CircleCI でも buildx を利用してマルチ CPU アーキテクチャのビルドができるので job を少し修正することで既存の運用に乗せられそう
    • https://circleci.com/blog/building-docker-images-for-multiple-os-architectures/
  • サイドカーで動作する Datadog Agent イメージもマルチ CPU アーキテクチャに対応している
    • https://hub.docker.com/r/datadog/agent