1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

App Runner をいろいろ試してみる。

Posted at

はじめに

すごく今更なのですが、App Runner について少し調べる必要が出たので、調べてみた記事です。

AWS App Runner とは?

AWS App Runner は、2021 年 5 月に GA されたサービスで、ソースコードまたはコンテナイメージから簡単にインフラが構築できるサービスです。

ALB の設定も不要で、App Runner 単体でオートスケーリングや負荷分散も実施してくれるので、開発者はアプリケーションの開発に集中できます。

料金体系も特徴的で、プロビジョニングされたコンテナインスタンスに対する課金と、実際のコンピューティングリソース・メモリの使用量に応じた従量課金の 2 つで構成されます。

最小インスタンス数分のプロビジョニング料金は常に発生しますが、リクエストがない場合は従量課金が抑えられるため、トラフィックの少ない時間帯はコストを抑えることができます。

以下の2つの資料が分かりやすいので紹介です!

もうすぐローンチ 3 周年! AWS App Runner の魅力と進化の歴史

こちらは動画も公開されていますので、動画で確認するのがオススメ。

AWS App Runner を使う時に押さえておきたい勘所 〜 Web アプリをコンテナに最適化する  〜

試してみる

では、触ってみます。

今回は TypeScript(hono)と CDK を使い、メジャーな機能の動作確認をしてみました。

なお、CDK および、App Runner のコードは以下に格納済みです。(ソース本体と CDK の両方をモノレポで管理しています。)

ソースコード(モノレポ)からデプロイ

App Runner 上で動作するアプリケーションは ECR 上のコンテナイメージまたはソースコードから指定できますが、今回はソースコードからデプロイするようにしてみました。

デプロイ時間の比較はしていませんが、ソースコードからのデプロイは CodeBuild を使ったイメージの作成も実施されるため、ECR を使ったデプロイよりは時間がかかりそうです。

image.png

(引用元:https://speakerdeck.com/track3jyo/app-runner-the-appeal-and-evolution-over-3-years-since-launch?slide=18)

また 2023 年にはモノレポに対応して、ソースのルートディレクトリを指定することが可能になっています。

スクリーンショット 2025-11-17 5.30.38.png

CDK 対応

公式や Construct Hub を見る限り、2025/11 現在、L2 Construct は@aws-cdk/aws-apprunner-alpha moduleが利用できそうです。

ただ Alpha 版ということで、ソースの大幅変更を伴う修正が入る可能性もあり、利用には注意が必要です。

(とはいえ、もう公開から 4 年経過している模様...)

コードはこのような感じです。

app-runner.ts
// App Runner
const autoScalingConfig = new apprunnerAlpha.AutoScalingConfiguration(
  this,
  "AutoScalingConfig",
  {
    maxConcurrency: 5,
    maxSize: 2,
    minSize: 1,
  }
);
const service = new apprunnerAlpha.Service(this, "HonoAppRunnerService", {
  source: apprunnerAlpha.Source.fromGitHub({
    repositoryUrl: props.repositoryUrl,
    branch: "main",
    configurationSource: apprunnerAlpha.ConfigurationSourceType.API,
    codeConfigurationValues: {
      runtime: apprunnerAlpha.Runtime.NODEJS_22,
      buildCommand: "npm install && npm run build",
      startCommand: "npm start",
      port: "8080",
      environment: {
        PORT: "8080",
        DB_HOST: dbCluster.clusterEndpoint.hostname,
        DB_NAME: "apprunner",
      },
      environmentSecrets: dbCluster.secret
        ? {
            DB_USER: apprunnerAlpha.Secret.fromSecretsManager(
              dbCluster.secret,
              "username"
            ),
            DB_PASSWORD: apprunnerAlpha.Secret.fromSecretsManager(
              dbCluster.secret,
              "password"
            ),
          }
        : undefined,
    },
    connection: apprunnerAlpha.GitHubConnection.fromConnectionArn(
      props.githubConnectionArn
    ),
  }),
  vpcConnector,
  autoScalingConfiguration: autoScalingConfig,
  healthCheck: apprunnerAlpha.HealthCheck.http({
    path: "/health",
  }),
});

後述していますが、codeConfigurationValuesのところを省略できれば、より少ないコードで定義可能です。

なお、App Runner から GitHub への接続は初回のみ CDK では対応できず、以下マネジメントコンソールの接続済みアカウントからGitHubの設定しておく必要がありました。

スクリーンショット 2025-11-17 5.51.39.png

また、ソースコードからの自動デプロイ、モノレポ対応が対応しておらず、エスケープハッチでの対応が必要です。

app-runner.ts
const cfnService = service.node.defaultChild as apprunner.CfnService;
cfnService.addPropertyOverride(
  "SourceConfiguration.CodeRepository.SourceDirectory",
  "packages/hono-apprunner"
);
cfnService.addPropertyOverride(
  "SourceConfiguration.AutoDeploymentsEnabled",
  true
);

環境変数について

App Runner 上で動作するサービスに DB 接続先などの情報を提供する際は Secrets Manager を使うことが推奨されており、サービス側では環境変数として利用することができます。

今回の場合、CDK のcodeConfigurationValues.environmentSecretsに指定していますが、apprunner.yamlとして資材のルートディレクトリに格納することも可能です。

apprunner.yaml
version: 1.0
runtime: nodejs22
build:
  commands:
    build:
      - echo "Installing dependencies"
      - npm install
      - echo "Building application"
      - npm run build
run:
  command: npm start
  network:
    port: 8080
  env:
    - name: PORT
      value: "8080"
    - name: DB_HOST
      value: "forapprunner.cluster-cp2ai8qycrin.ap-northeast-1.rds.amazonaws.com"
    - name: DB_NAME
      value: "apprunner"
  secrets:
    - name: DB_USER
      value-from: "arn:aws:secretsmanager:ap-northeast-1:123456789123:secret:rds!cluster-4d6bb964-0cf6-471a-8865-a684ea85c653-rHmsS3:username::"
    - name: DB_PASSWORD
      value-from: "arn:aws:secretsmanager:ap-northeast-1:123456789123:secret:rds!cluster-4d6bb964-0cf6-471a-8865-a684ea85c653-rHmsS3:password::"

本来は、apprunner.yaml側で管理したいのですが、今回は同一 Stack で生成したリソースの参照(Aurora の接続情報)が発生するため、CDK 側で指定しています。

VPC コネクタ経由でAurora Serverless に接続

App Runner は初期状態で、VPC 内のリソースに接続できませんが、VPC コネクタを接続することで VPC リソースにも接続可能です。

これでプライベートサブネット上に構築した RDS/Aurora へ接続することが可能になります。

VPC コネクタにはセキュリティグループが必要ですが、基本的にはアウトバンドのみを許可しておけば問題ありません。

app-runner.ts
// VPCコネクタ
const vpcConnectorSg = new ec2.SecurityGroup(this, "VpcConnectorSg", {
  vpc,
  description: "Security group for App Runner VPC Connector",
  allowAllOutbound: true,
});

const vpcConnector = new apprunnerAlpha.VpcConnector(this, "VpcConnector", {
  vpc,
  vpcSubnets: vpc.selectSubnets({
    subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
  }),
  securityGroups: [vpcConnectorSg],
});

今回は/db-testエンドポイントで動作確認しました。

index.ts
const dbConfig = {
  host: process.env.DB_HOST || "localhost",
  user: process.env.DB_USER || "root",
  password: process.env.DB_PASSWORD || "",
  database: process.env.DB_NAME || "test",
  port: 3306,
};

app.get("/db-test", async (c) => {
  try {
    const connection = await mysql.createConnection(dbConfig);
    const [rows] = await connection.execute("select 1");
    await connection.end();

    return c.json({
      status: "Database connection successful",
      result: rows,
    });
  } catch (error: any) {
    return c.json(
      {
        status: "Database connection failed",
        error: error.message || "Unknown error",
      },
      500
    );
  }
});

問題なさそうです!

{
    "status": "Database connection successful",
    "result": [
        {
            "1": 1
        }
    ]
}

VPC コネクタ経由で外部サイトに接続

次に外部サイトへ接続してみます。

VPC コネクタは Private サブネットのみ接続可能です。

また、VPC コネクタを指定すると全ての通信がプライベートサブネット経由になるため、App Runner 上のサービスから外部に接続する際は NAT Gateway の準備が必要です。

今回は/external-testのエンドポイントで確認してみました。

app.get("/external-test", async (c) => {
  try {
    const response = await fetch("http://checkip.amazonaws.com");
    const data = await response.json();

    return c.json({
      status: "External communication successful",
      externalResponse: data,
    });
  } catch (error: any) {
    return c.json(
      {
        status: "External communication failed",
        error: error.message || "Unknown error",
      },
      500
    );
  }
});

問題なさそうです!

{
    "status": "External communication successful",
    "ipAddress": "13.xxx.xxx.130"
}

オートスケーリング

App Runner はオートスケーリングも自動で設定可能ですが、そのトリガーはリクエスト数のみです。

image-1.png

(引用元:https://speakerdeck.com/track3jyo/app-runner-the-appeal-and-evolution-over-3-years-since-launch?slide=21)

動作確認してみてわかったことですが、TPS のような単純なリクエスト数換算ではなく、リクエストをどれくらい多重に処理をしているか、でスケールするようです。

最初は文字列を出力するのみのエンドポイントで動作確認していましたが、うまくスケールアウトしてくれませんでした。

そこで、500msec の wait を追加することで処理が同時実行されるようにした上で確認してみました。

app.get("/", async (c) => {
+  await new Promise((resolve) => setTimeout(resolve, 500));
  return c.json({
    message: "Hello from Hono on App Runner!",
  });
});

スケールアウトの条件を同時実行5に設定した状態にて、Postmanから仮想ユーザ15で5分間、負荷をかけてみます。

image-4.png

Concurrency(処理の多重度)は最大で6まで上がっています。

image-6.png

それに伴い、Active instancesも2つになっていました。

image-5.png

結構頻度にアクティブインスタンスが増減するんですね。

また、多くリクエストを投げると、429 Too Many Requestsの発生を確認しました。

カスタムドメイン

デフォルトではhttps://xxxxxxxxx.ap-northeast-1.awsapprunner.comというドメインで接続可能ですが、独自ドメインを設定することも可能です。

今回は、別アカウントの ACM で購入したドメインで動作確認してみましたが、いくつかの CNAME レコードを指定するだけで簡単に設定できました。

スクリーンショット 2025-11-17 18.42.17.png

API Gateway との HTTP 統合

App Runner には認証・認可、流量制御機能は用意されていません。

このため、API Gateway と HTTP 統合することで、これらの機能を API Gateway にお任せすることもできます。

image-2.png

気になること

ここまでの通り、App Runner の紹介をしました。

サイドカー構成など、手が届かないところもあるのですが、それ以上に気になるところがあります。

CDK の対応状況もそうですが、App Runner 自体のアップデートも直近はランタイムの継続的な更新及び、IPv6 対応に留まり、新機能の追加がありません。

また、下記の公開ロードマップを見ても、開発が活発に行われている感じがしません。

状況によっては本番ワークロードにも活用できるサービスかと考えているのですが、サービス終了にならないかが個人的な心配事です...

まとめ

今回は App Runner の紹介でした!

ここ数年はアップデートが少なく、寂しい感じはしますが活用できるシーンはあると思います。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?