はじめに
nuxt3は11/16正式リリースされましたね!!
AppRunnerもつい最近プライベートエンドポイントに対応したので、利用の検討を考えている人も多いと思うのでデプロイ方法とアーキテクチャーを検討してみました
今回の記事で使用したリソースを保管しているリポジトリ: リンク
前提条件
- AWSアカウントは開発環境と本番環境の2つがあると仮定
- 開発環境の中に開発中に使用するDEV環境と、本番環境とほぼ同等のSTG環境の2つがある想定
- 今回は本番環境については考慮しない
Deploy戦略
AppRunnerにアプリケーションをデプロイする方法は以下の3つのいずれかが多いかと思います。
-
CodePipelineとCodeBuild、CloudformationでコンテナをビルドしてAppRunnerを構築する
-
コンテナをCI/CDを備えたソフトウェアでビルド後ECRにプッシュして、AppRunnerの自動反映(AutoDeploy)機能でアプリケーションを反映する
1のメリット
- Cloudformationを使ってDeployしているため、コンテナのデプロイ時にlatestタグではなくバージョン指定してDeployが可能。(CodePipelineの部分をCI/CDツールに置き換えてAWS-CDKを使う方法でも可)
- アクセスキー・シークレットキーを発行せずRoleにアタッチした権限でデプロイが可能
- ECR1つに対して複数環境を構築することが可能(今回は環境ごとに分けます)
2のメリット
- コンテナさえECRにPushできる環境があれば自動反映が使える
3のメリット
- CI/CDのツールを構築する必要がなくマネジメントコンソールからApp Runnerを構築したらすぐデプロイできる
この記事では1の方法でデプロイします。2や3の方法は様々な方が実践されていますのでそちらご参考ください。
全体アーキテクチャー図
注意
App RunnerのアウトバウンドはNAT Gateway経由でインバウンドはVPCエンドポイント経由のまたはインターネットのパブリックアクセスになります。(非公開設定は入れておりません)
App Runnerをプライベートエンドポイントアクセスの設定して、VPCからのみアクセスできるようにしようと思ったのですが、インフラ周りのソースとドキュメントを構築し終えた時にAWS-CDKでプライベートエンドポイント作れないことがわかったのでパブリック公開とて実装してします。悲しいね。。。(Cloudformationではプライベートエンドポイントの作成には対応してるので、Cloudformationテンプレートに書き起こせる方はご検討ください。)
今回自分が作成したネットワークではPrivate subnetの必要性はあまりありませんが、データベースのRDSを追加する可能性があるため作成しています。
ネットワーク構成図
ルーティングやセキュリティグループについて以下の通り構築する。
- リクエストの受け口となるロードバランサーやインターネットアクセスの受付をするNAT GatewayはPublic subnetに配置
- EC2やFargateその他アプリケーションを配置するリソースは、インターネットのインバウンドのアクセスがないProtect subnetに配置
- ※Protect subnetはインターネットのインバウンド・アウトバウンドができないPrivate subnetに対して、アウトバウンドをできるようにしたもの
- RDSのMySQLやPostgreSQLはProtect subnetにあるリソースからのみアクセスできるようにPrivate subnetに配置
VPCとサブネットのテンプレート
VPC:
Type: AWS::EC2::VPC
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
CidrBlock: !Sub ${NwSeg}.0/24
EnableDnsHostnames: true
EnableDnsSupport: true
# AZa
PublicSubnetAZa:
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZa'
- Key: Subnet
Value: !Sub 'Public'
VpcId: !Ref VPC
CidrBlock: !Sub '${NwSeg}.0/27'
AvailabilityZone: ap-northeast-1a
ProtectSubnetAZa:
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZa'
- Key: Subnet
Value: !Sub 'Protect'
VpcId: !Ref VPC
CidrBlock: !Sub '${NwSeg}.64/26'
AvailabilityZone: ap-northeast-1a
PrivateSubnetAZa:
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZa'
- Key: Subnet
Value: !Sub 'Private'
VpcId: !Ref VPC
CidrBlock: !Sub '${NwSeg}.192/28'
AvailabilityZone: ap-northeast-1a
# AZc
PublicSubnetAZc:
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZc'
- Key: Subnet
Value: !Sub 'Public'
VpcId: !Ref VPC
CidrBlock: !Sub '${NwSeg}.32/27'
AvailabilityZone: ap-northeast-1c
ProtectSubnetAZc:
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZc'
- Key: Subnet
Value: !Sub 'Protect'
VpcId: !Ref VPC
CidrBlock: !Sub '${NwSeg}.128/26'
AvailabilityZone: ap-northeast-1c
PrivateSubnetAZc:
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZc'
- Key: Subnet
Value: !Sub 'Private'
VpcId: !Ref VPC
CidrBlock: !Sub '${NwSeg}.208/28'
AvailabilityZone: ap-northeast-1c
Rooting
ルーティング周りを行っているテンプレート
# VPC Internet rooting
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
VPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
PublicSubnetRouteTable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Subnet
Value: !Sub 'Public'
VpcId: !Ref VPC
RouteInternetGateway:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
RouteTableId: !Ref PublicSubnetRouteTable
# PublicSubnet Rooting
PublicSubnetRouteTableAssociationAZa:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicSubnetRouteTable
SubnetId: !Ref PublicSubnetAZa
PublicSubnetRouteTableAssociationAZc:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicSubnetRouteTable
SubnetId: !Ref PublicSubnetAZc
# AZa ProtectSubnet rooting
ElasticIPAZa:
Type: AWS::EC2::EIP
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZa'
- Key: Subnet
Value: !Sub 'Public'
Domain: vpc
NatGatewayAZa:
Type: AWS::EC2::NatGateway
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZa'
- Key: Subnet
Value: !Sub 'Public'
AllocationId: !GetAtt ElasticIPAZa.AllocationId
SubnetId: !Ref PublicSubnetAZa
DependsOn:
- ElasticIPAZa
ProtectSubnetRouteTableAZa:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZa'
- Key: Subnet
Value: !Sub 'Protect'
VpcId: !Ref VPC
RouteNatGatewayAZa:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGatewayAZa
RouteTableId: !Ref ProtectSubnetRouteTableAZa
ProtectSubnetRouteTableAssociationAZa:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref ProtectSubnetRouteTableAZa
SubnetId: !Ref ProtectSubnetAZa
# AZa ProtectSubnet rooting
ElasticIPAZc:
Type: AWS::EC2::EIP
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZc'
- Key: Subnet
Value: !Sub 'Public'
Domain: vpc
NatGatewayAZc:
Type: AWS::EC2::NatGateway
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZc'
- Key: Subnet
Value: !Sub 'Public'
AllocationId: !GetAtt ElasticIPAZc.AllocationId
SubnetId: !Ref PublicSubnetAZc
DependsOn:
- ElasticIPAZc
ProtectSubnetRouteTableAZc:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZc'
- Key: Subnet
Value: !Sub 'Protect'
VpcId: !Ref VPC
ProtectSubnetRouteAZc:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGatewayAZc
RouteTableId: !Ref ProtectSubnetRouteTableAZc
ProtectSubnetRouteTableAssociationAZc:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref ProtectSubnetRouteTableAZc
SubnetId: !Ref ProtectSubnetAZc
AppRunnerEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
PrivateDnsEnabled: true
SecurityGroupIds:
- !Ref ProtectSecurityGroup
ServiceName: !Sub 'com.amazonaws.${AWS::Region}.apprunner'
SubnetIds:
- !Ref ProtectSubnetAZa
- !Ref ProtectSubnetAZc
VpcEndpointType: 'Interface'
VpcId: !Ref VPC
Public subnetに配置されるリソース向けのセキュリティグループ
- インターネットからのインバウンドはTCPまたはUDPの80または443のポートを許可
- Public subnet内インバウンドとアウトバウンド、インターネットへのアウトバウンドはTCPのみ全ポート許可
- Protect subnetへはTCPまたはUDPの80または443のポートを許可
Publicサブネット向けのセキュリティグループテンプレート
PublicSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Subnet
Value: !Sub 'Public'
GroupDescription: Public Security Group
SecurityGroupIngress:
# Internet
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: !Sub '0.0.0.0/0'
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: !Sub '0.0.0.0/0'
- IpProtocol: udp
FromPort: 80
ToPort: 80
CidrIp: !Sub '0.0.0.0/0'
- IpProtocol: udp
FromPort: 443
ToPort: 443
CidrIp: !Sub '0.0.0.0/0'
# Public Subnet AZa
- IpProtocol: tcp
FromPort: 0
ToPort: 65535
CidrIp: !Sub '${NwSeg}.0/27'
# Public Subnet AZc
- IpProtocol: tcp
FromPort: 0
ToPort: 65535
CidrIp: !Sub '${NwSeg}.32/27'
SecurityGroupEgress:
# Public Subnet AZa
- IpProtocol: tcp
FromPort: 0
ToPort: 65535
CidrIp: !Sub '${NwSeg}.0/27'
# Public Subnet AZc
- IpProtocol: tcp
FromPort: 0
ToPort: 65535
CidrIp: !Sub '${NwSeg}.32/27'
# Protect Subnet AZa
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: !Sub '${NwSeg}.64/26'
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: !Sub '${NwSeg}.64/26'
- IpProtocol: udp
FromPort: 80
ToPort: 80
CidrIp: !Sub '${NwSeg}.64/26'
- IpProtocol: udp
FromPort: 443
ToPort: 443
CidrIp: !Sub '${NwSeg}.64/26'
# Protect Subnet AZc
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: !Sub '${NwSeg}.128/26'
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: !Sub '${NwSeg}.128/26'
- IpProtocol: udp
FromPort: 80
ToPort: 80
CidrIp: !Sub '${NwSeg}.128/26'
- IpProtocol: udp
FromPort: 443
ToPort: 443
CidrIp: !Sub '${NwSeg}.128/26'
VpcId: !Ref VPC
Protect subnetに配置されるリソース向けのセキュリティグループ
- Public subnetへはTCPの80または443のポートを許可(主にNAT Gateway経由)
- Public subnetからのインバウンドはTCPまたはUDPの80または443のポートを許可
- Protect subnet内インバウンドとアウトバウンドはTCPのみ全ポート許可
- Private subnetへはTCPの3306または5432のポートを許可
Protectサブネットのセキュリティグループテンプレート
ProtectSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Subnet
Value: !Sub 'Protect'
GroupDescription: Protect Security Group
SecurityGroupIngress:
# Public Subnet AZa
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: !Sub '${NwSeg}.0/27'
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: !Sub '${NwSeg}.0/27'
- IpProtocol: udp
FromPort: 80
ToPort: 80
CidrIp: !Sub '${NwSeg}.0/27'
- IpProtocol: udp
FromPort: 443
ToPort: 443
CidrIp: !Sub '${NwSeg}.0/27'
# Public Subnet AZc
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: !Sub '${NwSeg}.32/27'
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: !Sub '${NwSeg}.32/27'
- IpProtocol: udp
FromPort: 80
ToPort: 80
CidrIp: !Sub '${NwSeg}.32/27'
- IpProtocol: udp
FromPort: 443
ToPort: 443
CidrIp: !Sub '${NwSeg}.32/27'
# Protect Subnet AZa
- IpProtocol: tcp
FromPort: 0
ToPort: 65535
CidrIp: !Sub '${NwSeg}.64/26'
# Protect Subnet AZc
- IpProtocol: tcp
FromPort: 0
ToPort: 65535
CidrIp: !Sub '${NwSeg}.128/26'
SecurityGroupEgress:
# Public Subnet AZa / AZc
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
# Protect Subnet AZa
- IpProtocol: tcp
FromPort: 0
ToPort: 65535
CidrIp: !Sub '${NwSeg}.64/26'
# Protect Subnet AZa
- IpProtocol: tcp
FromPort: 0
ToPort: 65535
CidrIp: !Sub '${NwSeg}.128/26'
# Private Subnet AZa
- IpProtocol: tcp
FromPort: 5432
ToPort: 5432
CidrIp: !Sub '${NwSeg}.192/28'
- IpProtocol: tcp
FromPort: 3306
ToPort: 3306
CidrIp: !Sub '${NwSeg}.192/28'
# Private Subnet AZc
- IpProtocol: tcp
FromPort: 5432
ToPort: 5432
CidrIp: !Sub '${NwSeg}.208/28'
- IpProtocol: tcp
FromPort: 3306
ToPort: 3306
CidrIp: !Sub '${NwSeg}.208/28'
VpcId: !Ref VPC
Private subnetに配置されるリソース向けのセキュリティグループ
Privateサブネットのセキュリティグループテンプレート
PrivateSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Subnet
Value: !Sub 'Private'
GroupDescription: Private Security Group
SecurityGroupIngress:
# Protect Subnet AZa
- IpProtocol: tcp
FromPort: 5432
ToPort: 5432
CidrIp: !Sub '${NwSeg}.64/26'
- IpProtocol: tcp
FromPort: 3306
ToPort: 3306
CidrIp: !Sub '${NwSeg}.64/26'
# Protect Subnet AZc
- IpProtocol: tcp
FromPort: 5432
ToPort: 5432
CidrIp: !Sub '${NwSeg}.128/26'
- IpProtocol: tcp
FromPort: 3306
ToPort: 3306
CidrIp: !Sub '${NwSeg}.128/26'
VpcId: !Ref VPC
UDPが許可されていないパターンありますが、リソース同士でUDPを使うことはあまりないかと思うので許可しておりません。インターネットのインバウンド系統はGoogleのQUICプロトコルのため許可しています。
VPC全体のテンプレート
Cloudformationテンプレート
AWSTemplateFormatVersion: 2010-09-09
Parameters:
SystemId:
Type: String
Description: System's ID used as a part of the AWS resource names
Env:
Type: String
Description: target environment
AllowedValues:
- dev
- stg
- prod
NwSeg:
Type: String
Description: network segment
AllowedValues:
- 10.0.0
- 10.0.1
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
CidrBlock: !Sub ${NwSeg}.0/24
EnableDnsHostnames: true
EnableDnsSupport: true
# AZa
PublicSubnetAZa:
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZa'
- Key: Subnet
Value: !Sub 'Public'
VpcId: !Ref VPC
CidrBlock: !Sub '${NwSeg}.0/27'
AvailabilityZone: ap-northeast-1a
ProtectSubnetAZa:
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZa'
- Key: Subnet
Value: !Sub 'Protect'
VpcId: !Ref VPC
CidrBlock: !Sub '${NwSeg}.64/26'
AvailabilityZone: ap-northeast-1a
PrivateSubnetAZa:
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZa'
- Key: Subnet
Value: !Sub 'Private'
VpcId: !Ref VPC
CidrBlock: !Sub '${NwSeg}.192/28'
AvailabilityZone: ap-northeast-1a
# AZc
PublicSubnetAZc:
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZc'
- Key: Subnet
Value: !Sub 'Public'
VpcId: !Ref VPC
CidrBlock: !Sub '${NwSeg}.32/27'
AvailabilityZone: ap-northeast-1c
ProtectSubnetAZc:
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZc'
- Key: Subnet
Value: !Sub 'Protect'
VpcId: !Ref VPC
CidrBlock: !Sub '${NwSeg}.128/26'
AvailabilityZone: ap-northeast-1c
PrivateSubnetAZc:
Type: AWS::EC2::Subnet
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZc'
- Key: Subnet
Value: !Sub 'Private'
VpcId: !Ref VPC
CidrBlock: !Sub '${NwSeg}.208/28'
AvailabilityZone: ap-northeast-1c
PublicSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Subnet
Value: !Sub 'Public'
GroupDescription: Public Security Group
SecurityGroupIngress:
# Internet
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: !Sub '0.0.0.0/0'
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: !Sub '0.0.0.0/0'
- IpProtocol: udp
FromPort: 80
ToPort: 80
CidrIp: !Sub '0.0.0.0/0'
- IpProtocol: udp
FromPort: 443
ToPort: 443
CidrIp: !Sub '0.0.0.0/0'
# Public Subnet AZa
- IpProtocol: tcp
FromPort: 0
ToPort: 65535
CidrIp: !Sub '${NwSeg}.0/27'
# Public Subnet AZc
- IpProtocol: tcp
FromPort: 0
ToPort: 65535
CidrIp: !Sub '${NwSeg}.32/27'
SecurityGroupEgress:
# Public Subnet AZa
- IpProtocol: tcp
FromPort: 0
ToPort: 65535
CidrIp: !Sub '${NwSeg}.0/27'
# Public Subnet AZc
- IpProtocol: tcp
FromPort: 0
ToPort: 65535
CidrIp: !Sub '${NwSeg}.32/27'
# Protect Subnet AZa
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: !Sub '${NwSeg}.64/26'
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: !Sub '${NwSeg}.64/26'
- IpProtocol: udp
FromPort: 80
ToPort: 80
CidrIp: !Sub '${NwSeg}.64/26'
- IpProtocol: udp
FromPort: 443
ToPort: 443
CidrIp: !Sub '${NwSeg}.64/26'
# Protect Subnet AZc
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: !Sub '${NwSeg}.128/26'
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: !Sub '${NwSeg}.128/26'
- IpProtocol: udp
FromPort: 80
ToPort: 80
CidrIp: !Sub '${NwSeg}.128/26'
- IpProtocol: udp
FromPort: 443
ToPort: 443
CidrIp: !Sub '${NwSeg}.128/26'
VpcId: !Ref VPC
ProtectSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Subnet
Value: !Sub 'Protect'
GroupDescription: Protect Security Group
SecurityGroupIngress:
# Public Subnet AZa
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: !Sub '${NwSeg}.0/27'
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: !Sub '${NwSeg}.0/27'
- IpProtocol: udp
FromPort: 80
ToPort: 80
CidrIp: !Sub '${NwSeg}.0/27'
- IpProtocol: udp
FromPort: 443
ToPort: 443
CidrIp: !Sub '${NwSeg}.0/27'
# Public Subnet AZc
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: !Sub '${NwSeg}.32/27'
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: !Sub '${NwSeg}.32/27'
- IpProtocol: udp
FromPort: 80
ToPort: 80
CidrIp: !Sub '${NwSeg}.32/27'
- IpProtocol: udp
FromPort: 443
ToPort: 443
CidrIp: !Sub '${NwSeg}.32/27'
# Protect Subnet AZa
- IpProtocol: tcp
FromPort: 0
ToPort: 65535
CidrIp: !Sub '${NwSeg}.64/26'
# Protect Subnet AZc
- IpProtocol: tcp
FromPort: 0
ToPort: 65535
CidrIp: !Sub '${NwSeg}.128/26'
SecurityGroupEgress:
# Public Subnet AZa / AZc
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
# Protect Subnet AZa
- IpProtocol: tcp
FromPort: 0
ToPort: 65535
CidrIp: !Sub '${NwSeg}.64/26'
# Protect Subnet AZa
- IpProtocol: tcp
FromPort: 0
ToPort: 65535
CidrIp: !Sub '${NwSeg}.128/26'
# Private Subnet AZa
- IpProtocol: tcp
FromPort: 5432
ToPort: 5432
CidrIp: !Sub '${NwSeg}.192/28'
- IpProtocol: tcp
FromPort: 3306
ToPort: 3306
CidrIp: !Sub '${NwSeg}.192/28'
# Private Subnet AZc
- IpProtocol: tcp
FromPort: 5432
ToPort: 5432
CidrIp: !Sub '${NwSeg}.208/28'
- IpProtocol: tcp
FromPort: 3306
ToPort: 3306
CidrIp: !Sub '${NwSeg}.208/28'
VpcId: !Ref VPC
PrivateSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Subnet
Value: !Sub 'Private'
GroupDescription: Private Security Group
SecurityGroupIngress:
# Protect Subnet AZa
- IpProtocol: tcp
FromPort: 5432
ToPort: 5432
CidrIp: !Sub '${NwSeg}.64/26'
- IpProtocol: tcp
FromPort: 3306
ToPort: 3306
CidrIp: !Sub '${NwSeg}.64/26'
# Protect Subnet AZc
- IpProtocol: tcp
FromPort: 5432
ToPort: 5432
CidrIp: !Sub '${NwSeg}.128/26'
- IpProtocol: tcp
FromPort: 3306
ToPort: 3306
CidrIp: !Sub '${NwSeg}.128/26'
VpcId: !Ref VPC
# VPC Internet rooting
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
VPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
PublicSubnetRouteTable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Subnet
Value: !Sub 'Public'
VpcId: !Ref VPC
RouteInternetGateway:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
RouteTableId: !Ref PublicSubnetRouteTable
# PublicSubnet Rooting
PublicSubnetRouteTableAssociationAZa:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicSubnetRouteTable
SubnetId: !Ref PublicSubnetAZa
PublicSubnetRouteTableAssociationAZc:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicSubnetRouteTable
SubnetId: !Ref PublicSubnetAZc
# AZa ProtectSubnet rooting
ElasticIPAZa:
Type: AWS::EC2::EIP
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZa'
- Key: Subnet
Value: !Sub 'Public'
Domain: vpc
NatGatewayAZa:
Type: AWS::EC2::NatGateway
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZa'
- Key: Subnet
Value: !Sub 'Public'
AllocationId: !GetAtt ElasticIPAZa.AllocationId
SubnetId: !Ref PublicSubnetAZa
DependsOn:
- ElasticIPAZa
ProtectSubnetRouteTableAZa:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZa'
- Key: Subnet
Value: !Sub 'Protect'
VpcId: !Ref VPC
RouteNatGatewayAZa:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGatewayAZa
RouteTableId: !Ref ProtectSubnetRouteTableAZa
ProtectSubnetRouteTableAssociationAZa:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref ProtectSubnetRouteTableAZa
SubnetId: !Ref ProtectSubnetAZa
# AZa ProtectSubnet rooting
ElasticIPAZc:
Type: AWS::EC2::EIP
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZc'
- Key: Subnet
Value: !Sub 'Public'
Domain: vpc
NatGatewayAZc:
Type: AWS::EC2::NatGateway
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZc'
- Key: Subnet
Value: !Sub 'Public'
AllocationId: !GetAtt ElasticIPAZc.AllocationId
SubnetId: !Ref PublicSubnetAZc
DependsOn:
- ElasticIPAZc
ProtectSubnetRouteTableAZc:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: SystemId
Value: !Sub '${SystemId}'
- Key: Env
Value: !Sub '${Env}'
- Key: Az
Value: !Sub 'AZc'
- Key: Subnet
Value: !Sub 'Protect'
VpcId: !Ref VPC
ProtectSubnetRouteAZc:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGatewayAZc
RouteTableId: !Ref ProtectSubnetRouteTableAZc
ProtectSubnetRouteTableAssociationAZc:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref ProtectSubnetRouteTableAZc
SubnetId: !Ref ProtectSubnetAZc
AppRunnerEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
PrivateDnsEnabled: true
SecurityGroupIds:
- !Ref ProtectSecurityGroup
ServiceName: !Sub 'com.amazonaws.${AWS::Region}.apprunner'
SubnetIds:
- !Ref ProtectSubnetAZa
- !Ref ProtectSubnetAZc
VpcEndpointType: 'Interface'
VpcId: !Ref VPC
Outputs:
VPC:
Value: !Ref VPC
Export:
Name: !Sub '${SystemId}-${Env}-VPC'
PublicSubnetAZa:
Value: !Ref PublicSubnetAZa
Export:
Name: !Sub '${SystemId}-${Env}-PublicSubnetAZa'
ProtectSubnetAZa:
Value: !Ref ProtectSubnetAZa
Export:
Name: !Sub '${SystemId}-${Env}-ProtectSubnetAZa'
PrivateSubnetAZa:
Value: !Ref PrivateSubnetAZa
Export:
Name: !Sub '${SystemId}-${Env}-PrivateSubnetAZa'
PublicSubnetAZc:
Value: !Ref PublicSubnetAZc
Export:
Name: !Sub '${SystemId}-${Env}-PublicSubnetAZc'
ProtectSubnetAZc:
Value: !Ref ProtectSubnetAZc
Export:
Name: !Sub '${SystemId}-${Env}-ProtectSubnetAZc'
PrivateSubnetAZc:
Value: !Ref PrivateSubnetAZc
Export:
Name: !Sub '${SystemId}-${Env}-PrivateSubnetAZc'
PublicSecurityGroup:
Value: !Ref PublicSecurityGroup
Export:
Name: !Sub '${SystemId}-${Env}-PublicSecurityGroup'
ProtectSecurityGroup:
Value: !Ref ProtectSecurityGroup
Export:
Name: !Sub '${SystemId}-${Env}-ProtectSecurityGroup'
PrivateSecurityGroup:
Value: !Ref PrivateSecurityGroup
Export:
Name: !Sub '${SystemId}-${Env}-PrivateSecurityGroup'
IAM Roleの作成
AWSを使うときの一番の難所であるIAMについてAppRunnerの周りで使用するRoleを簡単に解説します。 (IAMが一番の難所なんしょ?なんしょだけに)
IAMと権限周りを簡単に説明すると
- IAM User
- 個人のアカウント(IAM ユーザーもAWSのリソースの一つのため1アカウントにつき1AWSアカウントのみ紐づく)
- IAM GroupやIAM Policyを複数付与可能
- IAM Group
- 複数人を一つのグループにまとめることが可能
- グループに対してIAM Policyを付与することで複数人に権限を与えることが可能
- IAM Policy
- 公式ドキュメントではアイデンティティベースポリシーと記載されている
- ピカチュウがレベルアップしたら10万ボルトが使えるように、IAM Policyは操作する人に権限を与えるイメージ
- IAM Role
- ユーザーや各AWSをリソースがRoleにスイッチロールするとそのロールの権限で操作できるようになる
- AWSアカウントを複数持っているが、IAMユーザーを1つにしたい場合、別AWSアカウントにあるRoleにスイッチロールすることで別AWSアカウントを操作できるようになる(後述するRoleのリソースベースポリシーの設定が必要)
- リソースベースポリシー
- リソースベースポリシーと呼ばれているが、サービスごとに名称が違っている
- S3ならバケットポリシー、API Gatewayならリソースポリシー、IAM Roleなら信頼関係ポリシーなど呼ばれる
- JSONで許可するやつ(JSONドキュメントやポリシードキュメントと言ったり)にPrincipalというプロパティがあればだいたいリソースベースポリシー
- ピカチュウがサトシの言うことは聞いてロケット団の言うことは聞かないように、操作される側が操作する側を許可不許可を指定するもの
PassRole - 現在のロールを操作先のAWSリソースにロールを渡すイメージ
- 例えばマネジメントコンソールでCloudformationでStackを作るときに実行するRoleを指定する
- リソースベースポリシーと呼ばれているが、サービスごとに名称が違っている
AppRunnerがコンテナ立ち上げ時に使用するAppRunnerBuildRole
- ビルド時は
build.apprunner.amazonaws.com
がECRのコンテナを取得する- そのため信頼関係は
apprunner.amazonaws.com
的なものではなくbuild.apprunner.amazonaws.com
がスイッチロールする許可を与える
- そのため信頼関係は
- ECRをPullするだけなので、この機能のために用意されたマネジードポリシーを利用する
- Githubにアクセスするために権限必要かどうかは別のサイトをご覧ください
AppRunnerBuildRoleテンプレート
AppRunnerBuildRole:
Type: AWS::IAM::Role
Properties:
RoleName: AppRunnerBuildRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSAppRunnerServicePolicyForECRAccess
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- build.apprunner.amazonaws.com
Action: sts:AssumeRole
Path: /
AppRunner内で使用しているFargateにアタッチするAppRunnerServiceRole(アプリ内でAWS-SDKを使う時に使用)
- AppRunnerのタスクは
tasks.apprunner.amazonaws.com
というエンドポイントのため、信頼関係をtasks.apprunner.amazonaws.com
にしてスイッチロールする許可を与える - アイデンティティベースポリシーは基本的に自分が使いたいサービスと権限を指定する
- 今回はDynamoDBのアイテムの挿入・更新・削除を指定してみた(テーブル名に特定のプレフィックスを持つテーブルに限定)
AppRunnerServiceRoleのテンプレート
AppRunnerServiceRole:
Type: AWS::IAM::Role
Properties:
RoleName: AppRunnerServiceRole
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- tasks.apprunner.amazonaws.com
Action: sts:AssumeRole
Path: /
DynamoDBItemAccessPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: DynamoDBItemAccessPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- dynamodb:BatchGetItem
- dynamodb:DescribeStream
- dynamodb:DescribeTable
- dynamodb:Get*
- dynamodb:Query
- dynamodb:Scan
- dynamodb:BatchWriteItem
- dynamodb:DeleteItem
- dynamodb:UpdateItem
- dynamodb:PutItem
Resource:
- !Sub 'arn:aws:dynamodb:${AWS::Region}:*:table/${SystemId}*'
Roles:
- !Ref AppRunnerServiceRole
CodePipelineやCodeBuild上でAppRunnerのデプロイを行うために必要な権限を与えたCodePipelineServiceRole
- CodePipelineとCodeBuildに明示的にロールを指定しており、CloudformationはCodeBuild上で実行するAWS-CDKによりPassRoleされるため信頼関係に追加
- ビルドに必要そうなCodeファミリーの操作権限とビルド時にメトリクスやログを出力するためにCloudWatch周りの権限を付与
- 残りの権限はAppRunnerで使用するコンテナのビルドやAppRunnerのデプロイのために使用
- 手動で作ったPolicyは一時的なビルド資源置き場のS3やAppRunnerのVPC Connectorを作る権限を持つServiceLinkedRoleを作る権限を付与している
本当はもっと権限削ったほうがいいんだろうけどポリシー作るのがめんどくさくて。。。
CodePipelineServiceRoleのテンプレート
AppRunnerServiceRole:
Type: AWS::IAM::Role
Properties:
RoleName: AppRunnerServiceRole
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- tasks.apprunner.amazonaws.com
Action: sts:AssumeRole
Path: /
DynamoDBItemAccessPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: DynamoDBItemAccessPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- dynamodb:BatchGetItem
- dynamodb:DescribeStream
- dynamodb:DescribeTable
- dynamodb:Get*
- dynamodb:Query
- dynamodb:Scan
- dynamodb:BatchWriteItem
- dynamodb:DeleteItem
- dynamodb:UpdateItem
- dynamodb:PutItem
Resource:
- !Sub 'arn:aws:dynamodb:${AWS::Region}:*:table/${SystemId}*'
Roles:
- !Ref AppRunnerServiceRole
IAM全体のテンプレート
Cloudformationテンプレート
AWSTemplateFormatVersion: 2010-09-09
Parameters:
SystemId:
Type: String
Description: System's ID used as a part of the AWS resource names
Resources:
# https://docs.aws.amazon.com/ja_jp/apprunner/latest/dg/security_iam_service-with-iam.html
AppRunnerBuildRole:
Type: AWS::IAM::Role
Properties:
RoleName: AppRunnerBuildRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSAppRunnerServicePolicyForECRAccess
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- build.apprunner.amazonaws.com
Action: sts:AssumeRole
Path: /
AppRunnerServiceRole:
Type: AWS::IAM::Role
Properties:
RoleName: AppRunnerServiceRole
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- tasks.apprunner.amazonaws.com
Action: sts:AssumeRole
Path: /
DynamoDBItemAccessPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: DynamoDBItemAccessPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- dynamodb:BatchGetItem
- dynamodb:DescribeStream
- dynamodb:DescribeTable
- dynamodb:Get*
- dynamodb:Query
- dynamodb:Scan
- dynamodb:BatchWriteItem
- dynamodb:DeleteItem
- dynamodb:UpdateItem
- dynamodb:PutItem
Resource:
- !Sub 'arn:aws:dynamodb:${AWS::Region}:*:table/${SystemId}*'
Roles:
- !Ref AppRunnerServiceRole
CodePipelineServiceRole:
Type: AWS::IAM::Role
Properties:
RoleName: CodePipelineServiceRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AWSCodePipelineFullAccess
- arn:aws:iam::aws:policy/AWSCodeBuildAdminAccess
- arn:aws:iam::aws:policy/AWSCodeCommitFullAccess
- arn:aws:iam::aws:policy/AWSCodeDeployFullAccess
- arn:aws:iam::aws:policy/CloudWatchFullAccess
- arn:aws:iam::aws:policy/CloudWatchLogsFullAccess
- arn:aws:iam::aws:policy/CloudWatchEventsFullAccess
- arn:aws:iam::aws:policy/AWSCloudFormationFullAccess
- arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser
- arn:aws:iam::aws:policy/AWSAppRunnerFullAccess
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- codepipeline.amazonaws.com
- codebuild.amazonaws.com
- codedeploy.amazonaws.com
- cloudformation.amazonaws.com
Action: sts:AssumeRole
Path: /
CodePipelineServicePolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: CodePipelineServicePolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- s3:PutObject
- s3:PutObjectAcl
- s3:GetObject
- s3:GetObjectVersion
- s3:GetBucketVersioning
- s3:ListBucket
Resource:
- !Sub arn:aws:s3:::${SystemId}-*-temporary/*
- Effect: Allow
Action:
- iam:GetRole
- iam:PassRole
Resource:
- '*'
# AWSAppRunnerFullAccessにはCreateServiceLinkedRoleがあるが、VPCコネクタで使うサービスロールを作る権限がない
# https://repost.aws/questions/QU6Pp08CACTf6hX5FRHhhdDw/missing-resource-permission-in-aws-app-runner-full-access-causes-failure-when-calling-the-create-vpc-connector-operation
- Effect: Allow
Action:
- iam:CreateServiceLinkedRole
Resource:
- !Sub 'arn:aws:iam::${AWS::AccountId}:role/aws-service-role/networking.apprunner.amazonaws.com/AWSServiceRoleForAppRunnerNetworking'
Roles:
- !Ref CodePipelineServiceRole
Outputs:
AppRunnerBuildRoleArn:
Value: !GetAtt AppRunnerBuildRole.Arn
Export:
Name: AppRunnerBuildRoleArn
AppRunnerServiceRoleArn:
Value: !GetAtt AppRunnerServiceRole.Arn
Export:
Name: AppRunnerServiceRoleArn
CodePipelineServiceRoleArn:
Value: !GetAtt CodePipelineServiceRole.Arn
Export:
Name: CodePipelineServiceRoleArn
Stack分割
Stackに関しては図のように分割を行った
- 黄色い背景はAWS-CDKで構築
- 環境ごとに違ったりするため、if文やループ文などを手軽に使いたいため
- 実行時にパラメーターを挿入しやすい(今回はAppRunnerにCodeCommitのコミットハッシュをもとにECRのバージョンを指定したかった)
- IAMとCDKのBootstrapは環境ごとというより、AWSアカウントに対して1つのリソースにすべきだと思ったので、全環境で1つのStackにした
- ネットワーク系とリポジトリ系は一つのシステムで複数コンテナ(Web画面とバッチ処理、APIとか?)を扱う可能性があるため独立させている
- 1VPCに複数のAppRunnerをデプロイする可能性がある
- 複数のAppRunnerがあるということはリポジトリやECRが複数になる可能性が高い
実際にデプロイしてみる
- 事前準備
- 操作するユーザーには上記Stack分割で出てきたリソースの作成権限を与えてください(わからなければAdministratorAccessポリシーを検討してください)
- 操作するユーザーがCodeCommitやCDKを扱えるようにアクセスキー・シークレットキーの発行をしてください
-
CloudFormationにアクセスしてStackを3つ作成する
- 「Stackの作成」
- 「テンプレートの準備完了」→「テンプレートファイルのアップロード」で「aws/template/iam.yml」をアップロード
- スタックの名前は適当に(自分はapprunner-nuxt3-iamにしています)
- SystemIdは適当で結構ですが今後出てくる項目は統一してください(自分はapprunner-nuxt3にしています)
- 次へ→送信と進みデプロイ
- 同様の作業を「/aws/template/repository.yml」や「/aws/template/vpc.yml」で行う(Envはdev、NwSegはお好みで)
-
出来上がったCodeCommitにGithubの資源をPushする
-
パイプラインをCDKでデプロイする
-
あとは自動的にパイプラインがコンテナをビルドしてAppRunnerをデプロイする(およそ10分~15分)
環境を複製する
今回、構築する環境はdev環境、stg環境、prod環境を想定してテンプレートを作りました。
VPC stackとのrepository stackのENVとパイプラインの作成コマンドの環境名が一致していればそれぞれの環境に対応してAppRunnerが構築されます。
またCodeCommitのコミットによるパイプラインの実行を設定していますが、ブランチによって反映される環境が異なっていますのでご注意ください
mainブランチ → dev環境
stgブランチ → stg環境
prodブランチ → prod環境
小学生並みの感想
めちゃくちゃ簡単にAPIと画面資源をデプロイできるようになったので、Stackのテンプレートを使い回せば15分程度で環境を沢山生やして確認ができるようになった。
AppRunnerは偉大。。。Lambdaと違ってレスポンスタイムも速い。(API Gateway + Lambda(Node.js)で100ms~500msに対してAppRunnerは10ms・・・)
基本的なコンテナアプリケーションの実行には問題なく使えると思った。
個人的なAppRunnerを使う点での問題点は以下が挙げられる
- AWS WAFが使えない(Apprunnerにアタッチできない)
- IAM Policyによる設定の不許可を制御できない(パブリック公開に設定したAppRunnerを禁止するなど)
- デプロイが遅い(大体7分ぐらい)
- AWS-CDKのサポートが遅れている
- Amazon SNSやEventBridgeのイベント駆動に非対応(特定の時間になったら分析開始とかできたら嬉しい)
最後に
わからないところ・誤字・間違いあれば是非コメントください。。。
ソースコードにはコメント残したつもりですが、言葉足らずという指摘結構いただくので・・・
また関連記事も書く予定です