이번 글에서는 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에서 수동으로 리소스를 생성하는 것보다 쉽게 인프라를 구성할 수 있습니다.
[참고자료]