본문 바로가기

네트워크 & 클라우드/자동화

Terraform 기초 4 - Resource Block

Resource block


- resource block은 resource "type" "name" 구문으로 이뤄진다.

- type은 provider의 지정에 따라 달라진다. aws로 하면 aws_instance, aws_vpc 등의 type을 입력할 수 있다.

- name은 해당하는 resource type과 매칭되는 유니크한 명칭을 입력하면 된다.

  똑같은 name이라고 하더라도 type이 다르면 ok, 똑같은 name 똑같은 type은 no no hot hot.

#구문
resource
 "type" "name" {
 
}

#예시
resource "aws_vpc" "kgw_tf_vpc" {
 
}

 - 레지스트리에서 argument reference 부분을 보면, 필수요소(required)와 선택적요소(optional)가 있다.

   물론, vpc는 그런거 없다. optional만 있다.

   (https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc)

-  예시를 위해 aws_iam_policy resource의 argument reference를 알아본다.

   required라고 명시된 policy는 꼭 포함되어야 하는 인수이다.

- Arguments Resource를 구성하는 값들이다. 이를 input으로 친다면, Attribute output에 해당한다.

  vpc Attribute는 아래와 같다.

- 왜 output이라고 하는지 살펴보자.

   Attribute Reference 중 id는 vpc의 id값을 나타낸다.

   vpc_id값이 aws_subnet의 required인데, aws_vpc의 attribute인 id를 참조하여 값을 넣어줬다. 

   output 맞제? 

provider "aws" {
    region = "ap-northeast-1"
}

resource "aws_vpc" "kgw_tf_vpc" {
    cidr_block = "10.0.0.0/16"
}

resource "aws_subnet" "kgw_tf_subnet" {
    cidr_block = "10.0.1.0/24"
    vpc_id = aws_vpc.kgw_tf_vpc.id
}

 

- 구문은 아래와 같다.

<Resource Type>.<Name>.<Attribute>

Resource Type : aws_vpc
Name : kgw_tf_vpc
Attribute : id

 

- 지금까지 알아본 Resource Block Arguments(인수)들은 Resource를 생성하는데 필요한 요소이다.

  그렇다면 Resource 공통적인 Arguments들도 있지 않을까?

  ㅇㅇ 있음.

  그거시 바로 Meta-Arguments라는 것이다.

  

1) depends_on 

   - terraform은 종속성을 가지고 프로비저닝을 수행한다. 기본적으론 테라폼이 알아서 하고, 소스 순서를 바꿔도 동일하다.

     하지만 resource들의 실행 순서를 정하고 싶을때, depends_on을 통해서 정해줄 수 있다.

     명시적 종속성이라고 대충 네이밍을 해보자. 

 

 - 아래 코드를 실행하면 어떤 순서로 생성될까? 

resource "aws_s3_bucket" "kgw_tf_s3" {
  bucket = "kgw_bucket"
  acl    = "private"
}

resource "aws_instance" "kgw_tf_ec2" {
  ami           = "ami-0e9bfdb247cc8de84"
  instance_type = "t2.micro"
  }

 - 종속성 그래프는 아래와 같다.

 

 - 아래 코드를 실행하면 어떤 순서로 생성될까?

resource "aws_s3_bucket" "kgw_tf_s3" {
  bucket = "kgw_bucket"
  acl    = "private"
}

resource "aws_instance" "kgw_tf_ec2" {
  ami           = "ami-0e9bfdb247cc8de84"
  instance_type = "t2.micro"

  depends_on = [
    aws_s3_bucket.kgw_tf_s3
  ]
  }

- 종속 그래프가 달라졌다. 종속성에 따라 순서가 정해진다.

- 이 depends_on meta_argumets는 terraform이 종속성을 파악하기 어려운 상황에서 사용하면 된다. 당연히 특수한 경우이므로 comment 작성은 필수다. 마지막으로 굳이 depends_on을 쓰지 않고도 종속성을 명시적으로 수정할 수 있는 방안을 소개하고자 한다.

- 이처럼 s3의 bucket 이름을 ec2의 tags값을 참조하는 코드를 작성하면 자연스레 종속성을 지정할 수 있다.

resource "aws_s3_bucket" "kgw_tf_s3" {
    bucket = aws_instance.kgw_tf_ec2.tags.name
    acl    = "private"
}

resource "aws_instance" "kgw_tf_ec2" {
    ami           = "ami-0e9bfdb247cc8de84"
    instance_type = "t2.micro"

    tags = {
        name = "testkimtest"
    }
}

 

2) count

- 일반적으로 resource는 한번만 생성되지만, count meta-arguments를 사용하면 두려움은 없다.

- resource 안에 count를 숫자를 명시해주면, 그만큼 반복 생성된다.

- 아래는 s3를 3개 생성하는 코드이다.


resource "aws_s3_bucket" "kgw_tf_s3" {
    count = 3
    bucket = "testkim-${count.index+1}"
    acl    = "private"
}

 

- 결과 확인

- count를 써서 생성한 리소스들은 당연한 얘기지만, 소스 코드에서 name이 같기 때문에 인덱스 값을 붙여줘야한다.

   
   aws_s3_bucket.kgw_tf_s3[index].bucket
 

 

3) for_each

 - count와 동일하게 다양한 리소스를 여러 개 생성할 수 있게 해준다.

 - 다른점이라곤 map 이나 set을 값으로 가질 수 있다.

- set : 유일한 값을 요소로 갖는 list. ex) [1, 2, 3]
          each.key = member 값
          each.value = member 값

- map : key = value 형식의 list
            each.key = key 값
            each.value = value 값
# toset 사용
resource "aws_iam_user" "new-account" {
    for_each = toset( ["kgw", "testkim", "kimtest", "testkimtest"] )
    name     = each.key
    tags = {
      "dev" = each.value
    }
}

# map 사용
resource "aws_iam_user" "new-account-new" {
    for_each = {
      "kimkim" = "kimkim"
      "testtest" = "testtest"
    }
    name = each.key
    tags = {
        "dev" = each.value
        }
}

 

- 결과 확인

- for-each를 써서 생성한 리소스들은 당연한 얘기지만, 소스 코드에서 name이 같기 때문에 key 값을 붙여줘야한다.

   
   aws_iam_user.new-account[key].name
 

 

4) provider

- provider를 여러개 지정할 수 있다.

- 우선 default provider를 지정해주고, 추가로 설정하는 provider는 alias를 선언하여 alternate로 생성했다.

- resource 구문안에서 provider를 지정해서 alternate provider를 사용할 수 있다.

# default provider
provider "aws" {
    region = "ap-northeast-2"
}

# alternate provider
provider "aws" {
    alias = "tokyo"
    region = "ap-northeast-1"
}

# Ec2 instance - Seoul
resource "aws_instance" "kgw_tf_ec2-seoul" {
    ami           = "ami-0e9bfdb247cc8de84"
    instance_type = "t2.micro"
}

# Ec2 instance - Tokyo
resource "aws_instance" "kgw_tf_ec2-tokyo" {
    provider = aws.tokyo
    ami           = "ami-03f4fa076d2981b45"
    instance_type = "t2.micro"
}

- 결과확인

Seoul

Tokyo

 

5) lifecycle

- 말그대로 리소스의 생애주기를 설정하는 인자다. 3개 있다.

  • create_before_destory : terraform 기본 동작이 update가 불가할 경우 리소스를 삭제하고 다시 생성한다. 이 과정에서 해당인자를 사용하면, 먼저 리소스 생성 후에 기존 리소스를 삭제한다.
# create_before_destroy
resource "aws_instance" "kgw_tf_ec2_1" {
    ami           = "ami-0e9bfdb247cc8de84"
    instance_type = "t2.micro"
    lifecycle {
      create_before_destroy = true
    }
}

- 결과확인 : ami ubuntu에서 amazon-linux로 수정 후 terraform apply. 

                    instance 신규 생성 후 기존 instance 삭제 하는 것 확인

 

  • prevent_destroy : destroy를 못하게 한다. error발생한다.
# create_before_destroy
resource "aws_instance" "kgw_tf_ec2_1" {
    ami           = "ami-0e9bfdb247cc8de84"
    instance_type = "t2.micro"
    lifecycle {
      create_before_destroy = true
    }
}

- 결과 확인 : 삭제가 안된다.ㄷㄷ

 

  • ignore_changes : terraform과 console 등 다양한 방법으로 관리하고 있을 경우, console에서 수정한 값들은 terraform에 반영되지 않았을 것이다. 이에 terraform은 코드 내용 대로 다시 원복한다.
    그래서 ignore_changes로 인해 변경을 무시하여 원복 되지 않게끔 하는 것.

다른 인자들과 다르게 list 타입이며, list에 적은 arguments는 terraform에서 무시하여 update를 진행하지 않는다.

# ignore_changes
resource "aws_instance" "kgw_tf_ec2_3" {
    ami           = "ami-0e9bfdb247cc8de84"
    instance_type = "t2.micro"
    lifecycle {
      ignore_changes = [tags]
    }
}

- tags value를 변경

 

- 결과확인 : terraform apply 이후에 ingnore_changes = [tags]로 인해 해당 instance만 설정이 유지되는 것을 확인했다.