★★cloudNet@ 팀의 가시다 님이 진행하는 Terraform 101 Study 4기 내용과
한빛미디어 테라폼으로 시작하는 IaC 책을 참고하여 정리하였습니다.

 

데이터 소스

: 테라폼으로 정의되지 않은 외부 리소스 또는 저장된 정보를 테라폼 내에서 참조할 때 사용

: 데이터 소스 블록은 data로 시작하며 이후 데이터 소스 유형 정의 (Resource 블록 정의와 유사)
- 데이터 소스 유형은 첫 번째 _를 기준으로 앞은 프로바이더 이름, 뒤는 프로바이더에서 제공하는 리소스 유형
- 데이터 소스 유형을 선언한 뒤에는 고유한 이름을 붙인다. 리소스의 이름과 마찬가지로 이름은 동일한 유형에 대한 식별자 역할을 하므로 중복 X
- 데이터 소스 유형에 대한 구성 인수들은 {} 안에 선언. 인수가 필요하지 않은 경우에도 {}은 입력

 

    • 데이터 소스를 정의할 때 사용 가능한 메타인수
      - depends_on : 종속성 선언, 선언된 구성요소와의 생성 시점에 대해 정의
      - count : 선언된 개수에 따라 여러 리소스를 생성
      - for_each : map 또는 set 타입의 데이터 배열의 값을 기준으로 여러 리소스 생성
      - lifecycle : 리소스의 수명주기 관리
    • 실습 확인
      : 데이터 소스 참조 확인

terraform console

  • 데이터 소스 속성 참조
    - 데이터 소스로 읽은 대상을 참조하는 방식은 리소스와 구별되게 data가 앞에 붙는다
    속성 값은 다음과 같이 접근
    # Terraform Code
    data "<리소스 유형>" "<이름>" {
      <인수> = <값>
    }
    
    # 데이터 소스 참조
    data.<리소스 유형>.<이름>.<속성>

    - 코드 예시
    : 데이터 소스를 활용해 AWS 가용영역 인수를 정의 -> 리전 내에서 사용 가능한 가용영역 목록 가져오기
    # Declare the data source
    data "aws_availability_zones" "available" {
      state = "available"
    }
    
    resource "aws_subnet" "primary" {
      availability_zone = data.aws_availability_zones.available.names[0]
      # e.g. ap-northeast-2a
    }
    
    resource "aws_subnet" "secondary" {
      availability_zone = data.aws_availability_zones.available.names[1]
      # e.g. ap-northeast-2b
    }​
     
  • 예시 코드 확인 - AZ datasource

terraform state
꿀팁

: 테라폼 콘솔로 접속하지 않고도 data 리소스 조회 가능
# echo "data.aws_availability_zones.seoul.names" | terraform console

 

  • main.tf 파일 코드 수정
resource "local_file" "abc" {
  content  = "123!"
  filename = "${path.module}/abc.txt"
}

data "local_file" "abc" {
  filename = local_file.abc.filename
}

resource "local_file" "def" {
  content  = data.local_file.abc.content
  filename = "${path.module}/def.txt"
}

terraform state list
terraform console

: 궁금한 내용은 terraform console로 하여 확인해보자!

: def 파일이 abc 파일의 content를 참조하였으니 abc 의 content인 123! 가 def.txt에도 동일하게 확인 가능

 

입력 변수 Variable - 코드의 재사용성을 높일 때 사용

: 입력 변수는 인프라를 구성하는 데 필요한 속성 값을 정의해 코드의 변경 없이 여러 인프라를 생성하는 데 목적

: 입력 변수 Input Variables로 정의

: 변수는 variable로 시작되는 블록으로 구성
: 테라폼 예약 변수 이름으로 사용 불가능 : source, version, providers, count, for_each, lifecycle, depends_on, locals
(해당 이름들은 메타변수로 사용하기 때문에 변수 이름으로 사용 불가능)

# variable 블록 선언의 예
variable "<이름>" {
 <인수> = <값>
}

variable "image_id" {
 type = string
}

 

  • 변수 정의 시 사용 가능한 메타인수
    - default : 변수 값을 전달하는 여러 가지 방법을 지정하지 않으면 기본값이 전달됨
    기본값이 없으면 대화식으로 사용자에게 변수에 대한 정보를 물어봄
    - type : 변수에 허요오디는 값 유형 정의(string, number, bool, list, map, set, object, tuple)
    유형을 지정하지 않을 경우 any 유형으로 간주
    - description : 입력 변수의 설명
    - validation : 변수 선언의 제약조건을 추가해 유효성 검사 규칙을 정의
    - sensitive : 민감한 변수 값임을 알리고 테라폼의 출력문에서 값 노출을 제한 (민감데이터)
    - nullable : 변수에 값이 없어도 됨을 지정
  • 변수 유형 : 지원되는 변수의 범주와 형태
    1. 기본 유형
    - string : 글자 유형
    - number : 숫자 유형
    - bool : true 또는 false
    - any : 명시적으로 모든 유혀잉 허용됨을 표시
    2. 집합 유형
    - list(<유형>) : 인덱스 기반 집합
    - map(<유형>) : 값 = 속성 기반 집합이며 키값 기준 정렬
    - set(<유형>) : 값 기반 집합이며 정렬 키값 기준 정렬
    - object({<인수이름>=<유형>,...})
    - tuple ([<유형>,...]
    3. list와 set은 선언하는 형태가 비슷하지만 참조 방식이 인덱스와 키로 차이가 있고
    map와 set의 경우 선언된 값이 정렬되는 특징을 가짐

 

  • 입력 변수 사용 예시
variable "string" {
  type        = string
  description = "var String"
  default     = "myString"
}

variable "number" {
  type    = number
  default = 123
}

variable "boolean" {
  default = true
}

variable "list" {
  default = [
    "google",
    "vmware",
    "amazon",
    "microsoft"
  ]
}

output "list_index_0" {
  value = var.list.0
}

output "list_all" {
  value = [
    for name in var.list : upper(name)
  ]
}

variable "map" { # Sorting
  default = {
    aws   = "amazon",
    azure = "microsoft",
    gcp   = "google"
  }
}

variable "set" { # Sorting
  type = set(string)
  default = [
    "google",
    "vmware",
    "amazon",
    "microsoft"
  ]
}

variable "object" {
  type = object({ name = string, age = number })
  default = {
    name = "abc"
    age  = 12
  }
}

variable "tuple" {
  type    = tuple([string, number, bool])
  default = ["abc", 123, true]
}

variable "ingress_rules" { # optional ( >= terraform 1.3.0)
  type = list(object({
    port        = number,
    description = optional(string),
    protocol    = optional(string, "tcp"),
  }))
  default = [
    { port = 80, description = "web" },
  { port = 53, protocol = "udp" }]
}

terraform output

: 코드 확인 시 output > 2개 존재
: output "list_index_0" value =var.list.0 >>>> variable "list" 값의 첫번째 값 >> google
: output "list_all" for name in var.list : upper(name) >>> upper(변수 list의 전체 값) 
: upper를 사용할 경우 대문자로 변경하여 출력

 

  • 유효성 검사 : 사용자 지정 유효성 검사가 가능
    - 변수 블록 내에 validation 블록에서 조건인 condition에 지정되는 규칙이 true 또는 false를 반환
    condition 값의 결과가 false인 경우 error message 출력
    - regex 함수는 대상의 문자열에 정규식을 적용하고 일치하는 문자열을 반환
    여기에 can 함수를 함께 사용하면 정규식에 일치하지 않는 경우 오류 검출
    - validation 블록은 중복으로 선언 가능

variable "image_id" {
  type        = string
  description = "The id of the machine image (AMI) to use for the server."

  validation {
    condition     = length(var.image_id) > 4
    error_message = "The image_id value must exceed 4."
  }

  validation {
    # regex(...) fails if it cannot find a match
    condition     = can(regex("^ami-", var.image_id))
    error_message = "The image_id value must starting with \"ami-\"."
  }
}

1. ami 입력하였을 경우 error message 출력

2. ami- 입력하였을 경우 error message 출력

 

  • 변수 참조 : variable은 코드 내에서 var.<이름> 으로 참조
    : 선언된 변수를 참조해서 활용하려고 하면 앞에 코드 내에서 var. 으로 시작
variable "my_password" {}

resource "local_file" "abc" {
  content  = var.my_password
  filename = "${path.module}/abc.txt"
}

local_file.abc show

: 생성된 abc.txt 파일 내용 확인하면 내가 입력했던 my_password 값 확인 가능

terraform apply

: 기존 입력했던 qwe123 값에서 다시 terraform apply 하여 입력한 t101mypass 값으로 replaced 된 부분 확인

 

  • 민감한 변수 취급 : 입력 변수의 민감 여부 선언 가능
    : 기본값이 설정되어 있어 입력 항목(Enter a value)은 발생하지 않지만, 출력에서 참조되는 변수 값이(sensitive)로 감춰지는 것을 확인

sesitive 확인

: 민감한 변수로 지정해도 terraform.tfstate 파일에는 결과물이 평문으로 기록되므로 State 파일의 보안 유의
: terraform state, terrafrom console로 확인하여도 content 값이 sesitive 값으로 확인 됨

terraform tfstate 파일에서 확인 가능

  • 변수 입력 방식과 우선순위
    - variable의 목적은 코드 내용을 수정하지 않고 테라폼의 모듈적 특성을 통해 입력되는 변수로 재사용성을 높임
    - 사용자는 프로비저닝 실행 시에 원하는 값으로 변수에 정의 가능
    - 선언되는 방식에 따라 변수의 우선순위가 있으므로, 이를 적절히 사용해 로컬 환경과 빌드 서버 환경에서의 정의를 다르게 하거나, 프로비저닝 파이프라인을 구성하는 경우 외부 값을 변수에 지정

숫자가 작을수록 우선순위도 낮음

 

var1 입력 전
var1 입력 후 확인
variable 블록의 default 값이 있을 경우

 

시스템 환경 변수 등록 후 terraform apply

: 시스템 환경 변수로 저장
: 앞서 default로 추가한 var2 보다 시스템 환경 변수의 우선순위가 더 높음

 

#
echo 'my_var="var4"' > terraform.tfvars
cat terraform.tfvars

: 루트 모듈의 main.tf 파일과 같은 위치에 terraform.tfvars 파일을 생성해 변수에 대한 값을 추가하고 앞서 선언한 변수 선언과 비교하였을 때 terraform.tfvars에 정의된 변수가 우선순위가 더 높다

 

# a.auto.tfvars 파일 생성
echo 'my_var="var5_a"' > a.auto.tfvars
ls *.tfvars

# b.auto.tfvars 파일 생성
echo 'my_var="var5_b"' > b.auto.tfvars
ls *.tfvars

: terraform.tfvars 파일보다 *.auto.tfvars 파일의 우선순위가 더 높다
: a.auto.tfvars , b.auto.tfvars 파일이 있을 경우 a가 우선순위가 제일 낮음
: *.auto.tfvars 파일과 *.auto.tfvars.json 은 같은 우선 순위

 

#
terraform apply -auto-approve -var=my_var=var7
cat abc.txt ; echo

#
terraform apply -auto-approve -var=my_var=var7 -var=my_var=var8
cat abc.txt ; echo

: -var 인수에 지정 또는 -var-file로 파일 지정
: 여러 인수가 선언되는 경우 나중에 선언된 변수의 우선순위가 높다

# var9.txt 파일 생성
echo 'my_var="var9"' > var9.txt

#
terraform apply -auto-approve -var=my_var=var7 -var-file="var9.txt"
cat abc.txt ; echo

: *.tfvars와 같은 형식의 내용의 파일이라면 -var-file로 지정할 수 있으며 우선순위가 제일 높음

 

* .tfvars 확장자로 생성된 파일에 변수를 미리 기입하면 실행 시 입력해야 하는 변수 값을 하나의 파일에서 관리할 수 있음

 

VPC + 보안그룹 + EC2 배포 ★★★★★
목표 : default VPC 대신 직접 VPC를 만들고 해당 VPC내에 EC2 1대를 배포

1. vpc.tf 파일 생성

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

resource "aws_vpc" "myvpc" {
  cidr_block       = "10.10.0.0/16"

  tags = {
    Name = "t101-study"
  }
}

배포 후 vpc 확인
aws 웹콘솔에서 vpc 확인
DNS 호스트 이름 활성화를 위한 코드 수정
배포 후 DNS 호스트 이름 활성화됨으로 변경 확인

 

서브넷 배포
aws 웹콘솔에서 생성된 서브넷 확인

 

internet gateway 확인

: vpc.tf 파일 내에서 internet gateway 관련 resource 추가 후 배포

 

디폴트 라우팅 정보 추가
aws 웹콘솔에서 생성된 라우팅 확인

 

보안그룹 배포
배포한 EC2 확인

 

ec2 생성 확인

 

aws 웹콘솔에서 생성된 ec2 확인

 

 


error) Inconsistent dependency lock file

발생 원인 : terraform init을 하지 않고 plan이나 apply 하여 error 발생
해결 방법 : terraform init

 

Tip) echo "data.aws_ami.phj_amazonlinux2.id" | terraform console

terraform console 이용하여 값 확인