메뉴

문서정보

목차

소개

terrafom tutorial문서에서 아주 간단하게 사용방법을 알아봤다. 이제 좀 복잡한 인프라를 구성하면서 테라폼의 다양한 기능들을 살펴보려 한다. 이 문서는 terrafom tutorial를 기반으로 개선을 하는게 내용이므로 링크의 문서를 참고해야 한다.

테라폼으로 구성할 인프라는 아래와 같다.

 VPC 인프라

여기에서 사용한 예제의 원본은 여기에서 확인 할 수 있다. 원본의 내용을 개선하는 형태로 이루어진다.

버전

Terraform v0.11.13으로 테스트했다. (2019년 7월 2일)현재 최신버전은 v.12다. v.12 부터 for, if 문을 지원하는 등 변화가 크다.

가용영역 설정

ap-northeast-2a, ap-northeast-2b 두 개의 가용영역을 선택하기로 했다. 변수를 아래와 같이 정의했다. 가용 영역에 배열(list)를 사용했다.

Public subnet 정의

아래와 같이 퍼블릭 서브넷을 적용해보자. 거의 모든 terraform 리소스(resource)는 메타데이터 매개변수를 가지고 있다. count는 terrafrom의 count를 증가하면서 구문 블럭을 추가실행 하도록 해주는 매개변수다. HCL(HashCorp Configuration Language)는 선언적언어이기 때문에 루프나 if/else 문을 제공하지 않는다. 이는 인프라를 코드화하는 작업을 어렵게 만들 수 있다. count를 이용해서 루프를 실행 할 수 있다. 아래의 예제를 보자. 위 블럭을 일반언어로 바꾸면 대략 아래와 같이 표현할 수 있다.
for i := 0; i < 3; i++ {
  resource "aws_instance" "example" {
    ami = "ami-2d39803a"
    instance_type = "t2.micro"
  }
}

HCL은 내장 함수들을 제공한다. length는 HCL의 내장 함수 중 하나로 배열의 크기를 반환한다. 위 코드에서는 2가 반환될 것이다. cidrsubnet는 cidr 서브넷을 계산하는 내장 함수다.
cidrsubnet(prefix, newbits, netnum)
terraform console명령으로 함수를 테스트해볼 수 있다. element는 배열에서 아이템을 꺼낸다. 해석을 해보자.
  1. count : 가용영역(availability_zone)의 크기는 2이므로 이 리소스 블럭은 두 반복된다. for 루프문의 다른 구현이라고 볼 수 있겠다. 첫번째 실행에서는 ap-northeast-2a, 다은 번째 실행에서는 ap-northeast-2b가 될 것이다. 결론적으로 2개의 서브넷은 서로 다른 가용영역에 위치하게 될 것이다.
  2. cidr_block : count.index는 0, 1이 될 것이다. 결국 10.100.0.0/24, 10.100.1.0/24 두 개의 서브넷이 만들어진다.
  3. tags : Name 태그를 사용했다. 태그는 필터링, 분류, 과금, 통계 등을 위한 중요한 데이터다. 나중에 활용 할 수 있도록 자원에 대한 정보를 포함해야 한다. element를 이용해서 availability_zone을 가져오기로 했다.
Private subnet도 동일한 방법으로 구성했다.

NAT Gateway

Private subnet에 있는 인스턴스는 NAT Gateway를 통해서 인터넷과 통신 할 수 있다. 이를 위해서 필요한 요소는 아래와 같다. EIP를 만든다. Internet gateway가 만들어지고 난 다음에, EIP를 붙이도록 했다.

NAT gateway를 만든다. Private subnet 라우팅 테이블에 nat gateway로 향하는 룰(0.0.0.0/0을 nat gateway로)을 추가했다.

이제 라우팅 테이블에 각 subnet을 associate 하면 된다. 마지막으로 라우팅 테이블(aws_route_table.private)에 private subnet 을 associate 하면 된다. terraform plan, terraform apply 로 우리가 정의한 형상을 전개하자.

검증

제대로 만들어졌는지 검증해보자. vpc를 확인했다.
# aws ec2 describe-vpcs
{
    "Vpcs": [
        {
            "CidrBlock": "10.100.0.0/16",
            "DhcpOptionsId": "dopt-535a9438",
            "State": "available",
            "VpcId": "vpc-0b22c42f51fdb0dcc",
            "OwnerId": "522373083963",
            "InstanceTenancy": "default",
            "CidrBlockAssociationSet": [
                {
                    "AssociationId": "vpc-cidr-assoc-0d094cfcf3aadec7e",
                    "CidrBlock": "10.100.0.0/16",
                    "CidrBlockState": {
                        "State": "associated"
                    }
                }
            ],
            "IsDefault": false,
            "Tags": [
                {
                    "Key": "Name",
                    "Value": "test-vpc"
                }
            ]
        }

}
vpc-cidr-assoc-0d094cfcf3aadec7e의 subnet 정보다.
# aws ec2 describe-subnets --filters "Name=vpc-id,Values=vpc-0b22c42f51fdb0dcc"
{
    "Subnets": [
        {
            "AvailabilityZone": "ap-northeast-2a",
            "AvailabilityZoneId": "apne2-az1",
            "AvailableIpAddressCount": 250,
            "CidrBlock": "10.100.0.0/24",
            "DefaultForAz": false,
            "MapPublicIpOnLaunch": false,
            "State": "available",
            "SubnetId": "subnet-04a9e32c2d120e3db",
            "VpcId": "vpc-0b22c42f51fdb0dcc",
            "OwnerId": "522373083963",
            "AssignIpv6AddressOnCreation": false,
            "Ipv6CidrBlockAssociationSet": [],
            "Tags": [
                {
                    "Key": "Name",
                    "Value": "Public Subnet - ap-northeast-2a"
                }
            ],
            "SubnetArn": "arn:aws:ec2:ap-northeast-2:522373083963:subnet/subnet-04a9e32c2d120e3db"
        },
        {
            "AvailabilityZone": "ap-northeast-2a",
            "AvailabilityZoneId": "apne2-az1",
            "AvailableIpAddressCount": 251,
            "CidrBlock": "10.100.2.0/24",
            "DefaultForAz": false,
            "MapPublicIpOnLaunch": false,
            "State": "available",
            "SubnetId": "subnet-085a9890bad2c315f",
            "VpcId": "vpc-0b22c42f51fdb0dcc",
            "OwnerId": "522373083963",
            "AssignIpv6AddressOnCreation": false,
            "Ipv6CidrBlockAssociationSet": [],
            "Tags": [
                {
                    "Key": "Name",
                    "Value": "Private Subnet - ap-northeast-2a"
                }
            ],
            "SubnetArn": "arn:aws:ec2:ap-northeast-2:522373083963:subnet/subnet-085a9890bad2c315f"
        },
        {
            "AvailabilityZone": "ap-northeast-2b",
            "AvailabilityZoneId": "apne2-az2",
            "AvailableIpAddressCount": 251,
            "CidrBlock": "10.100.1.0/24",
            "DefaultForAz": false,
            "MapPublicIpOnLaunch": false,
            "State": "available",
            "SubnetId": "subnet-0c83fb7904b24fcd8",
            "VpcId": "vpc-0b22c42f51fdb0dcc",
            "OwnerId": "522373083963",
            "AssignIpv6AddressOnCreation": false,
            "Ipv6CidrBlockAssociationSet": [],
            "Tags": [
                {
                    "Key": "Name",
                    "Value": "Public Subnet - ap-northeast-2b"
                }
            ],
            "SubnetArn": "arn:aws:ec2:ap-northeast-2:522373083963:subnet/subnet-0c83fb7904b24fcd8"
        },
        {
            "AvailabilityZone": "ap-northeast-2b",
            "AvailabilityZoneId": "apne2-az2",
            "AvailableIpAddressCount": 251,
            "CidrBlock": "10.100.3.0/24",
            "DefaultForAz": false,
            "MapPublicIpOnLaunch": false,
            "State": "available",
            "SubnetId": "subnet-024e00d05b78a7b10",
            "VpcId": "vpc-0b22c42f51fdb0dcc",
            "OwnerId": "522373083963",
            "AssignIpv6AddressOnCreation": false,
            "Ipv6CidrBlockAssociationSet": [],
            "Tags": [
                {
                    "Key": "Name",
                    "Value": "Private Subnet - ap-northeast-2b"
                }
            ],
            "SubnetArn": "arn:aws:ec2:ap-northeast-2:522373083963:subnet/subnet-024e00d05b78a7b10"
        }
    ]
}
Public subnet과 Private subnet이 2개의 가용영역에 배치된 걸 확인 할 수 있다. NAT Gateway 정보를 확인해 보자.
#  aws ec2 describe-nat-gateways
{
    "NatGateways": [
        {
            "CreateTime": "2019-06-30T17:24:06.000Z",
            "NatGatewayAddresses": [
                {
                    "AllocationId": "eipalloc-02e98bc2373661a12",
                    "NetworkInterfaceId": "eni-010eae84a6d2d6b10",
                    "PrivateIp": "10.100.0.75",
                    "PublicIp": "13.125.104.150"
                }
            ],
            "NatGatewayId": "nat-086cb496e5638f1ab",
            "State": "available",
            "SubnetId": "subnet-04a9e32c2d120e3db",
            "VpcId": "vpc-0b22c42f51fdb0dcc",
            "Tags": []
        }
    ]
}
Public subnet에 전개된 것을 확인 할 수 있다.
aws ec2 describe-route-tables --filters "Name=vpc-id,Values=vpc-0b22c42f51fdb0dcc"
{
    "RouteTables": [
        {
            "Associations": [
                {
                    "Main": false,
                    "RouteTableAssociationId": "rtbassoc-0d88c73aacd13c265",
                    "RouteTableId": "rtb-06af924fba0573df9",
                    "SubnetId": "subnet-085a9890bad2c315f"
                },
                {
                    "Main": false,
                    "RouteTableAssociationId": "rtbassoc-041db9aaf61c917e4",
                    "RouteTableId": "rtb-06af924fba0573df9",
                    "SubnetId": "subnet-024e00d05b78a7b10"
                }
            ],
            "PropagatingVgws": [],
            "RouteTableId": "rtb-06af924fba0573df9",
            "Routes": [
                {
                    "DestinationCidrBlock": "10.100.0.0/16",
                    "GatewayId": "local",
                    "Origin": "CreateRouteTable",
                    "State": "active"
                },
                {
                    "DestinationCidrBlock": "0.0.0.0/0",
                    "NatGatewayId": "nat-086cb496e5638f1ab",
                    "Origin": "CreateRoute",
                    "State": "active"
                }
            ],
            "Tags": [
                {
                    "Key": "Name",
                    "Value": "Private Subnet Route Table"
                }
            ],
            "VpcId": "vpc-0b22c42f51fdb0dcc"
        },
        {
            "Associations": [
                {
                    "Main": false,
                    "RouteTableAssociationId": "rtbassoc-04b91f19661b8a7bf",
                    "RouteTableId": "rtb-0aec7d07ce3ea6efe",
                    "SubnetId": "subnet-04a9e32c2d120e3db"
                },
                {
                    "Main": false,
                    "RouteTableAssociationId": "rtbassoc-0ab3664a359182289",
                    "RouteTableId": "rtb-0aec7d07ce3ea6efe",
                    "SubnetId": "subnet-0c83fb7904b24fcd8"
                }
            ],
            "PropagatingVgws": [],
            "RouteTableId": "rtb-0aec7d07ce3ea6efe",
            "Routes": [
                {
                    "DestinationCidrBlock": "10.100.0.0/16",
                    "GatewayId": "local",
                    "Origin": "CreateRouteTable",
                    "State": "active"
                },
                {
                    "DestinationCidrBlock": "0.0.0.0/0",
                    "GatewayId": "igw-07a20b7d0c86d2850",
                    "Origin": "CreateRoute",
                    "State": "active"
                }
            ],
            "Tags": [
                {
                    "Key": "Name",
                    "Value": "Public Subnet Route Table"
                }
            ],
            "VpcId": "vpc-0b22c42f51fdb0dcc"
        }
}
Public Subnet Route Table를 보자. Private Subnet Route Table역시 최초에 설계한 모습 그대로 설정된 걸 알 수 있다.

정리

지금까지의 내용을 정리한다.