😎

AWS CDK で AWS App Runner をデプロイする

2024/03/11に公開

概要

AWS App Runner を AWS CDK でデプロイしてみました。App Runner 用の L2 Construct はまだリリースされていないため CDK の恩恵は少なめですが、L1 で作成しました(α版はあるようですが)。コンテナイメージのビルドも CDK でおこない、cdk-docker-image-deployment を使って ECR リポジトリへのプッシュを同時におこないます。

準備

src/app/ 配下に Dockerfile をおき、通常の Web サーバーが起動するコンテナイメージがビルドできる状態にしておきます。

CDK プロジェクトに cdk-docker-image-deployment をインストールしておきます。

npm install --save cdk-docker-image-deployment

CDK 定義

const cpu = 256;
const memory = 512;
const containerPort = 8080;

const repository = new ecr.Repository(this, "Repository", {
    emptyOnDelete: true,
    removalPolicy: cdk.RemovalPolicy.DESTROY,
});

const imageDeployment = new imagedeploy.DockerImageDeployment(this, "ImageDeployment", {
    source: imagedeploy.Source.directory("src/app"),
    destination: imagedeploy.Destination.ecr(repository, {tag: "latest"}),
}); 

const accessRole = new iam.Role(this, "AccessRole", {
    assumedBy: new iam.ServicePrincipal("build.apprunner.amazonaws.com"),
    managedPolicies: [
        iam.ManagedPolicy.fromAwsManagedPolicyName("service-role/AWSAppRunnerServicePolicyForECRAccess"),
    ],
});
const instanceRole = new iam.Role(this, "InstanceRole", {
    assumedBy: new iam.ServicePrincipal("tasks.apprunner.amazonaws.com"),
});
const autoScalingConfiguration = new apprunner.CfnAutoScalingConfiguration(this, "AutoScalingConfiguration", {
    maxSize: 1,
});
const service = new apprunner.CfnService(this, "AppRunner", {
    autoScalingConfigurationArn: autoScalingConfiguration.attrAutoScalingConfigurationArn,
    instanceConfiguration: {
        cpu: String(cpu),
        instanceRoleArn: instanceRole.roleArn,
        memory: String(memory),
    },
    sourceConfiguration: {
        authenticationConfiguration: {
            accessRoleArn: accessRole.roleArn,
        },
        autoDeploymentsEnabled: true,
        imageRepository: {
            imageConfiguration: {
                port: String(containerPort),
                runtimeEnvironmentVariables: [],
                runtimeEnvironmentSecrets: [],
            },
            imageIdentifier: repository.repositoryUriForTag("latest"),
            imageRepositoryType: "ECR",
        },
    },
});
service.node.addDependency(imageDeployment);

注意点ですが、更新デプロイ時にコンテナイメージの更新とリソースの設定変更が同時に発生した場合、イメージの更新を検出して App Runner がデプロイシーケンスを開始するため、リソースの設定変更が状態不正でエラーになってしまうようでした。App Runner はソースやコンテナのビルドパイプラインの機能もあるので、CDK でビルドまでするのはあまり相性が良くないかもしれません。

カスタムドメイン

これで払い出された URL (https://xxxxxxxx.ap-northeast-1.apprunner.com) でアクセスできるようになりますが、独自のドメインでサービスするにはカスタムドメインの設定も必要です。

CloudFormation で App Runner のカスタムドメインの設定には現状対応していなかったため、以下のようにカスタムリソースで作成しました。この方法では、ドメイン名をあとから変更して更新することはできません。

参考) #129 CloudFormation/CDK Custom Domain Support For AppRunner

new cdk.custom_resources.AwsCustomResource(this, "CustomResource", {
    logRetention: logs.RetentionDays.ONE_DAY,
    onCreate: {
        service: "AppRunner",
        action: "AssociateCustomDomain",
        parameters: {
            ServiceArn: service.attrServiceArn,
            DomainName: domainName,
        },
        physicalResourceId: cdk.custom_resources.PhysicalResourceId.of("AppRunner"),
    },
    onDelete: {
        service: "AppRunner",
        action: "DisassociateCustomDomain",
        parameters: {
            ServiceArn: service.attrServiceArn,
            DomainName: domainName,
        },
        physicalResourceId: cdk.custom_resources.PhysicalResourceId.of("AppRunner"),
    },
    policy: cdk.custom_resources.AwsCustomResourcePolicy.fromSdkCalls({
        resources: cdk.custom_resources.AwsCustomResourcePolicy.ANY_RESOURCE,
    }),
});

デプロイ後、ドメイン検証のため、App Runner のサービス > 「カスタムドメイン」タブから「DNS の設定」を参照し、手順に従って表示された内容の CNAME レコードを DNS サーバーに登録します。正しく設定できていれば、自動でサーバー証明書の作成がおこなわれ、ステータスが「アクティブ」になります。同様に、App Runner への CNAME または ALIAS レコードを追加して完了です。

DNS の設定

Discussion