App Runnerの学習にあたり、以下のWorkshopをCDKで実装してみました。そのまとめです。
catalog.us-east-1.prod.workshops.aws
コードは以下にあります。
※App Runnerが何であるかは一切書いてありません。基礎知識を得たい場合は以下の記事がおすすめです。
動画が良い場合は以下。
目次
アーキテクチャ
以下のようにApp Runnerの主要な機能を一通り学習することができます。
CDKプロジェクトの構成
. ├── README.md ├── bin │ └── cdk.ts ├── cdk.json ├── cdk.out ├── lib │ ├── apprunner-rds-workshop-stack.ts │ └── construct │ ├── apprunner.ts # App Runnerを実装 │ ├── database.ts # Auroraを実装 │ └── network.ts # VPCを実装 ├── package-lock.json ├── package.json ├── test │ └── cdk.test.ts └── tsconfig.json
CDKの実装
networkの実装
Workshopに従い、以下の条件を満たすVPCを作成します。
- NAT Gatewayは1つ
- AZは3つにまたがる
- 各AZはパブリックサブネットとプライベートサブネットを持つ
今回は以下のようにVPCのCIDRを指定し、上記に関するプロパティ設定を行った上で後はおまかせの形にしました。
const vpc = new ec2.Vpc(this, 'Vpc', { natGateways: 1, // NAT Gatewayは1つ maxAzs: 3, // AZは3つ ipAddresses: ec2.IpAddresses.cidr(`10.0.0.0/16`), subnetConfiguration: [ // サブネットはパブリックとプライベート(アウトバウンドはNAT Gateway)を1つずつ。 { cidrMask: 24, name: 'PublicSubnet', subnetType: ec2.SubnetType.PUBLIC, }, { cidrMask: 24, name: 'PrivateSubnet', subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, }, ], enableDnsHostnames: true, enableDnsSupport: true } )
なお、3つ以上のAZにサブネットを作成する場合は、アカウントとリージョンを明示する必要があります。
databaseの実装
Workshopに従いAurora MySQLを構築します。
今回はAurora Serverless v2にしてみました。
const databaseCluster = new rds.DatabaseCluster(this, 'Database', { engine: rds.DatabaseClusterEngine.auroraMysql({ version: rds.AuroraMysqlEngineVersion.VER_3_05_0 }), vpc: props.vpc, vpcSubnets: props.vpc.selectSubnets({ subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }), // 配置されるサブネットのタイプのみ指定 credentials: rds.Credentials.fromGeneratedSecret('apprunner'), writer: rds.ClusterInstance.serverlessV2('Writer', {}), // Aurora Serverless v2を指定 serverlessV2MaxCapacity: 1.0, serverlessV2MinCapacity: 0.5, cloudwatchLogsRetention: logs.RetentionDays.ONE_DAY, removalPolicy: cdk.RemovalPolicy.DESTROY })
apprunnerの実装
今回のメインです。αモジュールを使用しています。
@aws-cdk/aws-apprunner-alpha module · AWS CDK
Dockerイメージによるデプロイ
今回はマネージドランタイムではなく、Dockerイメージによるデプロイにしてみました。
モノレポ構成でアプリ(ap
)とインフラ(cdk
)を同居させているので、DockerImageAsset
によりcdk deploy
時にイメージのビルド、プッシュを行います。
// Dockerイメージのビルド・プッシュ const image = new DockerImageAsset(this, 'CDKAppRunnerSampleImage', { directory: '../ap', platform: Platform.LINUX_AMD64, });
なお、M2 Macbook Air(Apple Silicon)を使用しているのですが、Docker Desktopではうまくビルドができませんでした。そのため今回 Finch
を使用しています。
Finchの解説は以下が参考になりました。
CDKでFInchを使用する場合は、以下のようにFinchのVMを起動して、環境変数のCDK_DOCKER
を設定します。CDK_DOCKER
の説明は以下が参考になりました。
# finch vm起動 finch vm start # CDK_DOCKERを設定 export CDK_DOCKER=finch
VPC Connectorの設定
VPCリソースに接続するためVPC Connector を作成します。
セキュリティグループの設定はconnections
を使用して簡易に実装しています。
※参考
// VPC Connector const vpcConnector = new apprunner.VpcConnector(this, 'VpcConnector', { vpc: props.vpc, vpcSubnets: props.vpc.selectSubnets({ subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }), // プライベートサブネットを指定 }) // AppRunner -> RDSのアクセス許可 props.databaseCluster.connections.allowDefaultPortFrom(vpcConnector) // connectionsでVPC ConnectorからAuroraに接続できるよう設定
App RunnerのServiceを作成
サンプルAPで使用するSSM Parameter Storeと、App RunnerのServiceを定義します。
SSM Parameter StoreやSecrets ManagerはenvironmentSecrets
で参照させます。
// SSM Parameter Store const ssmParameter = new ssm.StringParameter(this, 'SsmParameter', { parameterName: 'HOTEL_NAME', stringValue: 'YOUR HOTEL NAME' }); // App Runner Service const appRunnerService = new apprunner.Service(this, 'AppRunnerService', { cpu: apprunner.Cpu.ONE_VCPU, memory: apprunner.Memory.TWO_GB, source: apprunner.Source.fromAsset({ asset: image, // DockerImageAssetで定義したassetを指定 imageConfiguration: { port: 8080, environmentSecrets: { MYSQL_SECRET: apprunner.Secret.fromSecretsManager(props.databaseCluster.secret!), // AuroraのSecrets Managerを参照 HOTEL_NAME: apprunner.Secret.fromSsmParameter(ssmParameter), // SSM Parameter Storeを参照 } }, }), vpcConnector: vpcConnector })
X-RAYの有効化
執筆時点ではαモジュールで有効化できなかったので、Escape Hatchesを使用して有効化しています。
// X-RAY有効化 const cfnObservabilityConfig = new CfnObservabilityConfiguration(this, 'SampleAppRunnerObserveConfig', { observabilityConfigurationName: 'SampleAppRunnerObserveConfig', traceConfiguration: { vendor: 'AWSXRAY' } }); const cfnService = appRunnerService.node.defaultChild as CfnService; cfnService.addPropertyOverride('ObservabilityConfiguration', { 'ObservabilityEnabled': true, 'ObservabilityConfigurationArn': cfnObservabilityConfig.ref })
WAF設定
WebACLを作成して、ARNで紐付けを行います。
// WAF設定 const appWaf = new wafv2.CfnWebACL(this, "AppRunnerWaf", { defaultAction: { allow: {} }, scope: "REGIONAL", visibilityConfig: { cloudWatchMetricsEnabled: true, sampledRequestsEnabled: true, metricName: "App-Runner-Waf", }, rules: [ // AWSManagedRulesCommonRuleSet { priority: 1, overrideAction: { none: {} }, visibilityConfig: { sampledRequestsEnabled: true, cloudWatchMetricsEnabled: true, metricName: "AWS-AWSManagedRulesCommonRuleSet", }, name: "AWSManagedRulesCommonRuleSet", statement: { managedRuleGroupStatement: { vendorName: "AWS", name: "AWSManagedRulesCommonRuleSet", }, }, }, // AWSManagedRulesKnownBadInputsRuleSet { name: "AWSManagedRulesKnownBadInputsRuleSet", priority: 2, statement: { managedRuleGroupStatement: { vendorName: "AWS", name: "AWSManagedRulesKnownBadInputsRuleSet", }, }, overrideAction: { none: {} }, visibilityConfig: { cloudWatchMetricsEnabled: true, sampledRequestsEnabled: true, metricName: "AWSManagedRulesKnownBadInputsRuleSet", }, }, ], }); // WebACLをApp Runnerに紐付け new wafv2.CfnWebACLAssociation(this, "Waf-App-Runner", { webAclArn: appWaf.attrArn, resourceArn: appRunnerService.serviceArn, });
動作確認
デプロイ後、App Runnerのエンドポイントにブラウザからアクセスし、サンプルアプリが起動していることを確認します。
Parameter
タブで、SSM Parameter StoreやSecrets Managerの値を確認することができます。DBのパスワードはマスクされていますね。
Create
タブを押下すると、アプリからDBに対してDDLが発行されテーブルが作成されます。
その後Add
やRoom
タブでDBの更新や内容の確認が行えます。
おわりに
AWS App Runner WorkshopでApp Runnerの主要機能を一通り試せるので、使用を検討されてる方はおすすめです。