- AWS CloudFormation 템플릿을 빌드하여 간단한 인프라 프로비저닝하고 CreateStack 작업 수행
- Detect drift 명령을 사용하여 AWS CloudFormation 스택에서 드리프트 감지
- AWS CloudFormation Change Set 생성 및 실행
지난 실습에 이어 AWS Cloud9을 사용하여 simple-infrastucture 템플릿을 수정함으로써 변경 세트(Change Set)을 업데이트하고 서브넷을 추가합니다.
Change Set을 확인하기 위해 simple-infrastructure.yaml
내용을 복사하여 아래의 조건들로 변경하여 simple-infrastructure-CS.yaml
파일로 붙여넣어 생성합니다.
아래의 정보로 simple-infrastructure-CS.yaml
파일을 수정합니다.
AWSTemplateFormatVersion: 2010-09-09
Description: >-
AWS CloudFormation Simple Infrastructure Template
VPC_Single_Instance_In_Subnet: This template will show how to create a VPC and
add an EC2 instance with an Elastic IP address and a security group.
Parameters:
VPCCIDR:
Description: CIDR Block for VPC
Type: String
Default: 10.199.0.0/16
AllowedValues:
- 10.199.0.0/16
PUBSUBNET1:
Description: Public Subnet 1
Type: String
Default: 10.199.10.0/24
AllowedValues:
- 10.199.10.0/24
PUBSUBNET2:
Description: Public Subnet 2
Type: String
Default: 10.199.12.0/24
AllowedValues:
- 10.199.12.0/24
InstanceType:
Description: WebServer EC2 instance type
Type: String
Default: t2.nano
AllowedValues:
- t2.nano
- t2.micro
- t2.small
ConstraintDescription: must be a valid EC2 instance type.
KeyName:
Description: Keyname for the keypair that Qwiklab will use to launch EC2 instances
Type: 'AWS::EC2::KeyPair::KeyName'
ConstraintDescription: must be the name of the provided existing EC2 KeyPair.
SSHLocation:
Description: ' The IP address range that can be used to SSH to the EC2 instances'
Type: String
MinLength: '9'
MaxLength: '18'
Default: 0.0.0.0/0
AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})'
ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
LatestAmiId:
Description: Find the current AMI ID using System Manager Parameter Store
Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
QwiklabLocale:
Default: en
Description: >-
The locale of the student will be passed in to this parameter via the
Qwiklab platform (via the student's browser)
Type: String
Resources:
VPC:
Type: 'AWS::EC2::VPC'
Properties:
CidrBlock: !Ref VPCCIDR
EnableDnsSupport: 'true'
EnableDnsHostnames: 'true'
Tags:
- Key: Application
Value: !Ref 'AWS::StackId'
- Key: Name
Value: CF lab environment
Subnet:
Type: 'AWS::EC2::Subnet'
DependsOn: VPC
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref PUBSUBNET1
MapPublicIpOnLaunch: 'true'
AvailabilityZone: !Select
- '0'
- !GetAZs ''
Tags:
- Key: Application
Value: !Ref 'AWS::StackId'
- Key: Name
Value: Public Subnet
SUBNET2:
Type: 'AWS::EC2::Subnet'
DependsOn: VPC
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref PUBSUBNET2
MapPublicIpOnLaunch: 'true'
AvailabilityZone: !Select
- '1'
- !GetAZs ''
Tags:
- Key: Application
Value: !Ref 'AWS::StackId'
- Key: Name
Value: Public Subnet2
InternetGateway:
Type: 'AWS::EC2::InternetGateway'
DependsOn: VPC
Properties:
Tags:
- Key: Application
Value: !Ref 'AWS::StackId'
AttachGateway:
Type: 'AWS::EC2::VPCGatewayAttachment'
DependsOn: VPC
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
RouteTable:
Type: 'AWS::EC2::RouteTable'
DependsOn: VPC
Properties:
VpcId: !Ref VPC
Tags:
- Key: Application
Value: !Ref 'AWS::StackId'
Route:
Type: 'AWS::EC2::Route'
DependsOn:
- VPC
- AttachGateway
Properties:
RouteTableId: !Ref RouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
SubnetRouteTableAssociation:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
DependsOn:
- VPC
- InternetGateway
Properties:
SubnetId: !Ref Subnet
RouteTableId: !Ref RouteTable
Subnet2RouteTableAssociation:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
DependsOn:
- VPC
- InternetGateway
Properties:
SubnetId: !Ref SUBNET2
RouteTableId: !Ref RouteTable
NetworkAcl:
Type: 'AWS::EC2::NetworkAcl'
DependsOn:
- VPC
- InternetGateway
Properties:
VpcId: !Ref VPC
Tags:
- Key: Application
Value: !Ref 'AWS::StackId'
InboundHTTPNetworkAclEntry:
Type: 'AWS::EC2::NetworkAclEntry'
DependsOn:
- VPC
- InternetGateway
Properties:
NetworkAclId: !Ref NetworkAcl
RuleNumber: '100'
Protocol: '6'
RuleAction: allow
Egress: 'false'
CidrBlock: 0.0.0.0/0
PortRange:
From: '80'
To: '80'
InboundSSHNetworkAclEntry:
Type: 'AWS::EC2::NetworkAclEntry'
DependsOn:
- VPC
- InternetGateway
Properties:
NetworkAclId: !Ref NetworkAcl
RuleNumber: '101'
Protocol: '6'
RuleAction: allow
Egress: 'false'
CidrBlock: 0.0.0.0/0
PortRange:
From: '22'
To: '22'
InboundResponsePortsNetworkAclEntry:
Type: 'AWS::EC2::NetworkAclEntry'
DependsOn:
- VPC
- InternetGateway
Properties:
NetworkAclId: !Ref NetworkAcl
RuleNumber: '102'
Protocol: '6'
RuleAction: allow
Egress: 'false'
CidrBlock: 0.0.0.0/0
PortRange:
From: '1024'
To: '65535'
OutBoundHTTPNetworkAclEntry:
Type: 'AWS::EC2::NetworkAclEntry'
DependsOn:
- VPC
- InternetGateway
Properties:
NetworkAclId: !Ref NetworkAcl
RuleNumber: '100'
Protocol: '6'
RuleAction: allow
Egress: 'true'
CidrBlock: 0.0.0.0/0
PortRange:
From: '80'
To: '80'
OutBoundHTTPSNetworkAclEntry:
Type: 'AWS::EC2::NetworkAclEntry'
DependsOn:
- VPC
- InternetGateway
Properties:
NetworkAclId: !Ref NetworkAcl
RuleNumber: '101'
Protocol: '6'
RuleAction: allow
Egress: 'true'
CidrBlock: 0.0.0.0/0
PortRange:
From: '443'
To: '443'
OutBoundResponsePortsNetworkAclEntry:
Type: 'AWS::EC2::NetworkAclEntry'
DependsOn:
- VPC
- InternetGateway
Properties:
NetworkAclId: !Ref NetworkAcl
RuleNumber: '102'
Protocol: '6'
RuleAction: allow
Egress: 'true'
CidrBlock: 0.0.0.0/0
PortRange:
From: '1024'
To: '65535'
SubnetNetworkAclAssociation:
Type: 'AWS::EC2::SubnetNetworkAclAssociation'
Properties:
SubnetId: !Ref Subnet
NetworkAclId: !Ref NetworkAcl
IPAddress:
Type: 'AWS::EC2::EIP'
DependsOn: AttachGateway
Properties:
Domain: vpc
InstanceId: !Ref WebServerInstance
InstanceSecurityGroup:
Type: 'AWS::EC2::SecurityGroup'
Properties:
VpcId: !Ref VPC
GroupDescription: Enable SSH access via port 22 and HTTP via port 80
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '22'
ToPort: '22'
CidrIp: !Ref SSHLocation
- IpProtocol: tcp
FromPort: '80'
ToPort: '80'
CidrIp: 0.0.0.0/0
WebServerInstance:
Type: 'AWS::EC2::Instance'
DependsOn: AttachGateway
Metadata:
Comment: Install a simple application
'AWS::CloudFormation::Init':
config:
packages:
yum:
httpd: []
files:
/var/www/html/index.html:
content: !Join
- |+
- - >-
<h1>Congratulations, you have successfully deployed a simple
infrastructure using AWS CloudFormation.</h1>
mode: '000644'
owner: root
group: root
/etc/cfn/cfn-hup.conf:
content: !Join
- ''
- - |
[main]
- stack=
- !Ref 'AWS::StackId'
- |+
- region=
- !Ref 'AWS::Region'
- |+
mode: '000400'
owner: root
group: root
/etc/cfn/hooks.d/cfn-auto-reloader.conf:
content: !Join
- ''
- - |
[cfn-auto-reloader-hook]
- |
triggers=post.update
- >
path=Resources.WebServerInstance.Metadata.AWS::CloudFormation::Init
- 'action=/opt/aws/bin/cfn-init -v '
- ' --stack '
- !Ref 'AWS::StackName'
- ' --resource WebServerInstance '
- ' --region '
- !Ref 'AWS::Region'
- |+
- |
runas=root
mode: '000400'
owner: root
group: root
services:
sysvinit:
httpd:
enabled: 'true'
ensureRunning: 'true'
cfn-hup:
enabled: 'true'
ensureRunning: 'true'
files:
- /etc/cfn/cfn-hup.conf
- /etc/cfn/hooks.d/cfn-auto-reloader.conf
Properties:
InstanceType: !Ref InstanceType
ImageId: !Ref LatestAmiId
KeyName: !Ref KeyName
Tags:
- Key: Application
Value: !Ref 'AWS::StackId'
- Key: Name
Value: Lab Host
NetworkInterfaces:
- GroupSet:
- !Ref InstanceSecurityGroup
AssociatePublicIpAddress: 'true'
DeviceIndex: '0'
DeleteOnTermination: 'true'
SubnetId: !Ref Subnet
UserData: !Base64
'Fn::Join':
- ''
- - |
#!/bin/bash -xe
- |
yum update -y aws-cfn-bootstrap
- '/opt/aws/bin/cfn-init -v '
- ' --stack '
- !Ref 'AWS::StackName'
- ' --resource WebServerInstance '
- ' --region '
- !Ref 'AWS::Region'
- |+
- '/opt/aws/bin/cfn-signal -e $? '
- ' --stack '
- !Ref 'AWS::StackName'
- ' --resource WebServerInstance '
- ' --region '
- !Ref 'AWS::Region'
- |+
CreationPolicy:
ResourceSignal:
Timeout: PT15M
Outputs:
URL:
Value: !Join
- ''
- - 'http://'
- !GetAtt
- WebServerInstance
- PublicIp
Description: Newly created application URL
AWS Cloud9 terminal에서 아래 명령어를 실행하여 키 페어 환경변수가 있는지 확인합니다.
터미널에서 다음 명령을 실행하여 스택 변경 세트 프로세스를 시작합니다. 변경 세트가 처리되면 AWS CloudFormation에서 StackId
및 Id
를 반환합니다.
aws cloudformation create-change-set --stack-name AWSStudent-Lab1 --change-set-name Lab1ChangeSet --parameters ParameterKey=InstanceType,ParameterValue=t2.micro ParameterKey=KeyName,ParameterValue=$keyPair --template-body file://simple-infrastructure-CS.yaml
AWS CloudFormation으로 돌아와서 변경 세트(Change Set) 탭을 선택하여 상태를 확인합니다.
Cloud9 터미널에서 아래 명령어를 실행합니다.
aws cloudformation execute-change-set --stack-name AWSStudent-Lab1 --change-set-name Lab1ChangeSet
적용된 모습을 확인할 수 있습니다.
AWS 검색창에서 VPC로 접속해서 서브넷을 선택합니다.
생성했던 Public Subnet2
를 확인할 수 있습니다.
아래 명령어를 AWS Cloud9 터미널에 입력하여 삭제할 수 있습니다.
aws cloudformation delete-change-set --change-set-name Lab1ChangeSet --stack-name AWSStudent-Lab1
지금까지 코드형 인프라 프로비저닝 서비스인 AWS CloudFormation을 통한 인프라 구축, 드래프트 감지(Detect Drift), 변경 세트(Change Set)에 대해 알아보았습니다. yaml 템플릿만으로 인프라를 구축할 수 있는 서비스를 경험해보니 굉장히 매력적인것 같습니다.