AWS入門ブログリレー2024〜AWS App Runner編〜

2024.04.12

当エントリは弊社AWS事業本部による『AWS 入門ブログリレー 2024』の19日目のエントリです。

このブログリレーの企画は、普段 AWS サービスについて最新のネタ・深い/細かいテーマを主に書き連ねてきたメンバーの手によって、 今一度初心に返って、基本的な部分を見つめ直してみよう、解説してみようというコンセプトが含まれています。

AWS をこれから学ぼう!という方にとっては文字通りの入門記事として、またすでに AWS を活用されている方にとっても AWS サービスの再発見や 2024 年のサービスアップデートのキャッチアップの場となればと考えておりますので、ぜひ最後までお付合い頂ければ幸いです。

では、さっそくいってみましょう。今回のテーマは『AWS App Runner』です。

はじめに

私は2022年にAWS App Runner(以後 App Runner)の入門記事を書いており、今回も基本的な内容は変わりません。

2022年から現在に至るまでに多くの機能が追加されていますので過去の入門記事をご覧になったことがある方は現在との差分をチェックしてみてください。

AWS App Runnerとは?

App Runnerは公式ページを見ると以下の様に記述されています。

AWS App Runner はフルマネージド型のコンテナアプリケーションサービスであり、インフラストラクチャやコンテナの経験がなくても、ウェブアプリケーションや API サービスを構築、デプロイ、実行できます。

「フルマネージド型」という表現の通り、アプリケーションコンテナひとつ用意すればあとのインフラはAWSにおまかせでWEBアプリケーションを公開できる便利なサービスです。

AWSでコンテナを扱うサービスは他にAmazon ECSAmazon EKSがありますが、App Runnerはインフラ管理をよりマネージドにし利用者はアプリケーション開発に集中できる様になっています。
実際App Runnerの内部実装はAWS管理のAmazon ECS + AWS Fargateとなっています。

ちなみに他社サービスに馴染みのある方にとってはGoogle Cloud RunやAzure App Service(Linux環境のWeb Apps for Containers)に近いものと考えるとわかりやすいかもしれません。

基本構成

App Runnerの基本構成は下図の通りです。

App Runnerでは公開するアプリケーションを「サービス」という形で登録し、サービス内部では単一イメージのコンテナアプリケーションが実行されます。
コンテナインスタンス数はリクエスト数に応じてオートスケーリングされ、各種ログはCloudWatch Logsに出力されます。

コンテナイメージは自作のDockerイメージをECRリポジトリにPushして利用するか、BitbucketまたはGitHub Repositoryと連携してソースコードからAmazon LinuxベースのDockerイメージを自動生成するかの2パターン選ぶことができます。

ソースコード連携の場合、本日時点で選択可能な言語は

  • Python 3.7 - 3.8, 3.11
  • Node.js 12, 14, 16, 18
  • Java (corretto) 8, 11
  • .NET 6
  • PHP 8.1
  • Ruby 3.1
  • Go 1.18

となります。
詳細は以下のドキュメントをご覧ください。

この他にAWS X-Rayを使った分散トレーシングやAWS WAFとの連携なども可能となっています。

利用可能リージョン・料金

本日時点でApp Runnerを利用可能なリージョンは

  • バージニア北部
  • オハイオ
  • オレゴン
  • ムンバイ
  • シンガポール
  • シドニー
  • 東京
  • フランクフルト
  • アイルランド
  • ロンドン
  • パリ

となります。
2022年より増えているものの残念ながら大阪では使えないままです。

そして利用料金はコンテナインスタンスのスペック(vCPU数とメモリサイズ)と利用時間に応じた金額が請求されます。
詳細は料金ページを参照してください。

  • AWS App Runner の料金 (※東京リージョンの利用単価は但し書きの方に記載されているので注意)

一点だけ重要な点を記載しておくと、デプロイされたコンテナの状態に応じて課金対象が変わりCPU料金はアクティブな時だけ対象となります。
メモリ料金はプロビジョニングされると状態に依らず対象となり、簡単にまとめると以下の様になります。

  • プロビジョニングされただけの状態(非アクティブ) : メモリサイズに応じた費用が課金対象
  • プロビジョニングされ、かつ、アクティブな状態 : vCPU数とメモリサイズに応じた費用が課金対象

ネットワーク構成

App Runnerはシンプルに利用する分にはネットワーク構成を意識する必要が無いのですが、現実的にはネットワーク構成を知っておくとより高度なアプリケーションを作成できます。

最初に図示したApp Runnerの基本構成にVPCは一切登場していません。 *1
この点がデータストアを考える際に大きな制約になり、初期状態ではDynamoDBの様なVPCに依存しないサービスやPublicに公開したRDS(および類似の公開データベースサービス)を使うしかありません。

(初期状態で利用可能なデータストア例)

VPC Connector (VPCコネクタ)

App RunnerからVPC内部のリソースにアクセスしたい場合は「VPC Connector」を設定する必要があります。

こちらは名前の通りApp RunnerのサービスからユーザーVPCへの接続を提供するものとなり、実装としてはユーザーが指定したサブネットにENIを生やすことであたかもApp Runnerがそのサブネットから通信するかの様に扱うことができます。

(VPC Connectorのイメージ図)

注意点としてはVPC Connectorを設定した場合、App Runnerからのほぼ全て *2のアウトバウンド通信はVPCから行われる様になるためインターネットアクセスする際はNAT Gatewayを用意するといった対応が必要となります。

VPC Endpoint (VPCインターフェイスエンドポイント)

また、App RunnerではVPC Endpointの利用もサポートされておりサービスへのアクセスをVPC内部からに限定することも可能です。

(VPC Endpoint利用イメージ)

VPC EndpointとVPC Connectorは併用可能で、例えば下図の様な構成を採ることも可能です。

(VPC ConnectorとVPC Endpointの併用例)

App Runnerでできること (2024年4月時点)

本日時点のApp Runnerで利用可能な機能を列挙していきます。
2022年から比べるとだいぶ増えました。

1. オートスケーリング

App Runnerではリクエスト数に応じたオートスケーリングを行うことが可能です。
デフォルトでは「1コンテナインスタンスあたり100同時リクエスト」をしきい値に「1 - 25 インスタンスの間でインスタンス数が変動」します。

この設定はカスタマイズ可能です。

2. 自動デプロイ

ECRに新しいイメージがPushされたときやGitHubの特定ブランチへPushされた際にアプリケーションの自動デプロイを行うことができます。

デプロイ方式はBlue/Greenデプロイとなりますが、ECSの様に再ルーティングに関する設定は無く完全にApp Runnerにおまかせする形になります。

3. カスタムドメイン

App Runnerのサービスはデフォルトで[ランダムID].[リージョン名].awsapprunner.comというドメイン名が割り当てられます。

これにユーザー保有の独自ドメインを紐づけサーバー証明書の自動発行を行うことができます。
加えてDNSにRoute 53を使っている場合はTXTレコード登録を自動で行うことも可能になっています。

4. AWS X-Ray連携

2022年4月のアップデートにより、アプリケーションにAWS Distro for OpenTelemetryを使ってOpenTelemetryを計装することでX-Rayによる分散トレーシングが可能になっています。

5. シークレット管理

2023年1月のアップデートでAWS Secrets Managerのシークレット及びSSM Parameter Storeの設定値を環境変数に展開できる様になりました。
これにより認証情報などの機密性の高いデータを環境変数としてアプリケーションから参照することが可能です。

6. AWS WAF連携

2023年2月のアップデートでAWS WAFの保護対象にApp Runnerのサービスを選べる様になりました。
これによりApp Runnerでもアクセス保護およびアクセス制限をかけることが可能になっています。

7. モノレポサポート

2023年9月のアップデートでソースコードからデプロイする際のソースディレクトリを指定可能になりました。
(従来はソースディレクトリとしてルートディレクトリが自動選択されていました)
これによりモノレポ構成のリポジトリにおいてもApp Runnerのデプロイが可能となっています。

8. IPv6サポート (パブリックエンドポイントのみ)

2023年11月のアップデートにより従来のIPv4だけでは無くIPv4とIPv6のデュアルスタックでサービスを公開できる様になっています。
なお、デュアルスタックがサポートされているのはパブリックエンドポイントのみであり、VPC Endpointを使ったプライベートアクセスは従来通りIPv4のみのサポートとなります。

App Runnerでできないこと (2024年4月時点)

App Runnerの機能も増え、できないことはだいぶ減った印象です。
App RunnerはGitHubで開発ロードマップが公開されており機能リクエストを受け付けています。

個人的には以下の機能が実装されて欲しいなと思っています。

この他にも欲しい機能があればリクエストしてみると良いでしょう。

試してみた

ここからは実際にApp Runnerを試していきます。
今回は私の検証用アカウントの東京リージョンで検証していきます。

0. 検証アプリケーション

2022年の入門記事を書いた際に作った簡単なアプリケーションをバージョンアップしました。

Flask + gunicornを使ったPythonアプリケーションでDynamoDBやRDS(for PostgreSQL)への接続確認もできる様にしています。

(ホーム画面のスクリーンショット)

1. ECRリポジトリへのイメージ登録

今年に入りAWS CloudShellでDockerの利用がサポートされたのを受け検証アプリケーションの構築を全てCloudShellでできる様にしておきました。

CloudShellを起動し、次のコマンドを入力すればGitHubからソースコード一式をダウンロードしてDockerイメージのPushまで行います。
(※各種リソースを作成できる権限のあるユーザーで行ってください)

DockerをサポートするリージョンのCloudShellで実行

# 1. ECRリポジトリ my-flask-app の作成
aws ecr create-repository --repository-name 'my-flask-app'

# 2. ソースコードのclone + Dockerイメージの作成
git clone https://github.com/stknohg/app-runner-flask-sample.git
cd ./app-runner-flask-sample/
docker build -t my-flask-app .

# 3. DockerイメージをECRにPush
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
aws ecr get-login-password | docker login --username AWS --password-stdin "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com"
docker tag my-flask-app:latest "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/my-flask-app:latest"
docker push "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/my-flask-app:latest"

コマンドを実行した結果、ECRリポジトリmy-flask-applatestタグのついたイメージが登録されていればOKです。

2. App Runnerサービスの作成

続けてCloudShell上で以下のコマンドを実行してCloudFormationスタックを作成します。

CloudShellで実行

# 4. CloudFormationテンプレート app-runner.yaml を実行しApp Runnerサービスを作成
aws cloudformation create-stack --stack-name my-flask-app --template-body file://./app-runner.yaml --capabilities CAPABILITY_NAMED_IAM

しばらく待ってスタックの作成が完了すればApp Runnerサービス「my-flask-app」が使える様になっているはずです。

あとは各種設定を自由に確認したり変えてみて動作確認してください。

今回はz7x4sd9u77.ap-northeast-1.awsapprunner.comというデフォルトURLが与えられ、アクセスするといい感じにサイトが表示されます。

補足1 : DynamoDBにアクセスしてみる

補足としてDynamoDBからのデータ取得も試していきます。

App Runnerではコンテナインスタンス自体に所定の権限を与えてやることで各種AWSリソースにアクセスすることができます。

今回はCloudFormationで既にIAMロール「my-flask-app-task-role」を作成しApp Runnerサービスと紐づけています。

このIAMロールにはDynamoDBテーブルEmployeeとSSM Parameter Storeに対するアクセス権を与えています。

my-flask-app-task-role内のポリシー定義

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "dynamodb:BatchGetItem",
                "dynamodb:GetShardIterator",
                "dynamodb:GetItem",
                "dynamodb:Scan",
                "dynamodb:Query",
                "dynamodb:GetRecords"
            ],
            "Resource": "arn:aws:dynamodb:ap-northeast-1:xxxxxxxxxxxx:table/Employee",
            "Effect": "Allow",
            "Sid": "DynamoDB"
        },
        {
            "Action": [
                "ssm:GetParameters"
            ],
            "Resource": "arn:aws:ssm:ap-northeast-1:xxxxxxxxxxxx:parameter/my-flask-app/*",
            "Effect": "Allow",
            "Sid": "SSMParameter"
        }
    ]
}

このため、DyanamoDBテーブルEmployeeを用意しデータ投入しておけばこの様にデータを表示できます。
(NoSQL WorkBenchの従業員データモデルのサンプルテーブルを用意してください)

補足2 : RDS for PostgreSQLにアクセスしてみる

続けてVPC Connectorを有効にしてVPC内部に用意したRDS for PostgreSQLからデータ取得してみます。
事前にVPC環境とRDS for PostgreSQLインスタンス、VPC Connector用のセキュリティグループを用意しておいてください。
セキュリティグループはアウトバウンド通信をRDSに接続できる様にしておけばOKです。

今回はCloudShellからAWS CLIを使ってVPC Connectorを作成していきます。
aws apprunner create-vpc-connectorが作成コマンドとなり、接続したいサブネットIDと紐づけるセキュリティグループIDをパラメーターとして指定してやります。

# aws apprunner create-vpc-connector コマンドでVPC Connectorを作成
aws apprunner create-vpc-connector --vpc-connector-name 'コネクタ名' \
    --subnets '接続したいサブネットのID (複数指定可)' \
    --security-groups '事前に用意したセキュリティグループのID'

CloudShellを起動しコマンドを実行してやるとこんな感じで作成されます。

CloudShellでの実行例

# CloudShellでの実行例
$ aws apprunner create-vpc-connector --vpc-connector-name 'my-vpc-connector' \
>     --subnets subnet-xxxxxxxxxx subnet-yyyyyyyyyy \
>     --security-groups sg-zzzzzzzzzzzzzzzz
{
    "VpcConnector": {
        "VpcConnectorName": "my-vpc-connector",
        "VpcConnectorArn": "arn:aws:apprunner:ap-northeast-1:xxxxxxxxxxxx:vpcconnector/my-vpc-connector/1/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "VpcConnectorRevision": 1,
        "Subnets": [
            "subnet-xxxxxxxxxx",
            "subnet-yyyyyyyyyy"
        ],
        "SecurityGroups": [
            "sg-zzzzzzzzzzzzzzzz"
        ],
        "Status": "ACTIVE",
        "CreatedAt": "2024-04-10T23:40:24.530000+00:00"
    }
}

これでVPC Connector my-vpc-connectorが作成されましたが、まだApp Runnerサービスとの紐づけができていません。
サービスの設定画面から「ネットワーキング」を選び送信ネットワークトラフィック欄で「カスタムVPC」を選び「VPCコネクタ」に作成したVPC Connectorを指定してやります。

あとは設定を保存してやれば変更が開始されアウトバウンド通信の経路が変更されます。

今回の検証アプリではRDSへの接続用にSSM Parameter Store /my-flask-app/RDSPostgreSQL を用意しています。 *3

Parameter Storeの値を更新したうえで、さらにApp Runnerサービスを再デプロイしてください。
すると更新後のSSM Parameter Storeの内容を取得しなおしてRDSへ接続可能となります。

ちなみにApp Runnerサービス側はこんな感じで環境変数を指定しています。

(環境変数POSTGRES_URLの値にSSM Parameter StoreのARNを指定)

あわせて読みたい

AWSジャパンのソリューションアーキテクトはまーんさんの登壇資料が非常にわかりやすいので本記事とあわせて読むとより理解が深まると思います。

終わりに

以上、『AWS 入門ブログリレー 2024』の19日目のエントリ『AWS App Runner』編でした。
次回、4/13日は弊社みなみによる「Amazon CloudFront編」の予定です!

脚注

  1. 実際にはAWSが内部的に管理するVPCがありその中でコンテナが起動しています
  2. コンテナイメージのPull、CloudWatch Logsの出力、シークレットへのアクセスを行うための通信(ドキュメント上ではApp Runner trafficと呼称される)は例外
  3. CloudFormation一発で検証環境を作成する都合SecureStringではなく通常のString型になっています。本番環境ではSecureString型を使うと良いでしょう。