Terraform 가이드

 테라폼 사용을 위한 용어 설명 및 VPC 구성 하는 방법에 대한 설명


◎ Terrafrom이란?

인프라스트럭처를 코드로 작성, 계획, 생성하는 도구.

“Write, Plan and Create Infrastructure as Code”

환경 구성에 있어 필요한 리소스를 선언적인 코드로 작성하여 관리할 수 있다.

쉽게 말해 테라폼을 이용하면 개별로 VPC, EC2를 개별로 올리는게 아닌 코드로 내용 작성하여 일괄 생성 또는 제거(관리)를 할 수 있게 된다.

◎  용어 설명

- 프로비저닝[Provisioning] : 어떤 프로세스나 서비스를 실행하기 위한 준비 단계. 주로 테라폼은 네트워크나 컴퓨팅 자원을 준비하는 작업을 주로 다룸

- 프로바이더[Provider] : 테라폼과 외부 서비스를 연결해주는 기능을 하는 모듈. 테라폼으로 서비스에 접근하여 자원 생성등의 작업을 하기 위해서는 Provider가 먼저 셋업되어야 한다. AWS외 GCP, Azure와 같은 범용 클라우드 서비스 등 다양한 서비스를 지원

- 자원[Resource] : 특정 프로바이더가 제공해주는 조작 가능한 대상의 최소 단위. 예를 들어 AWS 프로바이더는 aws_instance 리소스 타입을 제공하고, 이 리소스 타입을 사용해 Amazon EC2의 가상 머신 리소스를 선언하고 조작하는 것이 가능

- HCL[Hashicorp Configuration Language] : HCL은 테라폼에서 사용하는 설정 언어이다. 파일의 확장자는 .tf를 사용하며 테라폼에서 모든 설정과 리소스 선언은 HCL을 사용해 이루어짐

- 계획[Plan] : 프로젝트 디렉터리 아래의 모든 .tf 파일의 내용을 실제로 적용 가능한지 확인하는 작업. 명령어를 실행하면 어떤 리소스가 생성되고, 수정되고, 삭제될지 계획을 보여줌

- 적용[Apply] : Plan이 실제로 적용가능한지 확인하는 작업이라면, Apply는 실제로 적용하는 명령어

- 삭제[Destroy] : tf파일로 생성된 모든 리소스들을 제거

◎  테라폼 기본 환경 구성 하기

1. Terraform 다운로드

    : 최신버전 다운로드 링크 : https://www.terraform.io/downloads.html

# wget https://releases.hashicorp.com/terraform/0.12.26/terraform_0.12.26_linux_amd64.zip
# unzip terraform_0.12.26_linux_amd64.zip
# rm terraform_0.12.26_linux_amd64.zip
# mv terraform /usr/bin
# chmod +x /usr/bin/terraform
# terraform -v


2. Terraform 프로젝트 디렉토리 생성

# mkdir ‘Dir Name’

# cd ‘Dir Name’


3. Provider 설정

: 프로바이더를 셋업한다. AWS 서비스에 접근하기 위하여 aws 프로바이더를 생성하였다.

# vim provider.tf

provider "aws" {                     # aws Provider 선언

     Access_key = "<ACCESS_KEY>"      # 개인 Access Key 입력

     secret_key = "<SECRET_KEY>"      # 개인 Secret Key 입력

     region  = "<REGION>"             # 리전 정보 입력

}


4. Terraform 초기화[ 명령어 :  terrafrom init ] 

    : 프로젝트를 초기화 한다. 생성된 프로바이더에 맞춰 필요한 플러그인들이 설치된다.

# terreform init

Initializing the backend...

Initializing provider plugins...

- Checking for available provider plugins...

- Downloading plugin for provider "aws" (hashicorp/aws) 2.65.0...

 

The following providers do not have any version constraints in configuration,

so the latest version was installed.

 

To prevent automatic upgrades to new major versions that may contain breaking

changes, it is recommended to add version = "..." constraints to the

corresponding provider blocks in configuration, with the constraint strings

suggested below.

 

* provider.aws: version = "~> 2.70"

 

Terraform has been successfully initialized!

 

You may now begin working with Terraform. Try running "terraform plan" to see

any changes that are required for your infrastructure. All Terraform commands

should now work.

 

If you ever set or change modules or backend configuration for Terraform,

rerun this command to reinitialize your working directory. If you forget, other

commands will detect it and remind you to do so if necessary.

◎  AWS 환경 구성(VPC)

1. VPC 구성(ex: vpc.tf)

resource "aws_vpc" "Terra-vpc" {

  cidr_block = "20.0.0.0/16"

  tags = {

    Name = "Terra-vpc"

  }

}

- resource "aws_vpc" "Terra-vpc"  : 리소스 ‘aws_vpc’를 선언 후, alias를 입력한다. 모든 tf파일 첫줄은 리소스 선언 > 별칭 지정으로 구성된다.

- cidr_block : 생성할 네트워크 IP와 Subnet 정보를 입력한다.

- tags : 콘솔화면에 출력 될 Tag를 입력한다.

볼드처리된 부분에 구성할 정보를 입력하면 된다.


2. Subnet 구성(ex: subnet.tf)

resource "aws_subnet" "Terra-subnet-pub-a" {

  vpc_id = "${aws_vpc.Terra-vpc.id}"

  cidr_block = "20.0.1.0/24"

  availability_zone = "ap-northeast-2a"

  tags = {

    Name = "Terra-Pub-A"

  }

 }

resource "aws_subnet" "Terra-subnet-pub-c" {

  vpc_id = "${aws_vpc.Terra-vpc.id}"

  cidr_block = "20.0.2.0/24"

  availability_zone = "ap-northeast-2c"

  tags = {

    Name = "Terra-Pub-C"

  }

}

- vpc_id : aws_vpc 리소스에 alias 된 vpc-id 값을 변수로 받는다.

- cidr_block : 생성된 vpc 내에서 구성할 서브넷 대역을 입력한다.

- availability_zone : 가용영역을 입력한다.

- tags : 콘솔화면에 출력 될 Tag를 입력한다.


3. Internet Gateway 구성(ex: igw.tf)

resource "aws_internet_gateway" "Terra-gateway" {

  vpc_id = "${aws_vpc.Terra-vpc.id}"

tags = {

    Name = "Terra-IGW"

  }

- 리소스 선언, vpc id 변수입력, Tags Name 지정하여 생성


4. NAT 구성(ex: nat.tf)

    > EIP 생성

           resource "aws_eip" "Terra-nateip" {

  vpc      = true

}

    > Subnet에 EIP 연결

resource "aws_nat_gateway" "Terra-natgw" {

  allocation_id = aws_eip.Terra-nateip.id

  subnet_id      = aws_subnet. Terra-subnet-pub-a.id

  tags = {

         Name = "terra-natgw"

  }

}


5. Route 구성(ex: route.tf)

    > 라우트 구성 후 IGW 연결

resource "aws_route_table" "Terra-route-table-pub" {

  vpc_id = "${aws_vpc.Terra-vpc.id}"

  route {

    cidr_block = "0.0.0.0/0"

    gateway_id = "${aws_internet_gateway.Terra-gateway.id}"

  }

tags = {

    Name = "Terra-route-Pub"

  }

}

    > Subnet  연결

 resource "aws_route_table_association" "Terra-public-route-a" {

  subnet_id      = aws_subnet.Terra-subnet-pub-a.id

  route_table_id = aws_route_table.Terra-route-table-pub.id

}

resource "aws_route_table_association" "Terra-public-route-c" {

  subnet_id      = aws_subnet.Terra-subnet-pub-c.id

  route_table_id = aws_route_table.Terra-route-table-pub.id

}


6. 보안그룹 구성(ex: securitygroup.tf)

resource "aws_security_group" "ssh" {

  vpc_id = "${aws_vpc.Terra-vpc.id}"

  name = "Terra-WEB-SG"

  ingress {

    from_port = 22

    to_port = 22

    protocol = "tcp"

    cidr_blocks = ["0.0.0.0/0"]

  }

  ingress {

    from_port = 80

    to_port = 80

    protocol = "tcp"

    cidr_blocks = ["0.0.0.0/0"]

  }

  ingress {

    from_port = 443

    to_port = 443

    protocol = "tcp"

    cidr_blocks = ["0.0.0.0/0"]

  }

  egress {

    from_port = 0

    to_port = 0

    protocol = "-1"

    cidr_blocks = ["0.0.0.0/0"]

  }

}

- ingress : 인바운드 규칙 생성

- egress : 아웃바운드 규칙 생성

- from_port : 시작포트

- to_port : 끝나는 포트

- protocol : 사용할 프로토콜. -1은 ALL

- cidr_blocks : 적용할 IP/Subnet 범위


7. Output 확인(ex: output.tf)

output "Terra-vpc-id" {

  value = "${aws_vpc.Terra-vpc.id}"

}

output "Terra-igw" {

  value = "${aws_internet_gateway.Terra-gateway.id}"

}

output "Terra-nateip" {

  value = "${aws_eip.Terra-nateip.id}"

}

output "Terra-natgw" {

  value = "${aws_nat_gateway.Terra-natgw.id}"

}

output "Terra-route-table-pub" {

  value = "${aws_route_table.Terra-route-table-pub.id}"

}

output "Terra-route-table-pri" {

  value = "${aws_route_table.Terra-route-table-pri.id}"

}

output "Terra-subnet-pub-a" {

  value = "${aws_subnet.Terra-subnet-pub-a.id}"

}

output "Terra-subnet-pub-c" {

  value = "${aws_subnet.Terra-subnet-pub-c.id}"

}

output "Terra-subnet-pri-a" {

  value = "${aws_subnet.Terra-subnet-pri-a.id}"

}

output "Terra-subnet-pri-c" {

  value = "${aws_subnet.Terra-subnet-pri-c.id}"

}

- Apply 이후 콘솔에 실제 적용된(생성된) ID를 확인 가능


8. 구성 사전 확인 [ 명령어 : terraform plan ]

    - HCL 형식에 맞지 않는다던지, 참조 위치가 잘못되어 있을경우 에러 화면을 출력


9. 적용단계 [ 명령어 : terrafrom apply ]

    - 계획(Plan) 단계에서 특이점이 없다면 terraform apply를 이용하여 실제 aws 환경에 적용. 이후 콘솔에서 적용내용 확인


<VPC 생성 확인>


 <서브넷 생성 확인>

 <라우팅 테이블 생성 확인>

 <보안그룹 생성 확인>


10. 삭제 [명령어 : terraform destroy]

    - 해당 명령어를 이용하면 콘솔내 생성된 Terraform 정보가 모두 삭제



이처럼 "VPC만" 구성하기 위해 정의한 tf파일만 해도 5가지가 넘는다. 여기에 EC2나 RDS같은 내용까지 구성한다고 하면 tf파일의 개수는 정신없이 늘어날 것이다.

예를 들어, 만약 동일한 3-Tier 구성을 다른 리전에 해야하는 상황이 있을 경우 VPC 생성, Subnet, Route, 보안그룹, EC2, LB등은 모두 동일하나 내부 IP정보같은 파라미터만 다르다.

단지 IP 정보만 수정하면 되는걸 tf파일을 일일히 하나하나 카피해야하는 복잡함이 생긴다. 이를 해결하기 위해 Module이라는 개념이 나오게 된다.

사용할 리소스를 하나의 tf로 정의하여 모듈로 구성하고(main.tf), 구성된 모듈을 사용할때 입력받을 변수를 정의한다(variable.tf). 그리고 이 구성된 모듈을 기반으로 파라미터 정보가 있는 tf파일을 생성(data.tf)하여 apply 시킨다.

이렇게 모듈화 해놓게 되면, 이후 동일한 구성을 다른 리전에서 생성할 경우 data.tf의 내용만 수정하면 손쉽게 생성할 수 있게 된다. 이 내용에 대해서는 다음 가이드 문서에서 설명한다.