AWSTemplateFormatVersion: "2010-09-09"
Description: CloudTech ECS Demo
#======================
# パラメーター
#======================
Parameters:
# プロジェクト名を入力する。各リソースのNameタグの値となる。
EnvironmentName:
Description: An environment name that is prefixed to resource names
Type: String
# VPCのCIDRレンジ
VpcCIDR:
Description: Please enter the IP range (CIDR notation) for this VPC
Type: String
Default: 10.99.0.0/16
# パブリックサブネット1
PublicSubnet1CIDR:
Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone
Type: String
Default: 10.99.10.0/24
# パブリックサブネット2
PublicSubnet2CIDR:
Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone
Type: String
Default: 10.99.11.0/24
# プライベートサブネット1
PrivateSubnet1CIDR:
Description: Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone
Type: String
Default: 10.99.20.0/24
# プライベートサブネット2
PrivateSubnet2CIDR:
Description: Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone
Type: String
Default: 10.99.21.0/24
# Cluster名を入力する
ClusterName:
Description: Please enter the Cluster name
Type: String
# データベースに接続するパスワードを入力する
DatabasePassword:
Type: String
Description: Database password
NoEcho: "true"
# キーペアの名前
Keypairname:
Type: AWS::EC2::KeyPair::KeyName
Description: Enter keypair name
# ECSコンテナインスタンスの最新のAMIのIDを取得する
ApplicationImageId:
Type: AWS::SSM::Parameter::Value<String>
Default: /aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id
#======================
# リソース
#======================
Resources:
#======================
##### ECR作成 #####
#======================
TodobackendRepository:
Type: AWS::ECR::Repository
Properties:
RepositoryName: cloudtech/todobackend
LifecyclePolicy:
LifecyclePolicyText: |
{
"rules": [
{
"rulePriority": 1,
"description": "Untagged images",
"selection": {
"tagStatus": "untagged",
"countType": "sinceImagePushed",
"countUnit": "days",
"countNumber": 7
},
"action": {"type": "expire"
}
}
]
}
#======================
##### VPC作成 #####
#======================
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCIDR
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Ref EnvironmentName
# インターネットゲートウェイ作成
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Ref EnvironmentName
# インターネットゲートウェイをVPCにアタッチする
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
# パブリックサブネット1を作成
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [ 0, !GetAZs '' ]
CidrBlock: !Ref PublicSubnet1CIDR
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Public Subnet (AZ1)
# パブリックサブネット2を作成
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [ 1, !GetAZs '' ]
CidrBlock: !Ref PublicSubnet2CIDR
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Public Subnet (AZ2)
# プライベートサブネット1を作成
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [ 0, !GetAZs '' ]
CidrBlock: !Ref PrivateSubnet1CIDR
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Private Subnet (AZ1)
# プライベートサブネット2を作成
PrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [ 1, !GetAZs '' ]
CidrBlock: !Ref PrivateSubnet2CIDR
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Private Subnet (AZ2)
# ルートテーブル(パブリックサブネット用共通)作成
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Public Routes
DefaultPublicRoute:
Type: AWS::EC2::Route
DependsOn: InternetGatewayAttachment
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet1
PublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet2
# ルートテーブル(プライベートサブネット用共通)作成
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Private Routes
PrivateSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet1
PrivateSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet2
#NATGatewayをパブリックサブネットに作成する
NatGatewayPublic1:
Type: AWS::EC2::NatGateway
DependsOn: EIP
Properties:
AllocationId:
Fn::GetAtt:
- EIP
- AllocationId
SubnetId: !Ref PublicSubnet1
EIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
#NATGateway用のルーティングをプライベートサブネットのルートテーブルに追加する
PrivateRoute:
Type: AWS::EC2::Route
DependsOn: NatGatewayPublic1
Properties:
RouteTableId: !Ref PrivateRouteTable
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGatewayPublic1
#======================
##### ECS作成 #####
#======================
Cluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: !Ref ClusterName
#======================
##### RDS作成 #####
#======================
ApplicationDatabase:
Type: AWS::RDS::DBInstance
Properties:
Engine: MySQL
EngineVersion: 8.0
DBInstanceClass: db.t2.micro
AllocatedStorage: 10
StorageType: gp2
MasterUsername: todobackend
MasterUserPassword:
Ref: DatabasePassword
DBName: todobackend
VPCSecurityGroups:
- !Ref ApplicationDatabaseSecurityGroup
DBSubnetGroupName: !Ref ApplicationDatabaseSubnetGroup
MultiAZ: "false"
AvailabilityZone: !Sub ${AWS::Region}a
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-db
ApplicationDatabaseSubnetGroup:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription: Application Database Subnet Group
SubnetIds:
- !Ref PrivateSubnet1
- !Ref PrivateSubnet2
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-db-subnet-group
# セキュリティグループ(RDS)
ApplicationDatabaseSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub ${AWS::StackName} Application Database Security Group
VpcId: !Ref VPC
SecurityGroupEgress:
- IpProtocol: icmp
FromPort: -1
ToPort: -1
CidrIp: 192.0.2.0/32
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-db-sg
ApplicationToApplicationDatabaseIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
IpProtocol: tcp
FromPort: 3306
ToPort: 3306
GroupId: !Ref ApplicationDatabaseSecurityGroup
SourceSecurityGroupId: !Ref ApplicationAutoscalingSecurityGroup
ApplicationToApplicationDatabaseEgress:
Type: AWS::EC2::SecurityGroupEgress
Properties:
IpProtocol: tcp
FromPort: 3306
ToPort: 3306
GroupId: !Ref ApplicationAutoscalingSecurityGroup
DestinationSecurityGroupId: !Ref ApplicationDatabaseSecurityGroup
# セキュリティグループ(EC2)
ApplicationAutoscalingSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub ${AWS::StackName} Application Autoscaling Security Group
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0
SecurityGroupEgress:
- IpProtocol: udp
FromPort: 53
ToPort: 53
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
#======================
##### ALB作成 #####
#======================
ApplicationServiceTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Protocol: HTTP
Port: 8000
VpcId: !Ref VPC
TargetGroupAttributes:
- Key: deregistration_delay.timeout_seconds
Value: 30
ApplicationLoadBalancerHttpListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
LoadBalancerArn: !Ref ApplicationLoadBalancer
Protocol: HTTP
Port: 80
DefaultActions:
- TargetGroupArn: !Ref ApplicationServiceTargetGroup
Type: forward
ApplicationLoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Scheme: internet-facing
Subnets:
- !Ref PublicSubnet1
- !Ref PublicSubnet2
SecurityGroups:
- !Ref ApplicationLoadBalancerSecurityGroup
LoadBalancerAttributes:
- Key: idle_timeout.timeout_seconds
Value : 30
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-alb
# セキュリティグループ(ALB)
ApplicationLoadBalancerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Application Load Balancer Security Group
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value:
Fn::Sub: ${AWS::StackName}-alb-sg
# セキュリティグループ(EC2はALBからの通信を許可)
ApplicationLoadBalancerToApplicationIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
IpProtocol: tcp
FromPort: 32768
ToPort: 60999
GroupId: !Ref ApplicationAutoscalingSecurityGroup
SourceSecurityGroupId: !Ref ApplicationLoadBalancerSecurityGroup
# セキュリティグループ(ALBはEC2への通信を許可)
ApplicationLoadBalancerToApplicationEgress:
Type: AWS::EC2::SecurityGroupEgress
Properties:
IpProtocol: tcp
FromPort: 32768
ToPort: 60999
GroupId: !Ref ApplicationLoadBalancerSecurityGroup
DestinationSecurityGroupId: !Ref ApplicationAutoscalingSecurityGroup
#======================
##### AutoScaling作成 #####
#======================
# オートスケーリング
ApplicationAutoscaling:
Type: AWS::AutoScaling::AutoScalingGroup
CreationPolicy:
ResourceSignal:
Count: 0
Timeout: PT5M
Properties:
LaunchConfigurationName: !Ref ApplicationAutoscalingLaunchConfiguration
MinSize: 0
MaxSize: 4
DesiredCapacity: 0
VPCZoneIdentifier:
- !Ref PrivateSubnet1
- !Ref PrivateSubnet2
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-ApplicationAutoscaling-instance
PropagateAtLaunch: "true"
# 起動設定
ApplicationAutoscalingLaunchConfiguration:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
ImageId: !Ref ApplicationImageId
InstanceType: t2.micro
KeyName: !Ref Keypairname
IamInstanceProfile: !Ref ApplicationAutoscalingInstanceProfile
SecurityGroups:
- !GetAtt "ApplicationAutoscalingSecurityGroup.GroupId"
UserData:
Fn::Base64: !Sub
- |
#!/bin/bash
echo ECS_CLUSTER=${CLUSTERNAME} > /etc/ecs/ecs.config
mkdir -p /data/public
chown -R 1000:1000 /data
- {
CLUSTERNAME: !Ref ClusterName
}
# インスタンスプロファイル
ApplicationAutoscalingInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Roles:
- Ref: ApplicationAutoscalingInstanceRole
# ロール指定
ApplicationAutoscalingInstanceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName: ECSContainerInstancePermissions
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- ecs:RegisterContainerInstance
- ecs:DeregisterContainerInstance
- ecs:UpdateContainerInstancesState
Resource: !Sub ${Cluster.Arn}
- Effect: Allow
Action:
- ecs:DiscoverPollEndpoint
- ecs:Submit*
- ecs:Poll
- ecs:StartTelemetrySession
Resource: "*"
- Effect: Allow
Action:
- ecr:BatchCheckLayerAvailability
- ecr:BatchGetImage
- ecr:GetDownloadUrlForLayer
- ecr:GetAuthorizationToken
Resource: "*"
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
- logs:DescribeLogStreams
Resource: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/${AWS::StackName}*
#======================
# アウトプット
#======================
Outputs:
PublicURL:
Description: Public DNS name of Application Load Balancer
Value: !Sub ${ApplicationLoadBalancer.DNSName}
EnvironmentName=cloudtech
ClusterName=cloudtech-cluster
DatabasePassword=rds-database-secret-password
Keypairname=keypair01
DesiredCount=1
■コマンド
aws cloudformation deploy --template-file 6.EC2.yml --stack-name cloudtech-app --parameter-overrides $(cat dev.cfg) --capabilities CAPABILITY_NAMED_IAM --no-execute-changeset