terraform 참고 팁 및 간단한 가이드 (2018)

설치, 설정

AWS 설정

사용하는 AWS key는 named profiles 를 이용하여 terraform 코드에 설정을 하도록 한다. 사용자가 실수로 terraform 코드를 잘못 실행하는 것을 방지하기 위한 목적이다.

terraform plugin_cache_dir 설정

terraform init 명령을 실행한 경우 현재 작업 디렉토리의 .terraform 디렉토리에  plugins(aws provider 등)를 다운로드 받는다. 

그래서 terraform 코드가 있는 디렉토리 별로 provider를 따로 다운로드 받기 때문에 시간이 많이 걸린다.

홈디렉토리의 .terraformrc 파일에 plugin cache 설정을 해서 사용을 하면  특정 디렉토리에 plugins를 다운로드 받고 공유해서 사용할 수 있다.

이 디렉토리는 terraform이 자동생성하지 않기 때문에 수동으로 생성을 해 주어야 한다.

https://www.terraform.io/docs/commands/cli-config.html

$ cat ~/.terraformrc plugin_cache_dir = "$HOME/.terraform.d/plugin-cache" $ mkdir -p $HOME/.terraform.d/plugin-cache $ pwd /home/taejoon/terraform_test $ tree .terraform/ .terraform/ └── plugins ├── registry.terraform.io │   └── hashicorp │   ├── aws │   │   └── 3.12.0 │   │   └── linux_amd64 -> /home/taejoon/.terraform.d/plugin-cache/registry.terraform.io/hashicorp/aws/3.12.0/linux_amd64 │   └── tls │   └── 3.0.0 │   └── linux_amd64 -> /home/taejoon/.terraform.d/plugin-cache/registry.terraform.io/hashicorp/tls/3.0.0/linux_amd64 └── selections.json 17 directories, 6 files $ du -sh ~/.terraform.d/plugin-cache/registry.terraform.io/hashicorp/aws/* 156M /home/taejoon/.terraform.d/plugin-cache/registry.terraform.io/hashicorp/aws/3.11.0 157M /home/taejoon/.terraform.d/plugin-cache/registry.terraform.io/hashicorp/aws/3.12.0

terraform 사용하기

terraform을 사용할 때 처음부터 코드를 새로 짜는 것보다는 terraform module 을 참고한다.

외부 모듈을 쓰는 것이 확실하게 좋은 경우가 아니라면 가급적 직접 코드를 짜는 것이 좋을 수 있다.  일부 리소스는 직접 만들고 일부 리소스는 외부 모듈을 이용하는 경우 혼란스러울 수 있다.

  1. terraform module registry  https://registry.terraform.io/browse?provider=aws : Verified 는 사용을 해도 좋지만 그 외의 것은 코드 수준이 다양하므로 코드를 보고 판단해야 한다.

  2. best practicces terraform : https://github.com/hashicorp/best-practices/tree/master/terraform : 현재 deprecated 이고 terraform module registry를 참고하라고 하지만 terrafrom 전체적인 코드를 보기에는 도움이 된다.

  3. terraform examples https://github.com/terraform-providers/terraform-provider-aws/tree/master/examples

  4. github 등에서 검색

엔터프라이즈 환경에서 terraform 사용하기

https://www.terraform.io/docs/enterprise/guides/recommended-practices/index.html (한글자료 https://blog.outsider.ne.kr/1333)

https://learn.hashicorp.com/terraform/development/running-terraform-in-automation

https://learn.hashicorp.com/terraform/operations/maintaining-multiple-environments

terraform workspace 활용 https://www.terraform.io/docs/state/workspaces.html

디렉토리 구조

....

환경구분 : prod , staging , ......

remote state 설정

https://www.terraform.io/docs/state/remote.html

terraform 에서는 기본으로는 terraform.tfstate 파일을 로컬에 저장한다. 여러 명이 함께 협업을 할 경우에는 불편한 부분이 있으며 remote state를 설정해서 state 데이터를 원격의 저장소에 놓고 사용을 할 수가 있다. remote state 를 지원하는 backend type 은 consul, s3 등이 있다. 

consul의 경우에는 remote state + locking을 지원하고 s3를 이용하는 경우에는 locking도 사용하려면 DynamoDB 도 함께 써야 한다. s3에서 버저닝 기능을 이용하면 예전의 state 파일로 복구 가능한 장점이 있다.

코드 가이드라인

README 파일 만들기 : 코드를 보고 판단 가능한 경우는 생략해도 되지만 설명이 필요한 경우는 README 파일 필수

main.tf : variables, data, module 호출. output.  작업 성격에 따라서 main.tf 의 내용을 특정 AWS resource에 따라 여러 개의 파일로 구분할 수 있다.

provider.tf : region, profile 지정

terraform.tfvars : 변수

backend.tf : remote state 설정



AWS key는 provide 의 profile에 지정을 한다.



$ cat provider.tf

provider "aws" {

  region  = "${var.region}"

  profile = "${var.profile}"

}





다른 AWS  리소스 정보가 필요할 경우 변수를 하드코딩 하는 것보다는 data source 를 이용하여 tag 등에서 검색을 해서 가져오는 것이 좋다. 그러면 prod, staging 에 상관없이 동일한 코드를 짤 수 있다.



data "aws_vpc" "selected" {

  filter {

    name   = "tag:Name"

    values = ["${var.vpc_name}"]

  }

}

 

...

  vpc_id      = "${data.aws_vpc.selected.id}"

...





각 리소스를 조건에 따라 생성, 삭제할 수 있게 count 변수를 잘 활용하면 편리하다. 예를 들어 staging 에는 만들 필요가 없고 prod 에만 특정 리소스가 필요할 경우  staging 에서는 count 를 0으로 설정을 하면 된다. 모듈에 있는 코드들은 보통 이런 식으로 구현을 해 놓았다.



https://github.com/jonbrouse/terraform-style-guide 등 참고.

Strings are in double-quotes.

Spacing : Use 2 spaces 

Resource Block Alignment

Terraform resource name :  underscore(_) 사용



resource "aws_security_group" "security_group" {

...





resource 의  name 에는  hyphen(-)  사용. 



resource "aws_security_group" "security_group" {

 name = "${var.resource_name}-security-group"

...





https://github.com/hashicorp/best-practices/tree/master/terraform/providers/aws/us_east_1_prod



참고로 terraform 의 terraform fmt 명령을 이용하면 자동으로 코드 스타일을 맞출 수 있다. 이런 부분을 commit hook에 넣어서 사용할 수도 있겠다.



$ terraform fmt test.tf



lifecycle

create_before_destroy :   새로운 리소스를 먼저 생성하고 기존의 리소스 삭제.



ignore_changes 

terraform 에서 리소스의 설정 내용 중 변경사항이 있으면 해당 리소스를 삭제하고 다시 생성한다. 특정 속성의 변경사항이 있어도 해당 리소스를 재생성하는 것을 막으려면 lifecycle 에서 ignore_changes 를 이용하면 된다.

https://www.terraform.io/docs/configuration/resources.html



$ cat sample.tf

resource "aws_instance" "service" {

  instance_type          = "${var.instance_type}"

  ami                    = "${lookup(var.amis, var.os)}"

  key_name               = "${var.aws_key_pair}"

  subnet_id              = "${var.subnets}"

  vpc_security_group_ids = ["${var.security_group_ids}"]

  iam_instance_profile   = "${data.aws_iam_instance_profile.ec2_common_iam_instance_profile.name}"

 

  user_data = "${data.template_cloudinit_config.config.rendered}"

 

  tags {

    Name        = "${var.name}"

    Owner       = "${var.owner}"

    Environment = "${var.environment}"

  }

 

  lifecycle {

    ignore_changes = ["ami","user_data"]

  }

 

}



terraform module  - AWS



terraform module  - AWS

Verified 는 사용을 해도 좋지만 그 외의 것은 코드 수준이 다양하므로 코드를 보고 판단해야 한다.

https://registry.terraform.io/browse?provider=aws&verified=true

terraform module registry를 이용하지 않는다고 하더라도 재사용 가능한 코드가 있는 경우에는 module을 이용하는 것이 좋다. 

https://www.terraform.io/docs/modules/create.html

어떤 경우 모듈을 짜는게 좋은지는 https://www.terraform.io/docs/enterprise/guides/recommended-practices/part3.2.html 문서 참고.

아키텍쳐 패턴일 경우

VPC, RDS cluster 등 여러개의 설정이 필요한 서비스

EC2+ELB, autoscalinig group 등과 같이 여러 리소스 타입에 대해서 별도 설정이 필요한 경우

Terraform 디버깅

https://www.terraform.io/docs/internals/debugging.html

TF_LOG 환경변수로 설정할 수 있다. log level : TRACEDEBUGINFOWARN or ERROR



$ export TF_LOG=DEBUG ; terraform plan