この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
안녕하세요 클래스메소드 김재욱(Kim Jaewook) 입니다. 이번에는 LaunchTemplate으로 EC2 인스턴스를 생성하는 CloudFormation 코드를 정리해 봤습니다.
VPC 생성
AWSTemplateFormatVersion: "2010-09-09"
Description: VPC Network set
Metadata:
"AWS::CloudFormation::Interface":
ParameterGroups:
- Label:
default: "Network Configuration"
Parameters:
- VPCCIDR
- PublicSubnetACIDR
- PublicSubnetCCIDR
- PrivateSubnetACIDR
- PrivateSubnetCCIDR
ParameterLabels:
VPCCIDR:
default: "VPC CIDR"
PublicSubnetACIDR:
default: "PublicSubnetA CIDR"
PublicSubnetCCIDR:
default: "PublicSubnetC CIDR"
PrivateSubnetACIDR:
default: "PrivateSubnetA CIDR"
PrivateSubnetCCIDR:
default: "PrivateSubnetC CIDR"
# Input VPC, Subnet Parameters & fix Subnet CIDR
Parameters:
VPCCIDR:
Type: String
Default: "10.0.0.0/16"
PublicSubnetACIDR:
Type: String
Default: "10.0.1.0/24"
PublicSubnetCCIDR:
Type: String
Default: "10.0.2.0/24"
PrivateSubnetACIDR:
Type: String
Default: "10.0.11.0/24"
PrivateSubnetCCIDR:
Type: String
Default: "10.0.12.0/24"
# Set VPC, InternetGateway, Subnet
Resources:
VPC:
Type: "AWS::EC2::VPC"
Properties:
CidrBlock: !Ref VPCCIDR
EnableDnsSupport: "true"
EnableDnsHostnames: "true"
InstanceTenancy: default
Tags:
- Key: Name
Value: !Sub "test-vpc"
InternetGateway:
Type: "AWS::EC2::InternetGateway"
Properties:
Tags:
- Key: Name
Value: !Sub "test-igw"
InternetGatewayAttachment:
Type: "AWS::EC2::VPCGatewayAttachment"
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
PublicSubnetA:
Type: "AWS::EC2::Subnet"
Properties:
AvailabilityZone: "ap-northeast-2a"
CidrBlock: !Ref PublicSubnetACIDR
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "test-front-subnet-1a"
PublicSubnetC:
Type: "AWS::EC2::Subnet"
Properties:
AvailabilityZone: "ap-northeast-2c"
CidrBlock: !Ref PublicSubnetCCIDR
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "test-front-subnet-1c"
PrivateSubnetA:
Type: "AWS::EC2::Subnet"
Properties:
AvailabilityZone: "ap-northeast-2a"
CidrBlock: !Ref PrivateSubnetACIDR
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "test-application-subnet-1a"
PrivateSubnetC:
Type: "AWS::EC2::Subnet"
Properties:
AvailabilityZone: "ap-northeast-2c"
CidrBlock: !Ref PrivateSubnetCCIDR
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "test-application-subnet-1c"
# Route Tables
FRONTRTB :
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "test-front-rtb"
APPRTB1A:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "test-application-rtb-1a"
APPRTB1C:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "test-application-rtb-1c"
FRONTRTBroute:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref FRONTRTB
DestinationCidrBlock: "0.0.0.0/0"
GatewayId: !Ref InternetGateway
# Route Tables Subnet Association
FRONTRTBAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref PublicSubnetA
RouteTableId: !Ref FRONTRTB
FRONTRTB2Association:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref PublicSubnetC
RouteTableId: !Ref FRONTRTB
APPRTB1AAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref PrivateSubnetA
RouteTableId: !Ref APPRTB1A
APPRTB1CAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref PrivateSubnetC
RouteTableId: !Ref APPRTB1C
# Output Parameters
Outputs:
# VPC
VPC:
Value: !Ref VPC
Export:
Name: VPC
VPCCIDR:
Value: !Ref VPCCIDR
Export:
Name: VPCCIDR
# Subnet
PublicSubnetA:
Value: !Ref PublicSubnetA
Export:
Name: PublicSubnetA
PublicSubnetACIDR:
Value: !Ref PublicSubnetACIDR
Export:
Name: PublicSubnetACIDR
PublicSubnetC:
Value: !Ref PublicSubnetC
Export:
Name: PublicSubnetC
PublicSubnetCCIDR:
Value: !Ref PublicSubnetCCIDR
Export:
Name: PublicSubnetCCIDR
PrivateSubnetA:
Value: !Ref PrivateSubnetA
Export:
Name: PrivateSubnetA
PrivateSubnetACIDR:
Value: !Ref PrivateSubnetACIDR
Export:
Name: PrivateSubnetACIDR
PrivateSubnetC:
Value: !Ref PrivateSubnetC
Export:
Name: PrivateSubnetC
PrivateSubnetCCIDR:
Value: !Ref PrivateSubnetCCIDR
Export:
Name: PrivateSubnetCCIDR
해당 코드로 생성되는 리소스는 다음과 같습니다.
- VPC - 10.0.0.0/16
- Public Subnet - 10.0.1.0/24, 10.0.2.0/24
- Private Subnet - 10.0.11.0/24, 10.0.12.0/24
- Route Tables
- Internet Gateway
그리고 다른 Stack에서 해당 리소스의 id와 같은 정보를 불러올 수 있도록 Outputs으로 값을 내보내줍니다.
Security Group 생성
AWSTemplateFormatVersion: "2010-09-09"
Description: Create Security Group
Resources:
# Security Group
EC2SecurityGroup1:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: "launch-template-sg"
GroupDescription: "launch-template-sg"
VpcId: { "Fn::ImportValue": !Sub "VPC" }
SecurityGroupIngress:
-
IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0
-
IpProtocol: tcp
FromPort : 80
ToPort : 80
CidrIp: 0.0.0.0/0
Tags:
- Key: "Name"
Value: launch-template-sg
Outputs:
EC2SecurityGroup1:
Value: !Ref EC2SecurityGroup1
Export:
Name: EC2SecurityGroup1
보안 그룹도 별도로 만들어줍니다. 테스트용이기 때문에 22번 포트를 0.0.0.0으로 뚫어놨습니다.
IAM Role 생성
AWSTemplateFormatVersion: "2010-09-09"
Description: Create IAM Role
Resources:
# IAM Role (SSM)
SSMIAMRole:
Type: AWS::IAM::Role
DeletionPolicy: Retain
Properties:
RoleName:
Fn::Sub: "launch-template-ssm-role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service:
- "ec2.amazonaws.com"
Action:
- "sts:AssumeRole"
Path: "/"
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
SSMInstanceProfile:
Type: "AWS::IAM::InstanceProfile"
DeletionPolicy: Retain
Properties:
InstanceProfileName:
Fn::Sub: "launch-template-ssm-role"
Path: "/"
Roles:
- Ref: SSMIAMRole
Outputs:
SSMInstanceProfile:
Value: !GetAtt SSMInstanceProfile.Arn
Export:
Name: SSMInstanceProfile
이어서 IAM Role도 생성합니다.
IAM Role의 경우 AmazonSSMManagedInstanceCore만 추가한 상태입니다.
LaunchTemplate & EC2 인스턴스 생성
AWSTemplateFormatVersion: '2010-09-09'
Description: Create LaunchTemplate & EC2 Instance
Parameters:
LinuxLatestAmi:
Type : AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
Ec2InstanceType:
Type: String
Default: t3.micro
KeyPairName:
Description: "EC2 Keypair name."
Type: AWS::EC2::KeyPair::KeyName
Resources:
MyLaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateName: MyLaunchTemplate
LaunchTemplateData:
IamInstanceProfile:
Arn:
Fn::ImportValue: !Sub SSMInstanceProfile
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeType: gp2
VolumeSize: 20
DeleteOnTermination: true
Encrypted: true
DisableApiTermination: true
NetworkInterfaces:
- AssociatePublicIpAddress: true
DeviceIndex: 0
Groups:
- Fn::ImportValue: !Sub EC2SecurityGroup1
SubnetId: { "Fn::ImportValue": !Sub "PublicSubnetA" }
ImageId: !Ref LinuxLatestAmi
InstanceType: !Ref Ec2InstanceType
KeyName: !Ref KeyPairName
UserData: !Base64 |
#!/bin/bash
yum update -y
yum install httpd-2.4.51 -y
systemctl start httpd
systemctl enable httpd
httpd -v
cp /usr/share/httpd/noindex/index.html /var/www/html/index.html
EC2Instance:
Type: AWS::EC2::Instance
Properties:
LaunchTemplate:
LaunchTemplateId: !Ref MyLaunchTemplate
Version: !GetAtt MyLaunchTemplate.LatestVersionNumber
DisableApiTermination: true
LaunchTemplate에서 IAM Role을 불러와서 설정하고, NetworkInterfaces를 통해서 보안 그룹과 서브넷을 설정합니다.
AssociatePublicIpAddress를 true로 설정하고, Public Subnet으로 설정했기 때문에 EC2 인스턴스가 Public Subnet에 생성되겠지만, AssociatePublicIpAddress를 false로 설정하면 Private Subnet에 EC2 인스턴스를 생성할 수 있습니다.
이어서 UserData에 아파치 웹 서버를 설치하는 명령어를 작성합니다.
마지막으로 EC2 인스턴스를 생성하는 코드에 LaunchTemplate을 불러옵니다.
EC2 인스턴스 확인
CloudFormation Stack을 확인해 보면 문제없이 생성된 것을 확인할 수 있습니다.
LaunchTemplate도 CloudFormation에서 설정한 대로 생성 된 것을 확인할 수 있습니다.
LaunchTemplate을 바탕으로 EC2 인스턴스도 생성된 상태이며
EC2 인스턴스의 퍼블릭 아이피로 접속해 보면 아파치 또 한 정상적으로 설치된 것을 확인할 수 있습니다.
본 블로그 게시글을 읽고 궁금한 사항이 있으신 분들은 kis2702@naver.com로 보내주시면 감사하겠습니다.