Create CloudFormation Stack with VPC, Subnet, ALB, EC2, etc...
Phong Nguyen
Bài Lab này sẽ cung cấp CloudFormation Template tạo 1 VPC with 1 private và 1 public subnet trong mỗi AZ. Mỗi public subnet sẽ chứa 1 EC2 và được kết nối đến Application Load Balancer. VPC sẽ có Internet Gateway, Route Table.
Lưu ý
- AWS Region: US East (N. Virginia) us-east-1
Architecture
CloudFormation Template
AWSTemplateFormatVersion: 2010-09-09
Description: Create VPC, ALB, EC2 Stack
Parameters:
KeyName:
Description: Key Pair for EC2
Type: 'AWS::EC2::KeyPair::KeyName'
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: d-vpc-DVA-001
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: d-igw-DVA-001
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.1.0/24
AvailabilityZone: !Select [0, !GetAZs '']
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: d-vpc-DVA-001-subnet-public1
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.2.0/24
MapPublicIpOnLaunch: false
AvailabilityZone: !Select [0, !GetAZs '']
Tags:
- Key: Name
Value: d-vpc-DVA-001-subnet-private1
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.3.0/24
AvailabilityZone: !Select [1, !GetAZs '']
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: d-vpc-DVA-001-subnet-public2
PrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.4.0/24
AvailabilityZone: !Select [1, !GetAZs '']
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: d-vpc-DVA-001-subnet-private2
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: d-vpc-DVA-001-rtb-public
PublicRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicSubnetRouteTableAssociation1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet1
RouteTableId: !Ref PublicRouteTable
PublicSubnetRouteTableAssociation2:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet2
RouteTableId: !Ref PublicRouteTable
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: d-vpc-DVA-001-rtb-private
PrivateSubnetRouteTableAssociation1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnet1
RouteTableId: !Ref PrivateRouteTable
PrivateSubnetRouteTableAssociation2:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnet2
RouteTableId: !Ref PrivateRouteTable
#EC2 Instances
EC2Instance1:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-079db87dc4c10ac91
InstanceType: t2.micro
Tags:
- Key: Name
Value: d-ec2-DVA-web-server-01
SecurityGroupIds:
- !Ref EC2SecurityGroup
SubnetId: !Ref PublicSubnet1
KeyName: !Ref KeyName
UserData:
Fn::Base64: !Sub |
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<h1>Hello from $(hostname -f) in AZ A</h1>" > /var/www/html/index.html
EC2Instance2:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-079db87dc4c10ac91
InstanceType: t2.micro
Tags:
- Key: Name
Value: d-ec2-DVA-web-server-02
SecurityGroupIds:
- !Ref EC2SecurityGroup
SubnetId: !Ref PublicSubnet2
KeyName: !Ref KeyName
UserData:
Fn::Base64: !Sub |
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<h1>Hello from $(hostname -f) in AZ B</h1>" > /var/www/html/index.html
# EC2 and ALB Security Groups
ELBSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ELB Security Group
GroupName: d-sg-DVA-ALB
VpcId: !Ref VPC
Tags:
- Key: Name
Value: d-sg-DVA-ALB
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
EC2SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow access from ALB
GroupName: d-sg-DVA-web-server
VpcId: !Ref VPC
Tags:
- Key: Name
Value: d-sg-DVA-web-server
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId:
Fn::GetAtt:
- ELBSecurityGroup
- GroupId
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0
# Target Group, Listener and Application Load Balancer
EC2TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
HealthCheckIntervalSeconds: 30
HealthCheckProtocol: HTTP
HealthCheckTimeoutSeconds: 15
HealthyThresholdCount: 2
Matcher:
HttpCode: '200'
Name: d-tg-DVA-web-server
Port: 80
Protocol: HTTP
TargetGroupAttributes:
- Key: deregistration_delay.timeout_seconds
Value: '20'
Targets:
- Id: !Ref EC2Instance1
Port: 80
- Id: !Ref EC2Instance2
Port: 80
UnhealthyThresholdCount: 3
VpcId: !Ref VPC
ALBListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: forward
TargetGroupArn: !Ref EC2TargetGroup
LoadBalancerArn: !Ref ApplicationLoadBalancer
Port: 80
Protocol: HTTP
ApplicationLoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: d-alb-DVA-web-server-alb
Scheme: internet-facing
Subnets:
- !Ref PublicSubnet1
- !Ref PublicSubnet2
SecurityGroups:
- !GetAtt ELBSecurityGroup.GroupId
Mô tả các resource được tạo
VPC
- VPC CIDR:
10.0.0.0/16
- EnableDnsSupport:
true
- EnableDnsHostnames:
true
- VPC CIDR:
Subnets:
- Public Subnet 1 - in AZ a with CIDR 10.0.1.0/24.
- Public Subnet 2 - in AZ b with CIDR10.0.3.0/24.
- Private Subnet 1 - in AZ a with CIDR 10.0.2.0/24.
- Private Subnet 2 - in AZ b with CIDR 10.0.4.0/24
Internet Gateway: Attatch to VPC
Public Route Tables
- Route to Internet via Internet Gateway
- Routes traffic trong mạng 10.0.0.0/16
- Associate with 2 public subnet
Private Route Tables
- Routes traffic chỉ trong mạng 10.0.0.0/16
- Associate with 2 private subnet
EC2 Instances
- 2 EC2 Instances in public subnet with user data to install Apache web server.
- The Instances have a reference to EC2 Security group and KeyPair.
Security Groups:
- EC2 Security Group: Port 22 for SSH and Port 80 open to the Load Balancer.
- ELB Security Group: Port 80 open to everyone.
TargetGroup
Application Load Balancer
Deploying CloudFormation Template
- Copy nội dung Template phía trên và lưu lại với tên
VPC-ALB-EC2-Stack.yaml
hoặc tải file Tại đây - Tại CloudFormation Console -> Chọn Menu Stack -> Create stack
- Upload file
VPC-ALB-EC2-Stack.yaml
và nhấn Next - Nhập tên Stack:
VPC-ALB-EC2-Stack-{random-characters}
(Vis Stack name không được trùng trong cùng 1 Region). Chọn KeyName từ Pulldown (Key-pair mà bạn đã tạo trước đó) - Next cho đến khi hoàn thành việc tạo Stack Chúng ta sẽ đợi cho đến khi Resource được tạo xong.
Nếu Stack tạo bị lỗi thì xem thử tại Tab Event xem thông báo lỗi gì để fix template rồi update lại Template nhé. Những lỗi thường gặp phải như là không tồn tại AMI ID ở Region XYZ. Lý do mỗi Region thì có AMI ID khác nhau, Guidline này mình hướng dẫn các bạn chạy ở Region us-east-1 nên dùng
ImageId: ami-079db87dc4c10ac91
. Nếu các bạn chạy ở Region khác thì cần update giá trị ImageId.
Sau khi đợi 1 lúc thì Stack đã tạo thành công!
Verify kết quả
Clean up
Challenge
Để tuân theo best practice thì 2 EC2 của chúng ta cần đặt ở Private subnet. Thay đổi cloudformation template để xây dựng kiến trúc như bên dưới.
- Đặt 2 EC2 ở private subnet
- Thêm NAT Gateway, đặt tại public subnet. (Chúng ta cần NAT Gateway để khi EC2 start sẽ chạy script cài đặt web apache trong user-data)
- Thêm 1 route cho Private Route Table: cho phép đi ra internet thông qua NAT Gateway
- Controll việc NAT Gateway phải được tạo xong thì mới tạo EC2. (Vì EC2 không đi ra internet dc sẽ ko cài đặt web apache được)
Trong trường Stack tạo thành công, nhưng TargetGroup health check vẫn fail thì khả năng web apache chưa được cài thành công trên EC2. Bạn cần tạo thủ công hoặc thay đổi template để thêm 1 EC2 đóng vai trò là bastion host, đặt tại public subnet.
- ssh vào bastion host
- Tạo KeyPair để ssh vào web server
- Đứng ở bastion host ssh vào webserver tham khảo Tại đây
- Confirm apache server đã running hay chưa:
systemctl status httpd.service
- Nếu apache server chưa được cài đặt thì tiến hành chạy thủ công.
yum update -y yum install -y httpd.x86_64 systemctl start httpd.service systemctl enable httpd.service echo “Hello World from $(hostname -f)” > /var/www/html/index.html