이번 글에서는 AWS에서 제공하는 IaC 도구 서비스인 Cloudformation을 이용하여 인프라를 구축하는 내용입니다.
What is Cloudformation?
AWS 및 서드 파티 리소스를 손쉽게 모델링, 프로비저닝 및 관리할 수 있는 코드형 인프라(IaC) 서비스입니다. 리소스를 코드로 관리하여 휴먼에러를 최소화하고 버전관리로 협업에 유리하며 템플릿을 사용하여 같은 구성을 다른 환경에서도 사용할 수 있다는 장점이 있습니다. 생성한 AWS 리소스에 대해서 사용 비용을 지불하고, 레지스트리 확장을 사용하는 경우에는 핸들러 작업당 요금이 부과됩니다.
Cloudformation 작동 방식
1. Cloudformation 템플릿을 작성합니다.
2. 템플릿을 로컬 또는 S3버킷에 저장합니다.
3. 템플릿 파일의 위치를 지정하여 Cloudformation 스택을 생성합니다.
사용자가 수행할 수 있는 권한이 있는 작업만 수행이 가능합니다. IAM User에 VPC 생성 권한을 주지 않고Cloudformation에서 VPC를 생성했을 때, 아래와 같이 생성이 실패하고 에러메시지에 생성 권한이 없다고 나옵니다.
Cloudformation 템플릿 구조
JSON 또는 YAML 형식의 Cloudformation 템플릿을 작성하여 프로비저닝합니다.
AWSTemplateFormatVersion: "version date" # 최신 템플릿 버전은 2010-09-09입니다. Description: # 템플릿에 대한 설명 String Metadata: # 템플릿에 대한 세부 정보 template metadata Parameters: # 스택을 생성하거나 업데이트 시 템플릿에 사용자 지정 값을 입력 set of parameters Mappings: # 리전별로 리소스를 지정할 때 사용(Key-Value 형식) set of mappings Conditions: # 스택을 생성하거나 업데이트 시 템플릿에 전달된 파라미터 검증 set of conditions Transform: # 템플릿을 처리하는 데 사용하는 매크로 지정 set of transforms Resources: # AWS 리소스 정의 set of resources Outputs: # 출력 값을 반환하거나 다른 스택에서 활용 가능 set of outputs
Cloudformation 템플릿을 작성하고 인프라를 구축해보면서 더 자세히 알아보겠습니다.
이번 글에서 생성할 AWS 리소스와 아키텍처는 다음과 같습니다.
– VPC
– Internet Gateway
– NAT Gateway
– Route Table
– Subnet
– EIP
[Cloudformation Template] – Parameters
AvailabilityZone, VPC IPv4 주소 범위, 각 Subnet Ipv4 주소 범위를 파라미터로 정의합니다. Cloudformation 스택을 생성할 때 파라미터 값을 수정할 수 있습니다.
Parameters:
AZ1:
Description: AvailabilityZone for public
Type: AWS::EC2::AvailabilityZone::Name
AZ2:
Description: AvailabilityZone for private
Type: AWS::EC2::AvailabilityZone::Name
VpcCIDR:
Description: Please enter the IP range (CIDR notation) for this VPC
Type: String
Default: 172.16.0.0/16
PublicSubnet1CIDR:
Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone
Type: String
Default: 172.16.10.0/24
PublicSubnet2CIDR:
Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone
Type: String
Default: 172.16.20.0/24
PrivateSubnet1CIDR:
Description: Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone
Type: String
Default: 172.16.40.0/24
PrivateSubnet2CIDR:
Description: Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone
Type: String
Default: 172.16.60.0/24
PrivateSubnet3CIDR:
Description: Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone
Type: String
Default: 172.16.80.0/24
PrivateSubnet4CIDR:
Description: Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone
Type: String
Default: 172.16.100.0/24
PrivateSubnet5CIDR:
Description: Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone
Type: String
Default: 172.16.120.0/24
PrivateSubnet6CIDR:
Description: Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone
Type: String
Default: 172.16.140.0/24
[Cloudformation Template] – Resources
Resources 섹션에서 VPC를 구성합니다. VPC의 CidrBlock은 !Ref를 사용하여 위에서 정의한 Parameters 값을 적용하겠습니다.
Resources:
###########
# VPC
###########
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCIDR
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: "Name"
Value: "Bespin-VPC"
Internet Gateway를 생성하고 VPC에 연결합니다. InternetGatewayId는 InternetGateway가 생성되고 생성된 ID를 참조하도록 합니다.
###########
# Internet Gateway
###########
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: "Name"
Value: "Bespin-IG"
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
Subnet을 생성합니다. Public Subnet에는 MapPublicIpOnLaunch: true 옵션을 사용하여 인스턴스가 생성될 때 Public IP를 부여할 수 있도록 합니다.
###########
# Subnet
###########
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Ref AZ1
CidrBlock: !Ref PublicSubnet1CIDR
MapPublicIpOnLaunch: true
Tags:
- Key: "Name"
Value: "Bespin-PublicSubnet1"
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Ref AZ2
CidrBlock: !Ref PublicSubnet2CIDR
MapPublicIpOnLaunch: true
Tags:
- Key: "Name"
Value: "Bespin-PublicSubnet2"
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Ref AZ1
CidrBlock: !Ref PrivateSubnet1CIDR
MapPublicIpOnLaunch: false
Tags:
- Key: "Name"
Value: "Bespin-PrivateSubnet1"
PrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Ref AZ2
CidrBlock: !Ref PrivateSubnet2CIDR
MapPublicIpOnLaunch: false
Tags:
- Key: "Name"
Value: "Bespin-PrivateSubnet2"
PrivateSubnet3:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Ref AZ1
CidrBlock: !Ref PrivateSubnet3CIDR
MapPublicIpOnLaunch: false
Tags:
- Key: "Name"
Value: "Bespin-PrivateSubnet3"
PrivateSubnet4:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Ref AZ2
CidrBlock: !Ref PrivateSubnet4CIDR
MapPublicIpOnLaunch: false
Tags:
- Key: "Name"
Value: "Bespin-PrivateSubnet4"
PrivateSubnet5:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Ref AZ1
CidrBlock: !Ref PrivateSubnet5CIDR
MapPublicIpOnLaunch: false
Tags:
- Key: "Name"
Value: "Bespin-PrivateSubnet5"
PrivateSubnet6:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Ref AZ2
CidrBlock: !Ref PrivateSubnet6CIDR
MapPublicIpOnLaunch: false
Tags:
- Key: "Name"
Value: "Bespin-PrivateSubnet6"
NAT Gateway에 연결할 EIP를 생성합니다. DependsOn 옵션을 사용하여 생성 순서를 정할 수 있습니다. Internet Gateway가 VPC 연결된 후에 EIP를 생성하도록 합니다.
###########
# NAT Gateway
###########
NatGatewayEIP:
Type: AWS::EC2::EIP
DependsOn: InternetGatewayAttachment
Properties:
Domain: vpc
NatGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt NatGatewayEIP.AllocationId
SubnetId: !Ref PublicSubnet2
Tags:
- Key: "Name"
Value: "Bespin-NAT"
다음은 Route Table 생성(AWS::EC2::RouteTable) –> Routing 설정(AWS::EC2::Route) –> 서브넷 연결(AWS::EC2::SubnetRouteTableAssociation) 순으로 구성됩니다. PublicRouteTable은 Public Subnet에 생성되는 인스턴스가 Internet Gateway를 통해 인터넷에 액세스하도록 설정합니다. PrivateRouteTable은 Private Subnet에 생성되는 인스턴스가 NAT Gateway를 통해 인터넷에 액세스하도록 설정합니다.
###########
# RouteTable
###########
PublicRouteTable: # 라우팅 테이블을 생성합니다.
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: "Name"
Value: "Bespin-PublicRouteTable"
DefaultPublicRoute: # 라우팅 테이블에 라우팅 설정을 합니다.
Type: AWS::EC2::Route
DependsOn: InternetGatewayAttachment
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicSubnet1RouteTableAssociation: # 라우팅 테이블에 서브넷을 연결 합니다.
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet1
PublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet2
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: "Name"
Value: "Bespin-PrivateRouteTable"
DefaultPrivateRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTable
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGateway
PrivateSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet1
PrivateSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet2
PrivateSubnet3RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet3
PrivateSubnet4RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet4
PrivateSubnet5RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet5
PrivateSubnet6RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet6
[Cloudformation Template] – Outputs
VPC, Subnet을 Outputs에 정의하고 출력 정보를 받아서 server를 구축할 때 이용할 것입니다.
###########
# Outputs
###########
Outputs:
VPC:
Description: A reference to the created VPC
Value: !Ref VPC
Export:
Name: !Sub '${AWS::StackName}-VPC'
PublicSubnet1:
Description: A reference to the public subnet in the 1st Availability Zone
Value: !Ref PublicSubnet1
Export:
Name: !Sub '${AWS::StackName}-PublicSubnet1'
PublicSubnet2:
Description: A reference to the public subnet in the 2nd Availability Zone
Value: !Ref PublicSubnet2
Export:
Name: !Sub '${AWS::StackName}-PublicSubnet2'
PrivateSubnet1:
Description: A reference to the private subnet in the 1st Availability Zone
Value: !Ref PrivateSubnet1
Export:
Name: !Sub '${AWS::StackName}-PrivateSubnet1'
PrivateSubnet2:
Description: A reference to the private subnet in the 2nd Availability Zone
Value: !Ref PrivateSubnet2
Export:
Name: !Sub '${AWS::StackName}-PrivateSubnet2'
PrivateSubnet3:
Description: A reference to the private subnet in the 1st Availability Zone
Value: !Ref PrivateSubnet3
Export:
Name: !Sub '${AWS::StackName}-PrivateSubnet3'
PrivateSubnet4:
Description: A reference to the private subnet in the 2nd Availability Zone
Value: !Ref PrivateSubnet4
Export:
Name: !Sub '${AWS::StackName}-PrivateSubnet4'
PrivateSubnet5:
Description: A reference to the private subnet in the 1st Availability Zone
Value: !Ref PrivateSubnet5
Export:
Name: !Sub '${AWS::StackName}-PrivateSubnet5'
PrivateSubnet6:
Description: A reference to the private subnet in the 2nd Availability Zone
Value: !Ref PrivateSubnet6
Export:
Name: !Sub '${AWS::StackName}-PrivateSubnet6'
[AWS Cloudformation 스택 생성 결과]
스택이 정상적으로 생성되면 CREATE_COMPLETE 상태가 됩니다.
리소스 항목에서 생성된 리소스를 확인할 수 있습니다.
[마무리]
AWS Cloudformation을 이용해서 간단하게 Network를 구축해봤습니다. 변경사항이 생기면 코드만 수정해주고 업데이트를 해주면 되니 AWS Console에서 수동으로 리소스를 생성하는 것보다 쉽게 인프라를 구성할 수 있습니다.
[참고자료]