SE업무/Cloud

AWS CloudFormation을 사용해서 기본 VPC 생성하기 (JSON)

에륜 2021. 5. 29. 23:42
반응형

AWS의 기본 VPC 만들기를 클릭만으로 만들 수도 있다.

처음 배울땐 클릭으로 만들며 구조를 배우는게 중요하지만

구조를 파악 한후 적응이 되고 만들때는 상당히 귀찮고 시간이 걸리고 실수 할 수 도 있어 골치아파 질수도있다.

신규 서비스를 만드는 경우 새로운 VPC를 만들 경우가 빈번하다.

 

그래서 GUI가 아닌 JSON파일이나 YAML 파일 형태로 AWS 구성을 할 수 있는 CloudFormation이라는 기능이 있다.

 

CloudFormation을 이용하여 기본 VPC 파일을 만들어서 사용할려고한다.

VPC를 만들때 변수를 넣어 생성시 DEV QA SANDBOX LIVE 와 같이 환경값을 넣어 보기 편하게 하였다.

 

비슷한 자료로 AWS DOCS에서도 제공한다.

https://docs.aws.amazon.com/ko_kr/codebuild/latest/userguide/cloudformation-vpc-template.html

 

AWS CloudFormation 템플릿 - AWS CodeBuild

이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.

docs.aws.amazon.com

AWS DOCS에서는 YAML로 제공하기 때문에 나는 JSON 파일로 변경해서 만들어 봤다.

 

설명을 위해 아래에는 주석을 달아 설명하고 주석없는 버전은 업로드 해놓겠습니다.

아주 기본적인 구조인 퍼블릭,프라이빗 서브넷을 이중화 및 안정성을 위해 각각 2개씩 만들고

인터넷,NAT 게이트웨이를 라우팅 테이블에 연결하고 각각 맞는 서브넷에 연결하는 과정이다.

DB존을 따로 만들고 싶다면 비슷하게 하나 더 추가해서 사용하면된다.

여기에 추가적으로 site to site VPN 연결도 추가하면 초기 셋팅할때 편하다

{
  "AWSTemplateFormatVersion": "2010-09-09",

  "Description": "CloudFormation template for a generic VPC with public and private subnets (with private network Internet access via NAT)",

  "Parameters": {#변수 입력을 위한 설정, 추가 변수입력이 필요하다면 더 추가하면됩니다.
	"Environment":{
		"Description": "Type Your Environment",
		"Type": "String"
	}
  },

  "Mappings": {# VPC의 CIDR 설정 이부분은 직접 수정해서 입력하면됩니다.
    "SubnetConfig": {
      "VPC": {
        "CIDR": "192.168.101.0/24"
      },
      "Public1": {
        "CIDR": "192.168.101.0/26"
      },
      "Public2": {
        "CIDR": "192.168.101.64/26"
      },
      "Private1": {
        "CIDR": "192.168.101.128/26"
      },
      "Private2": {
        "CIDR": "192.168.101.192/26"
      }
    }
  },

  "Resources": {

    "VPC": {#VPC 생성
      "Type": "AWS::EC2::VPC",
      "Properties": {
        "CidrBlock": {
          "Fn::FindInMap": ["SubnetConfig", "VPC", "CIDR"]
        },
        "Tags": [{
            "Key": "Application",
            "Value": {
              "Ref": "AWS::StackName"
            }
          },
          {
            "Key": "Network",
            "Value": "Public"
          },
          {
            "Key": "Name",
            "Value": {
                "Fn::Sub": [ "${Environment}-VPC", { "Environment": {"Ref" : "Environment" }} ]
            }
          }
        ]
      }
    },
 

    "PublicSubnet1": {#퍼블릭-01 서브넷생성
      "DependsOn": ["VPC"],
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "CidrBlock": {
          "Fn::FindInMap": ["SubnetConfig", "Public1", "CIDR"]
        },
        "AvailabilityZone": {
          "Fn::Select": ["0", {# 0은 보통 A az이다. 012 순서로 abc순서이다 b가없으면 c가 1이된다. 
            "Fn::GetAZs": ""
          }]
        },
        "Tags": [{
            "Key": "Application",
            "Value": {
              "Ref": "AWS::StackName"
            }
          },
          {
            "Key": "Network",
            "Value": "Public"
          },
          {
            "Key": "Name",
            "Value": {
                "Fn::Sub": [ "${Environment}-Pub1", { "Environment": {"Ref" : "Environment" }} ]
            }
          }
        ]
      }
    },

    "PublicSubnet2": {#퍼블릭-02 서브넷생성
      "DependsOn": ["VPC"],
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "CidrBlock": {
          "Fn::FindInMap": ["SubnetConfig", "Public2", "CIDR"]
        },
        "AvailabilityZone": {
          "Fn::Select": ["2", {#저는 a와 c존을 주로 사용합니다. 서울리전기준으로 a와 c존을 추천 이전에 b존에 문제가 생긴적이 있어서이다.
            "Fn::GetAZs": ""
          }]
        },
        "Tags": [{
            "Key": "Application",
            "Value": {
              "Ref": "AWS::StackName"
            }
          },
          {
            "Key": "Network",
            "Value": "Public"
          },
          {
            "Key": "Name",
            "Value": {
                "Fn::Sub": [ "${Environment}-Pub2", { "Environment": {"Ref" : "Environment" }} ]
            }
          }
        ]
      }
    },

    "InternetGateway": {#퍼블릭 서브넷들이 외부통신하기 위한 인터넷 게이트웨이 생성
      "Type": "AWS::EC2::InternetGateway",
      "Properties": {
        "Tags": [{
            "Key": "Application",
            "Value": {
              "Ref": "AWS::StackName"
            }
          },
          {
            "Key": "Network",
            "Value": "Public"
          },
          {
            "Key": "Name",
            "Value": {
                "Fn::Sub": [ "${Environment}-igw", { "Environment": {"Ref" : "Environment" }} ]
            }
          }
        ]
      }
    },

	
    "GatewayToInternet": {# 인터넷 게이트웨이를 VPC에 연결
      "DependsOn": ["VPC", "InternetGateway"],
      "Type": "AWS::EC2::VPCGatewayAttachment",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "InternetGatewayId": {
          "Ref": "InternetGateway"
        }
      }
    },

    "PublicRouteTable": {#라우팅 테이블생성
      "DependsOn": ["VPC"],
      "Type": "AWS::EC2::RouteTable",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "Tags": [{
            "Key": "Application",
            "Value": {
              "Ref": "AWS::StackName"
            }
          },
          {
            "Key": "Network",
            "Value": "Public"
          },
          {
            "Key": "Name",
            "Value": {
                "Fn::Sub": [ "${Environment}-Public", { "Environment": {"Ref" : "Environment" }} ]
            }
          }
        ]
      }
    },

    "PublicRoute": {#라우팅 테이블에 0.0.0.0/0은 인터넷 게이트웨이로 가게 설정
      "DependsOn": ["PublicRouteTable", "InternetGateway"],
      "Type": "AWS::EC2::Route",
      "Properties": {
        "RouteTableId": {
          "Ref": "PublicRouteTable"
        },
        "DestinationCidrBlock": "0.0.0.0/0",
        "GatewayId": {
          "Ref": "InternetGateway"
        }
      }
    },

    "PublicSubnetRouteTableAssociation1": {# 서브넷에 라우팅 테이블 연결
      "DependsOn": ["PublicSubnet1", "PublicRouteTable"],
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": {
        "SubnetId": {
          "Ref": "PublicSubnet1"
        },
        "RouteTableId": {
          "Ref": "PublicRouteTable"
        }
      }
    },

    "PublicSubnetRouteTableAssociation2": {# 서브넷에 라우팅 테이블 연결
      "DependsOn": ["PublicSubnet2", "PublicRouteTable"],
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": {
        "SubnetId": {
          "Ref": "PublicSubnet2"
        },
        "RouteTableId": {
          "Ref": "PublicRouteTable"
        }
      }
    },

    "PrivateSubnet1": {#프라이빗 서브넷 생성
      "DependsOn": ["VPC"],
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "CidrBlock": {
          "Fn::FindInMap": ["SubnetConfig", "Private1", "CIDR"]
        },
        "AvailabilityZone": {
          "Fn::Select": ["0", {
            "Fn::GetAZs": ""
          }]
        },
        "Tags": [{
            "Key": "Application",
            "Value": {
              "Ref": "AWS::StackName"
            }
          },
          {
            "Key": "Network",
            "Value": "Private"
          },
          {
            "Key": "Name",
            "Value": {
                "Fn::Sub": [ "${Environment}-Pri1", { "Environment": {"Ref" : "Environment" }} ]
            }
          }
        ]
      }
    },

    "PrivateSubnet2": {#프라이빗 서브넷 생성
      "DependsOn": ["VPC"],
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "CidrBlock": {
          "Fn::FindInMap": ["SubnetConfig", "Private2", "CIDR"]
        },
        "AvailabilityZone": {
          "Fn::Select": ["2", {
            "Fn::GetAZs": ""
          }]
        },
        "Tags": [{
            "Key": "Application",
            "Value": {
              "Ref": "AWS::StackName"
            }
          },
          {
            "Key": "Network",
            "Value": "Private"
          },
          {
            "Key": "Name",
            "Value": {
                "Fn::Sub": [ "${Environment}-Pri2", { "Environment": {"Ref" : "Environment" }} ]
            }
          }
        ]
      }
    },
  
    "NatGateway" : {#프라이빗 서브넷에선 외부 통신을 NAT 게이트웨이로 한다. 하나의 EIP를 주고 설정
      "DependsOn" : "VPC",
      "Type" : "AWS::EC2::NatGateway",
      "Properties" : {
        "AllocationId" : { "Fn::GetAtt" : ["EIP", "AllocationId"]},
        "SubnetId" : { "Ref" : "PublicSubnet1"},
		"Tags": [{
            "Key": "Application",
            "Value": {
              "Ref": "AWS::StackName"
            }
          },
          {
            "Key": "Network",
            "Value": "Private"
          },
          {
            "Key": "Name",
            "Value": {
                "Fn::Sub": [ "${Environment}-nat", { "Environment": {"Ref" : "Environment" }} ]
            }
          }
        ]
      }
    },
    
    "EIP" : {
      "Type" : "AWS::EC2::EIP",
      "Properties" : {
        "Domain" : "VPC"
      }
    },

    "PrivateRouteTable": {#프라이빗 라우팅 테이블 설정, 퍼블릭과 동일해서 아래는 생략하겠습니다.
      "DependsOn": ["VPC"],
      "Type": "AWS::EC2::RouteTable",
      "Properties": {
        "VpcId": { "Ref": "VPC" },
        "Tags": [{
            "Key": "Application",
            "Value": {
              "Ref": "AWS::StackName"
            }
          },
          {
            "Key": "Network",
            "Value": "Private"
          },
          {
            "Key": "Name",
            "Value": {
                "Fn::Sub": [ "${Environment}-Private", { "Environment": {"Ref" : "Environment" }} ]
            }
          }
        ]
      }
    },

    "PrivateRoute" : {
      "Type" : "AWS::EC2::Route",
      "Properties" : {
        "RouteTableId" : { "Ref" : "PrivateRouteTable" },
        "DestinationCidrBlock" : "0.0.0.0/0",
        "NatGatewayId" : { "Ref" : "NatGateway" }
      }
    },

    "PrivateSubnetRouteTableAssociation1": {
      "DependsOn": ["PrivateSubnet1", "PrivateRouteTable"],
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": {
        "SubnetId": {
          "Ref": "PrivateSubnet1"
        },
        "RouteTableId": {
          "Ref": "PrivateRouteTable"
        }
      }
    },

    "PrivateSubnetRouteTableAssociation2": {
      "DependsOn": ["PrivateSubnet2", "PrivateRouteTable"],
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": {
        "SubnetId": {
          "Ref": "PrivateSubnet2"
        },
        "RouteTableId": {
          "Ref": "PrivateRouteTable"
        }
      }
    }

  }
}

 

 

CloudFormation_template.json
0.01MB

이제 CloudFormation을 이용해서 직접 사용하는 과정을 보여주겠습니다.

1. CloudFormation 페이지에 가서 Create stack 클릭

 

2.

Template is ready

Upload a template file에서 파일 선택

 

3.CloudFormation의 stack 이름과 해당 파일에서 요구하는 Parameters값을 넣어준다

4.태그와 추가 옵션들이다

해당페이지는 입력을해도 되고 안해도된다.

다음 페이지는 리뷰페이지임으로 확인하고 생성을 하면된다.

다시 처음 탭에 돌아가보면

위와 같이 내가만든 스택이있고 클릭해서 보면 정보와 과정들이 있다

(삭제할때는 클릭하고 Delete만하면 CloudFormation으로 만든 설정들은 한번에 삭제된다)

특히 Event탭에 가면

내가 설정한게 생성되는 과정들을 볼 수 있다.

이 과정중에 VPC 대역 중복이나 JSON파일이 잘 못 되였다면 오류가 생기고 실패한다.

완료되면 리소스로 확인할수있다.

 

서브넷에 name도 잘들어가 있고 원하는 a, c az에 생성되었고 인터넷게이트웨이도 잘 연결되어있는걸 확인할수있다.

Public 존에 이제 서버를 만들고 바로 사용가능하다

매우 기본적인 설정이기때문에 한번쯤 자신의 서비스에 맞게 변경해서 만든다음 저장해둔다면 좋다.

기본적인 JSON 파일을 만들고 특별 서비스용으로 JSON파일들로 확장하면서 생성하면된다.

반응형