内容
下記環境をCFnで作成した備忘録
EC2はメンテ用でここでDockerFileからImageを作成してECRリポジトリにアップロードする。
CFnでEC2作成時、ユーザーデータでコンテナイメージ作成、ECRにPushを行なっている。
ECRはプライベートリポジトリでEC2やECSからはVPCエンドポイント経由で接続する。
構築方法
下記のスタックを順番にCFnで作成する。
ファイル | 内容 |
---|---|
1-CFn-Base.yml | VPC、サブネット、セキュリティグループなど作成 |
2-CFn-ECR.yml | プライベートECRリポジトリ作成 |
3-CFn-IAM.yml | 必要なIAMロール、IAMポリシー作成 |
4-CFn-Vpce.yml | VPCエンドポイント作成 |
5-CFn-EC2.yml | 管理用のEC2作成 |
6-CFn-ALB.yml | ALB、ターゲットグループ作成 |
7-CFn-ECS.yml | ECSタスク定義、ECSクラスタ、ECSサービス作成 |
手動でやる箇所
-
1-CFn-Base.yml
のセキュリティグループのSSH接続許可が0.0.0.0/0となっているので必要に応じて絞る -
5-CFn-EC2.yml
のキーペアKeyName
を指定する
AWS::EC2::KeyPair
で指定出来るが既存のキーペアを使用する想定のため手動 -
5-CFn-EC2.yml
のAWS_ACCOUNT_ID=
を指定する - 必要に応じて
5-CFn-EC2.yml
のDockerfile
作成の箇所を修正する
取り敢えずecho FROM nginx > Dockerfile
でnginxのイメージを書き込んでいるだけである。
テンプレートファイル
1-CFn-Base.yml
1-CFn-Base.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: Network - VPC/Subnet/RouteTable/IGW/SecurityGroup
Resources:
#### VPC Setting ####
Vpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsHostnames: true
EnableDnsSupport: true
InstanceTenancy: default
Tags:
- Key: Name
Value: Vpc
#### Subnet Setting ####
### IGW Setting ###
Igw:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: igw
VpcgwAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId:
Ref: Vpc
InternetGatewayId:
Ref: Igw
### Public Subnet Setting ###
## Subnet Setting ##
SubnetPublic1A:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.0.0.0/24
VpcId:
Ref: Vpc
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: ""
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: subnet-public-1a
- Key: Type
Value: Public
SubnetPublic1C:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.0.1.0/24
VpcId:
Ref: Vpc
AvailabilityZone:
Fn::Select:
- 1
- Fn::GetAZs: ""
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: subnet-public-1c
- Key: Type
Value: Public
## Route Table Setting ##
RoutePublic1:
Type: AWS::EC2::RouteTable
Properties:
VpcId:
Ref: Vpc
Tags:
- Key: Name
Value: route-public1
RoutePublic1Association1A:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId:
Ref: RoutePublic1
SubnetId:
Ref: SubnetPublic1A
RoutePublic1Association1C:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId:
Ref: RoutePublic1
SubnetId:
Ref: SubnetPublic1C
RoutePublic1Default:
Type: AWS::EC2::Route
Properties:
RouteTableId:
Ref: RoutePublic1
DestinationCidrBlock: 0.0.0.0/0
GatewayId:
Ref: Igw
DependsOn:
- VpcgwAttachment
### Public Subnet Setting ###
## Subnet Setting ##
SubnetPrivate1A:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.0.2.0/24
VpcId:
Ref: Vpc
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: ""
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: subnet-private-1a
- Key: Type
Value: Isolated
SubnetPrivate1C:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.0.3.0/24
VpcId:
Ref: Vpc
AvailabilityZone:
Fn::Select:
- 1
- Fn::GetAZs: ""
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: subnet-private-1c
- Key: Type
Value: Isolated
## Route Table Setting ##
RoutePrivate1:
Type: AWS::EC2::RouteTable
Properties:
VpcId:
Ref: Vpc
Tags:
- Key: Name
Value: route-private1
RoutePrivate1Association1A:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId:
Ref: RoutePrivate1
SubnetId:
Ref: SubnetPrivate1A
RoutePrivate1Association1C:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId:
Ref: RoutePrivate1
SubnetId:
Ref: SubnetPrivate1C
#### Security Group Setting ####
### for public subnet ###
SgPublic:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Security group for public
GroupName: public
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
Description: Allow all outbound traffic by default
IpProtocol: "-1"
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
Description: from http from my network
FromPort: 80
IpProtocol: tcp
ToPort: 80
- CidrIp: 0.0.0.0/0
Description: Allow ssh from my network
IpProtocol: tcp
FromPort: 22
ToPort: 22
Tags:
- Key: Name
Value: sg-public
VpcId:
Ref: Vpc
### for private subnet ###
SgPrivate:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Security group for private
GroupName: private
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
Description: Allow all outbound traffic by default
IpProtocol: "-1"
Tags:
- Key: Name
Value: sg-private
VpcId:
Ref: Vpc
### for VPC Endpoint ###
SgVpce:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Security group of VPC Endpoint
GroupName: vpce
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
Description: Allow all outbound traffic by default
IpProtocol: "-1"
Tags:
- Key: Name
Value: sg-vpce
VpcId:
Ref: Vpc
### Secuity Group Link ####
## Public -> Private ##
SgPrivateFromPublic:
Type: AWS::EC2::SecurityGroupIngress
Properties:
IpProtocol: tcp
Description: HTTP for Public
FromPort: 80
GroupId:
Fn::GetAtt:
- SgPrivate
- GroupId
SourceSecurityGroupId:
Fn::GetAtt:
- SgPublic
- GroupId
ToPort: 80
## Public -> VPC endpoint ##
SgVpceFromSgPublic:
Type: AWS::EC2::SecurityGroupIngress
Properties:
IpProtocol: tcp
Description: HTTPS for Public
FromPort: 443
GroupId:
Fn::GetAtt:
- SgVpce
- GroupId
SourceSecurityGroupId:
Fn::GetAtt:
- SgPublic
- GroupId
ToPort: 443
## Private -> VPC endpoint ##
SgVpceFromSgPrivate:
Type: AWS::EC2::SecurityGroupIngress
Properties:
IpProtocol: tcp
Description: HTTPS for Private
FromPort: 443
GroupId:
Fn::GetAtt:
- SgVpce
- GroupId
SourceSecurityGroupId:
Fn::GetAtt:
- SgPrivate
- GroupId
ToPort: 443
##### Output parameters for cross stack #####
Outputs:
### VPC ###
VPCId:
Value: !Ref Vpc
Export:
Name: VPCId
### Subnet ###
SubnetPublic1AId:
Value: !Ref SubnetPublic1A
Export:
Name: SubnetPublic1AId
SubnetPublic1CId:
Value: !Ref SubnetPublic1C
Export:
Name: SubnetPublic1CId
SubnetPrivate1AId:
Value: !Ref SubnetPrivate1A
Export:
Name: SubnetPrivate1AId
SubnetPrivate1CId:
Value: !Ref SubnetPrivate1C
Export:
Name: SubnetPrivate1CId
### Security Group ###
SgPublicId:
Value: !Ref SgPublic
Export:
Name: SgPublicId
SgPrivateId:
Value: !Ref SgPrivate
Export:
Name: SgPrivateId
SgVpceId:
Value: !Ref SgVpce
Export:
Name: SgVpceId
### Route Table ###
RoutePublic1Id:
Value: !Ref RoutePublic1
Export:
Name: RoutePublic1Id
RoutePrivate1Id:
Value: !Ref RoutePrivate1
Export:
Name: RoutePrivate1Id
2-CFn-ECR.yml
2-CFn-ECR.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: Create Private ECR Repository
#### ECR Repository ####
Resources:
ECRRepository:
Type: AWS::ECR::Repository
Properties:
RepositoryName: ecr-rep
ImageScanningConfiguration:
ScanOnPush: false
EncryptionConfiguration:
EncryptionType: "KMS"
3-CFn-IAM.yml
3-CFn-IAM.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: Create IAM Policy / IAM Role
#### IAM Policy for EC2 ####
Resources:
IAMRoleforEC2:
Type: AWS::IAM::Role
Properties:
RoleName: role-for-ec2
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- !Ref IAMPolicyforEC2
Tags:
- Key: Name
Value: role-for-ec2
DependsOn:
- IAMPolicyforEC2
InstanceProfileforEC2:
Type: 'AWS::IAM::InstanceProfile'
Properties:
InstanceProfileName: role-for-ec2
Roles:
- !Ref IAMRoleforEC2
IAMPolicyforEC2:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: access-to-ecr
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- ecr:GetDownloadUrlForLayer
- ecr:GetRepositoryPolicy
- ecr:DescribeRepositories
- ecr:ListImages
- ecr:DescribeImages
- ecr:BatchGetImage
- ecr:InitiateLayerUpload
- ecr:UploadLayerPart
- ecr:CompleteLayerUpload
- ecr:PutImage
- ecr:GetAuthorizationToken
- ecr:ListImages
- ecr:BatchCheckLayerAvailability
Resource: "*"
ECSTaskExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: "ecs-task-exec-role"
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
Outputs:
InstanceProfileforEC2Id:
Value: !Ref InstanceProfileforEC2
Export:
Name: InstanceProfileforEC2Id
ECSTaskExecutionRoleId:
Value: !Ref ECSTaskExecutionRole
Export:
Name: ECSTaskExecutionRoleId
4-CFn-Vpce.yml
4-CFn-Vpce.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: Create VPC Endpoint
#### VPC Endpoint ####
Resources:
### for ECR Api ###
ECRApiEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcEndpointType: Interface
ServiceName: !Sub "com.amazonaws.${AWS::Region}.ecr.api"
VpcId: !ImportValue VPCId
SubnetIds:
- !ImportValue SubnetPrivate1AId
- !ImportValue SubnetPrivate1CId
SecurityGroupIds:
- !ImportValue SgVpceId
PrivateDnsEnabled: true
### for ECR dkr ###
ECRDkrEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcEndpointType: Interface
ServiceName: !Sub "com.amazonaws.${AWS::Region}.ecr.dkr"
VpcId: !ImportValue VPCId
SubnetIds:
- !ImportValue SubnetPrivate1AId
- !ImportValue SubnetPrivate1CId
SecurityGroupIds:
- !ImportValue SgVpceId
PrivateDnsEnabled: true
### for ECR s3 ###
ECRS3Endpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcEndpointType: Gateway
ServiceName: !Sub "com.amazonaws.${AWS::Region}.s3"
VpcId: !ImportValue VPCId
RouteTableIds:
- !ImportValue RoutePrivate1Id
### for cloudwatch ###
CloudWatchEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcEndpointType: Interface
ServiceName: !Sub "com.amazonaws.${AWS::Region}.logs"
VpcId: !ImportValue VPCId
SubnetIds:
- !ImportValue SubnetPrivate1AId
- !ImportValue SubnetPrivate1CId
SecurityGroupIds:
- !ImportValue SgVpceId
PrivateDnsEnabled: true
5-CFn-EC2.yml
5-CFn-EC2.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: Create EC2 environment
#### EC2 ####
Resources:
EC2:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-072bfb8ae2c884cc4
InstanceType: t2.micro
KeyName: xxxxxxxxxxxxxxxxxxxxxxxxxxx
NetworkInterfaces:
- AssociatePublicIpAddress: "true"
DeviceIndex: "0"
SubnetId: !ImportValue SubnetPublic1AId
GroupSet:
- !ImportValue SgPublicId
IamInstanceProfile: !ImportValue InstanceProfileforEC2Id
UserData: !Base64 |
#!/bin/bash
sudo su -
yum update -y
yum install -y docker
systemctl start docker
systemctl enable docker
cd ~
echo FROM nginx > Dockerfile
AWS_ACCOUNT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxx
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com
docker build -t ecr-rep .
docker tag ecr-rep:latest ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/ecr-rep:latest
docker push ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/ecr-rep:latest
Tags:
- Key: Name
Value: Maintenance-Server
6-CFn-ALB.yml
6-CFn-ALB.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: Create ALB and Target Group
#### ALB/Listener/Target Group ####
Resources:
### ALB ###
ExternalALB:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Type: application
Name: external-alb
Scheme: internet-facing
IpAddressType: ipv4
SecurityGroups:
- !ImportValue SgPublicId
Subnets:
- !ImportValue SubnetPublic1AId
- !ImportValue SubnetPublic1CId
Tags:
- Key: Name
Value: external-alb
### Target Group ###
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: elb-tg
TargetType: ip
Protocol: HTTP
ProtocolVersion: HTTP1
Port: 80
VpcId: !ImportValue VPCId
HealthCheckProtocol: HTTP
HealthCheckPath: "/health"
HealthCheckPort: traffic-port
Matcher:
HttpCode: "404"
### Listener ###
Listener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: forward
TargetGroupArn: !Ref TargetGroup
LoadBalancerArn: !Ref ExternalALB
Port: 80
Protocol: HTTP
#### Outputs paramerer for cross stack ####
Outputs:
TargetGroupId:
Value: !Ref TargetGroup
Export:
Name: TargetGroupId
7-CFn-ECS.yml
7-CFn-ECS.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: ECS
Resources:
### CloudWatch Log Group ###
ECSLogGroup:
Type: "AWS::Logs::LogGroup"
Properties:
LogGroupName: "/ecs/logs/sbcntr-backend-def"
### ECS Task Definition ###
ECStask:
Type: AWS::ECS::TaskDefinition
Properties:
RequiresCompatibilities:
- FARGATE
Cpu: 512
Memory: 1024
NetworkMode: awsvpc
Family: nginx-def
ExecutionRoleArn: !ImportValue ECSTaskExecutionRoleId
containerDefinitions:
- Name: nginx
Image: !Sub "${AWS::AccountId}.dkr.ecr.ap-northeast-1.amazonaws.com/ecr-rep:latest"
MemoryReservation: 512
PortMappings:
- containerPort: 80
protocol: tcp
Cpu: 256
Essential: true
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref ECSLogGroup
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: ecs
### ECS Cluster ###
ECSCluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: ecs-cluster
ClusterSettings:
-
Name: containerInsights
Value: enabled
### ECS Service ###
ECSService:
Type: AWS::ECS::Service
Properties:
LaunchType: FARGATE
TaskDefinition: !Ref ECStask
Cluster: !Ref ECSCluster
ServiceName: ecs-service
DesiredCount: 1
EnableECSManagedTags: True
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: DISABLED
SecurityGroups:
- !ImportValue SgPrivateId
Subnets:
- !ImportValue SubnetPrivate1AId
- !ImportValue SubnetPrivate1CId
HealthCheckGracePeriodSeconds: 60
LoadBalancers:
-
ContainerName: nginx
ContainerPort: 80
TargetGroupArn: !ImportValue TargetGroupId