[AWS] CloudFormation 활용하기
CloudFormation
CloudFormation은 Amazon Web Services(AWS) 리소스를 자동으로 생성해 주는 서비스이다.
사용하려는 AWS 리소스를 템플릿 파일로 작성하면, CloudFormation이 이를 분석해서 AWS 리소스를 생성한다.
이렇게 생성된 리소스를 스택이라고 한다.
작동 방식
CloudFormation 아래 그림과 같이 작동한다. 템플릿 작성, 템플릿 업로드, 스택 생성, 스택 설정 및 리소스 생성의 4단계이다.
특징
- 인프라를 코드로 관리한다.
- 인프라를 코드로 관리하는 것을 Infrastructure as code라고 한다. 코드를 Git과 같은 버전 관리 시스템으로 관리하면 개발자가 소스코드를 관리하는 것과 비슷하게 인프라를 관리할 수 있다.
- 인프라 관리가 편리하다.
- 템플릿에 리소스를 정의하기만 하면 리소스를 생성하고 리소스가 서로 연계되도록 구성한다. 리소스가 더 이상 필요하지 않으면 스택을 삭제하는 것만으로 전체 리소스를 삭제할 수 있다.
- 인프라 구성을 재사용한다.
- 한번 구성한 인프라는 얼마든지 다시 구축할 수 있다. 한 리전에서 사용한 템플릿을 다른 리전에서 동일하게 사용한다. 같은 리전에서 재사용하려면 스택 이름을 다르게 설정한다.
- 사용 요금이 없다.
- 생성된 리소스에 대한 요금만 지불하면 되고 CloudFormation 자체에는 별도로 요금이 부과되지 않는다.
CloudFormation의 기본적인 Syntax 소개, 스택 생성 및 업데이트 실습
1. 스택 생성
ec2.yml 파일
AWSTemplateFormatVersion: '2010-09-09'
Description: EC2 CloudFormation Template
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
-
Parameters:
- EC2Name
- EC2InstanceType
- AMIId
- KeyName
- VPC
- Subnet
- AllocateEIP
ParameterLabels:
EC2Name:
default: EC2 Instance Name
EC2InstanceType:
default: Instance Type
AMIId:
default: AMI Id
KeyName:
default: EC2 Key Pair Name
AllocateEIP:
default: Elastic IP
# Custom Variable for the environment
Parameters:
EC2Name:
Description: Name tag for EC2
Type: String
# Keypair should be manually created prior to create cloudformation stack(EC2 -> KeyPair)
KeyName:
Description: Name of an existing EC2 KeyPair to enable SSH access to the instance
Type: AWS::EC2::KeyPair::KeyName
ConstraintDescription: must be the name of an existing EC2 KeyPair
EC2InstanceType:
Description: Specify EC2 instance type
Type: String
VPC:
Description: Specify VPC Id
Type: AWS::EC2::VPC::Id
Subnet:
Description: Specify Subnet Id
Type: AWS::EC2::Subnet::Id
AMIId:
Description: Specify AMI Id
Type: AWS::EC2::Image::Id
AllocateEIP:
Description: Select "yes" if you want to assign EIP to an instance
Type: String
AllowedValues:
- yes
- no
Conditions:
UseAllocateEIP: !Equals [!Ref AllocateEIP, yes]
Resources:
# IAM roles assigned to EC2 instnaces
IAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
-
Effect: Allow
Action:
- sts:AssumeRole
Principal:
Service:
- ec2.amazonaws.com
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM
# IAM Instance profile assigned to EC2 instnaces
InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles:
- !Ref IAMRole
DependsOn: IAMRole
# Security Group assigned to EC2 instnaces
InstanceSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Join ['-', [!Ref EC2Name, "sg"]]
GroupDescription: !Join [' ', [!Ref EC2Name, "Instance", "Security Group"]]
VpcId: !Ref VPC
Tags:
-
Key: Name
Value: !Join ['-', [!Ref EC2Name, "InstanceSecurityGroup"]]
Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref AMIId
InstanceType: !Ref EC2InstanceType
DisableApiTermination: false
InstanceInitiatedShutdownBehavior: stop
IamInstanceProfile: !Ref InstanceProfile
Monitoring: false
KeyName: !Ref KeyName
SecurityGroupIds:
- !Ref InstanceSecurityGroup
SubnetId: !Ref Subnet
Tags:
-
Key: Name
Value: !Ref EC2Name
DependsOn:
- InstanceSecurityGroup
- InstanceProfile
## Assign Elastic IP
EIP:
Type: AWS::EC2::EIP
Condition: UseAllocateEIP
## Associate Elastic IP
EIPAssociation:
Type: AWS::EC2::EIPAssociation
Condition: UseAllocateEIP
Properties:
AllocationId: !GetAtt EIP.AllocationId
InstanceId: !Ref Instance
DependsOn:
- EIP
- Instance
CloudFormation Stack Update
텍스트 에디터에서 ec2.yml 파일을 열고 Instance 블록을 수정한 후 아래 블록을 추가
생성한 stack에서 업데이트 , 변경한 ec2.yml파일을 교체
같은 방식으로 ec2-lt.yml로 스택 생성
업데이트 확인
Resource 내부에 코드를 붙여야한다 .
결과
CloudFormation Update Behaviors: 각 Resource의 속성 변경시 해당 Resource가 재시작 또는 재생성 될수 있다.
EC2를 예로 들자면 UserData의 경우에는 Some Interruption으로 기존에 생성된 인스턴스를 유지하되 재시작 또는 리부팅이 일어날수 있고, LaunchTemplate의 경우에는 Replacement로 인스턴스가 교체된다.
따라서 위의 예에서 Userdata에 스크립트를 추가했을때 반영이 되지 않았던 이유는 Userdata는 인스턴스 생성시에만 실행되기 때문이다.
CFN 템플릿 재사용 방안 및 모듈화된 (Nested Stack) 스택 구성 실습
Mapping
ec-2 mapping.yml 을 업로드해서 앞 단계와같이 스택을 생성한다 .
생성된 인스턴스타입을 확인한다
ec-2 mapping.yml
AWSTemplateFormatVersion: '2010-09-09'
Description: EC2 CloudFormation Template
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
-
Parameters:
- EC2Name
- Environment
- AMIId
- KeyName
- VPC
- Subnet
- AllocateEIP
ParameterLabels:
EC2Name:
default: EC2 Instance Name
Environment:
default: Environment
AMIId:
default: AMI Id
KeyName:
default: EC2 Key Pair Name
AllocateEIP:
default: Elastic IP
# Custom Variable for the environment
Parameters:
EC2Name:
Description: Name tag for EC2
Type: String
# Keypair should be manually created prior to create cloudformation stack(EC2 -> KeyPair)
KeyName:
Description: Name of an existing EC2 KeyPair to enable SSH access to the instance
Type: AWS::EC2::KeyPair::KeyName
ConstraintDescription: must be the name of an existing EC2 KeyPair
Environment:
Description: Specify Environment
Type: String
AllowedValues:
- test
- stag
- prod
VPC:
Description: Specify VPC Id
Type: AWS::EC2::VPC::Id
Subnet:
Description: Specify Subnet Id
Type: AWS::EC2::Subnet::Id
AMIId:
Description: Specify AMI Id
Type: AWS::EC2::Image::Id
AllocateEIP:
Description: Select "yes" if you want to assign EIP to an instance
Type: String
AllowedValues:
- yes
- no
Mappings:
Specs:
InstanceType:
test: t2.micro
stag: t2.medium
prod: m5.large
Conditions:
UseAllocateEIP: !Equals [!Ref AllocateEIP, yes]
Resources:
# IAM roles assigned to EC2 instnaces
IAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
-
Effect: Allow
Action:
- sts:AssumeRole
Principal:
Service:
- ec2.amazonaws.com
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM
# IAM Instance profile assigned to EC2 instnaces
InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles:
- !Ref IAMRole
DependsOn: IAMRole
# Security Group assigned to EC2 instnaces
InstanceSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Join ['-', [!Ref EC2Name, "sg"]]
GroupDescription: !Join [' ', [!Ref EC2Name, "Instance", "Security Group"]]
VpcId: !Ref VPC
Tags:
-
Key: Name
Value: !Join ['-', [!Ref EC2Name, "InstanceSecurityGroup"]]
# Security Group Ingress Rule
HTTPIngressRule:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref InstanceSecurityGroup
IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
DependsOn:
- InstanceSecurityGroup
LaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateData:
DisableApiTermination: false
InstanceInitiatedShutdownBehavior: stop
IamInstanceProfile:
Name: !Ref InstanceProfile
ImageId: !Ref AMIId
InstanceType: !FindInMap [Specs, InstanceType, !Ref Environment]
Monitoring:
Enabled: false
KeyName: !Ref KeyName
SecurityGroupIds:
- !Ref InstanceSecurityGroup
TagSpecifications:
-
ResourceType: instance
Tags:
-
Key: Name
Value: !Ref EC2Name
UserData:
Fn::Base64:
!Sub |
#!/bin/bash -xe
sudo yum install -y httpd
echo "<html>Hello-World!!</html>" > /tmp/index.html
sudo cp /tmp/index.html /var/www/html/index.html
sudo chmod 755 /var/www/html/index.html
sudo service httpd start
sudo chkconfig httpd on
LaunchTemplateName: !Ref EC2Name
DependsOn:
- InstanceSecurityGroup
- InstanceProfile
Instance:
Type: AWS::EC2::Instance
Properties:
LaunchTemplate:
LaunchTemplateId: !Ref LaunchTemplate
Version: !GetAtt LaunchTemplate.LatestVersionNumber
SubnetId: !Ref Subnet
DependsOn:
- LaunchTemplate
## Assign Elastic IP
EIP:
Type: AWS::EC2::EIP
Condition: UseAllocateEIP
## Associate Elastic IP
EIPAssociation:
Type: AWS::EC2::EIPAssociation
Condition: UseAllocateEIP
Properties:
AllocationId: !GetAtt EIP.AllocationId
InstanceId: !Ref Instance
DependsOn:
- EIP
- Instance
업데이트
현재 템플릿 사용을 선택, environment를 prod를 변경 후 다음 ,스택을 업데이트 한다 .
t2.micro에서 m5.large로 바뀌었다 .
댓글
댓글 쓰기