ECR+App RunnerをCDKデプロイする

[アップデート] AWS App Runner でついに AWS WAF がサポートされました | DevelopersIO

自分は圧倒的にLambdaマンだが、WAF対応もしたということで本番投入機会が増えていきそうなApp Runnerをキャッチアップしてみる。CDKで素振りする。

DockerのhttpdイメージをApp Runnerにデプロイしてみる。

環境

  • M1 Mac Big Sur
  • node 16.15.0
  • typescript 5.0.2
  • aws-cdk-lib 2.69.0
  • constructs 10.1.281
  • @aws-cdk/aws-apprunner-alpha 2.69.0-alpha.0
  • cdk-docker-image-deployment 0.0.195

コード

aws-cdk-lib 以外のところで以下を利用する:

両方とも公式もしくは準公式のパッケージなので採用で問題ないはず。

CDKコード:

// lib/app-runner-stack.ts
import { Construct } from "constructs";
import * as cdk from "aws-cdk-lib";
import * as apprunner from "@aws-cdk/aws-apprunner-alpha";
import * as imagedeploy from "cdk-docker-image-deployment";

export class AppRunnerStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const repository = new cdk.aws_ecr.Repository(this, "httpdRepository", {
      repositoryName: "httpd-repository",
      removalPolicy: cdk.RemovalPolicy.DESTROY,
    });

    new imagedeploy.DockerImageDeployment(
      this,
      "exampleImageDeploymentWithTag",
      {
        source: imagedeploy.Source.directory("./src/app-runner"),
        destination: imagedeploy.Destination.ecr(repository, {
          tag: "latest",
        }),
      }
    );

    const service = new apprunner.Service(this, "apprunnerService", {
      source: apprunner.Source.fromEcr({
        imageConfiguration: { port: 80 },
        repository,
        tagOrDigest: "latest",
      }),
    });

    new cdk.CfnOutput(this, "ServiceUrl", {
      exportName: "ServiceUrl",
      value: service1.serviceUrl,
    });
  }
}

Dockerfile:

# src/app-runner/Dockerfile
FROM --platform=linux/amd64 httpd

M1 Macなので --platform=linux/amd64 を付ける必要がある(ないと後述のエラーが発生)。

ハマった点

上記コードに行き着くまでに結構ハマっている。App Runnerのデプロイ毎に数分かかることもあり、高速で試行を回しづらく時間を溶かしてしまった。

まず、最初にCDKデプロイしようとすると下記エラーに遭遇:

# CDKデプロイ時エラー
Resource handler returned message: "null" (RequestToken: xxxxxxx-xxxxxxxxx-xxxxxxxx, HandlerErrorCode: null)

詳細な内容がなく、これだと原因がわからない。

こういうときはInfrastructure as Codeだけでなんとかしようとするのはやめてマネコンからリソースを作ってみるに限る、ということでマネコンからApp Runnerをデプロイ。

アプリケーションログにおいて以下のエラーが発生していることが判明:

# アプリケーションログ
exec /usr/local/bin/httpd-foreground: exec format error

調べたところ、M1 MacでDockerイメージをビルドした際に起こる問題の模様。

【GCP】「exec user process caused: exec format error」というエラーを解決!【GKE】|HikariBlog

ここ数年Lambda一辺倒過ぎて最近(M1なんてもう最近でもないけど)のDocker事情をキャッチアップできてなかった。

最初は --platform=linux/amd64 を付けていなかったため、付与してこの点は解決。

- FROM httpd
+ FROM --platform=linux/amd64 httpd

で、またデプロイしようとすると再度エラー。今度はイベントログ:

# イベントログ
[AppRunner] Deployment with ID : xxxxxxxxxxxxxxx failed. Failure reason : Health check failed.
[AppRunner] Health check failed on port '8080'. Check your configured port number. For more information, read the application logs.

エラーによると「指定してるポート違うんじゃない?」とのことなので、見直して気づく。 8080 にしてしまっていたので 80 に直した。

- imageConfiguration: { port: 8080 }
+ imageConfiguration: { port: 80 },

以上でAWSマネコン操作でもCDKデプロイでも正常に起動できるようになった。

参考