2주차 테라폼 기초 - 데이터 소스/ 입력 변수 variable/ local 지역 값/ 출력/ 반복문
1. 데이터 소스
테라폼으로 정의 되지 않은 외부 리소스 혹은 저장된 정보를 테라폼 내에서 참조해야 될때 사용합니다.
data "local_file" "abc" { // 데이터 소스 블록은 data 로 시작,
// 데이터 소스 유형은 `프로바이더이름_리소스 유형`
filename = "${path.module}/abc.txt" // 구성 인수들은 { } 안에 선언
}
A. 데이터 소스 구성
1. 데이터 소스를 생성해서 참조를 해보자!!
data "local_file" "abc" {
filename = "${path.module}/abc.txt"
}
echo "t101 study - 2week" > abc.txt

terraform console
> //
data.local_file.abc
의 해당 결과를 보여준다!
B. 데이터 소스 속성 참조
1. 리소스와 는 달리 앞에 data
가 붙는것을 눈여겨 봐야합니다.
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
}

다음 링크를 사용하면 다른 리소스들도 쉽게 참조 할 수 있다.
2. 입력 변수 Variable
A. 변수 선언 방식
인프라를 구성하는 데 필요한 속성 값을 정의해 여러 인프라를 구성하기 위해 입력 변수를 가집니다.
# variable 블록 선언의 예
variable "<이름>" {
<인수> = <값>
}
variable "image_id" {
type = string
}
예외 이름들:
source, version, providers, count, for_each, lifecycle, depends_on, locals
변수 정의 시 사용 가능한 메타인수
default : 변수 값을 전달하는 여러 가지 방법을 지정하지 않으면 기본값이 전달됨, 기본값이 없으면 대화식으로 사용자에게 변수에 대한 정보를 물어봄
type : 변수에 허용되는 값 유형 정의, string number bool list map set object tuple 와 유형을 지정하지 않으면 any 유형으로 간주
description : 입력 변수의 설명
validation : 변수 선언의 제약조건을 추가해 유효성 검사 규칙을 정의
sensitive : 민감한 변수 값임을 알리고 테라폼의 출력문에서 값 노출을 제한 (암호 등 민감 데이터의 경우)
nullable : 변수에 값이 없어도 됨을 지정
B. 변수 유형
지원되는 변수의 유형
기본 유형
string : 글자 유형
variable "string" {
type = string
default = "String"
}
number : 숫자 유형
variable "number" {
type = number
default = 123
}
bool : true 또는 false
variable "boolean" {
default = true
}
any : 명시적으로 모든 유형이 허용됨을 표시
집합 유형
list: list를 나타내는 집합
variable "list" {
default = [
"google",
"vmware",
"amazon",
"microsoft"
]
}
map: hashmap 같은 집합
variable "map" { # Sorting
default = {
aws = "amazon",
azure = "microsoft",
gcp = "google"
}
}
set : set 을 나타내는 집합
variable "set" { # Sorting
type = set(string)
default = [
"google",
"vmware",
"amazon",
"microsoft"
]
}
object : 복잡한 키 밸류 값을 나타내는 집합
variable "object" {
type = object({ name = string, age = number })
default = {
name = "abc"
age = 12
}
}
tuple: 간단한 배열을 나타내는 집합
variable "tuple" {
type = tuple([string, number, bool])
default = ["abc", 123, true]
}
C. 유효성 검사
변수에 대한 유효성 검사
variable "AMIID" {
type = string
description = "AMI ID"
validation {
condition = length(var.AMIID) > 5
error_message = "SHOULD exceed 5"
}
}
D. 변수 참조
선언되지 않은 변수는 입력 인자를 받게끔 프롬트가 뜨게된다!
variable "my_password" {}
resource "local_file" "abc" {
content = var.my_password
filename = "${path.module}/abc.txt"
}
terraform init -upgrade && terraform apply -auto-approve
var.my_password
Enter a value: qwe123
E. 민감한 변수 취급
입력 변수에 대한 민감한 정보 포함 여부도 표현할 수 있다.
아래와 같이 RUNNING 시에 해당 값이 가려지게 된다!
variable "my_password" {
default = "password"
sensitive = true
}
resource "local_file" "abc" {
content = var.my_password
filename = "${path.module}/abc.txt"
}
terraform apply -auto-approve // SENSITIVE는 가려짐
...
~ content = (sensitive value)
...
terraform state show local_file.abc // 여기서도 가려짐
echo "local_file.abc.content" | terraform console
하지만, terraform.tfstate 파일에서는 해당값이 표현이 된다!
해당 파일은 안전하게 보관이 되어야하는 방법을 생각해볼 수 있다.
보통은 s3에 담고 read를 못하게끔 제한 할 수 있을것같다.
F. 변수 입력 방식과 우선순위
variable는 입력변수로 적절하게 우선순위를 이용해서 환경에 따른 정의를 해줄 수 있습니다.
Env
1 제일 낮음
terraform.tfvars
2
terraform.tfvars.json
3
.auto.tfvars
4
-var 혹은 -var-file
5 제일 높음
1. env (실행 후 입력)
var.my_var
Enter a value: var1
2. default 값
variable "my_var" {
default = "var2"
}
3. 환경 변수 (TF_VAR 변수 이름)
export TF_VAR_my_var=var3
echo $TF_VAR_my_var
4. terraform.tfvars에 정의된 변수 선언
echo 'my_var="var4"' > terraform.tfvars
cat terraform.tfvars
5. *.auto.tfvars에 정의된 변수 선언
echo 'my_var="var5_b"' > b.auto.tfvars
ls *.tfvars
6. *.auto.tfvars.json에 정의된 변수 선언
# a.auto.tfvars.json 파일 생성
cat <<EOF > a.auto.tfvars.json
{
"my_var" : "var6_a"
}
EOF
ls *.tfvars ; ls *.json
7. CLI 실행 시 -var 인수에 지정 또는 -var-file로 파일 지정
terraform apply -auto-approve -var=my_var=var7
cat abc.txt ; echo
3. local 지역 값
A. local 선언
local 변수
는 외부에서 입력되지 않고, 코드 내에서만 동작하는 값으로 사용됩니다.
// 1. 선언되는 블록은 locals로 시작 (로컬 변수 이름은 전체 루트 모듈 내에서 유일)
locals {
content = "${var.prefix} ${local.name}"
}
locals {
content = "content2" // 중복 선언되어서는 안된다.
}
B. local 참조
local 변수
는local.<이름>
으로 참조할 수 있다.
locals {
name = "terraform"
}
resource "local_file" "abc" {
content = local.content
filename = "${path.module}/abc.txt"
}
변수 우선 순위 실습
서로 다른 테라폼 파일에서 로컬 값이 참조가 가능하고, 로컬값이 파편화되면 유지보수가 어려워진다.
local은 어떻게 사용해야 될까??
4. 출력 output
A. output 선언
프로비저닝 수행 후의 결과 속성 값을 확인하는 용도로 사용한다.
output 선언으로 모듈 내에서 생성되는 속성 값들을 정의 할 수 있다.
output "instance_ip_addr" {
value = "http://${aws_instance.server.private_ip}"
}
속성 값은 프로비저닝이 완료되어야 최종적으로 결과를 확인이 가능하다!
다음과 같은 옵션을 줄 수 있다.
description : 출력 값 설명
sensitive : 민감한 값으로 출력 제한
depends_on : value에 담길 값이 특정 구성에 종속성이 있는 경우 생성되는 순서를 임의로 조정
precondition : 출력 전에 조건 검증
B. output 활용 & abspath 함수
abspath : 절대 경로로 변환하는 함수
output "file_abspath" {
value = abspath(local_file.abc.filename)
}
다음과 같은 결과값으로 표기가 된다.
Changes to Outputs:
+ file_abspath = "/Users/simon/Downloads/workspaces/3.8/abc.txt"
+ file_id = (known after apply)
5. 반복문
list 형태의 값 목록을 반복문으로 쉽게 관리할 수 있다.
A. count
resource "local_file" "abc" {
count = 5
content = "abc"
filename = "${path.module}/abc.txt"
}
count 값이 선언된 만큼 리소스를 생성하게 됩니다.
하지만 위의 코드로 apply하게되면 한개의 파일만 생성되게 됩니다.

resource "local_file" "abc" {
count = 5
content = "This is filename abc${count.index}.txt"
filename = "${path.module}/abc${count.index}.txt"
}
다음의 코드를 생성하게 되면 각각 다른 리소스들이 5개 생성됩니다.

리소스를 참조하는 방법
echo "local_file.abc" | terraform console
echo "local_file.abc[0].content" | terraform console // <리소스 타입>.<이름>[<인덱스 번호>]
echo "local_file.abc[2].content" | terraform console
주의사항
중간에 값이 삭제되면 해당 값에 대한 리소스만 삭제되는 것이 아니라 이후의 정의된 리소스들도 삭제되고 재생성된다고 합니다.
6. 실습
A. VPC + 보안그룹 + EC2 배포
default VPC 대신 직접 VPC를 만들고, 해당 VPC내에 EC2 1대를 배포
보안 그룹 생성
보안 그룹 배포
ec2 생성
배포 후 ec2 생성 확인
1. VPC 생성을 위해서 vpc.tf 파일을 생성합니다.
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_vpc" "myvpc" {
cidr_block = "10.10.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "t101-study"
}
}
2. 보안그룹 생성을 위해 sg.tf 파일을 생성합니다.
resource "aws_security_group" "mysg" {
vpc_id = aws_vpc.myvpc.id
name = "T101 SG"
description = "T101 Study SG"
}
resource "aws_security_group_rule" "mysginbound" {
type = "ingress"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.mysg.id
}
resource "aws_security_group_rule" "mysgoutbound" {
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.mysg.id
}
output "aws_security_group_id" {
value = aws_security_group.mysg.id
}

ec2 생성을 위해 ec2.tf 를 생성합니다.
data "aws_ami" "my_amazonlinux2" {
most_recent = true
filter {
name = "owner-alias"
values = ["amazon"]
}
filter {
name = "architecture"
values = ["x86_64"]
}
owners = ["amazon"]
}
resource "aws_instance" "myec2" {
ami = data.aws_ami.my_amazonlinux2.id
instance_type = "t2.micro"
vpc_security_group_ids = ["${aws_security_group.mysg.id}"]
subnet_id = aws_subnet.mysubnet1.id
user_data = <<-EOF
#!/bin/bash
wget https://busybox.net/downloads/binaries/1.31.0-defconfig-multiarch-musl/busybox-x86_64
mv busybox-x86_64 busybox
chmod +x busybox
nohup ./busybox httpd -f -p 80 &
EOF
user_data_replace_on_change = true
tags = {
Name = "t101-myec2"
}
}
output "myec2_public_ip" {
value = aws_instance.myec2.public_ip
description = "The public IP of the Instance"
}


B. AWS IAM User 3명 생성/ 반복문 실습
```
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_iam_user" "myiam" {
count = 3
name = "myuser.${count.index}"
}
```
iamuser를 3명 생성합니다.

```
variable "user_names" {
description = "Create IAM users with these names"
type = list(string)
default = ["gasida", "akbun", "hyungwook"]
}
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_iam_user" "myiam" {
count = length(var.user_names)
name = var.user_names[count.index]
}
```

위와 같이 length 와 index를 활용해서 리소스 배열에 대한 IAM 유저를 생성할 수 있습니다.
variable "user_names" {
description = "Create IAM users with these names"
type = list(string)
default = ["gasida", "akbun", "hyungwook"]
}
// 위에서 밑으로 'AKBUN'을 제거하고 PLAN 하게 되면
// 모든 리소스를 삭제한 다음 해당 리소스를 처음부터 다시 만듬.
variable "user_names" {
description = "Create IAM users with these names"
type = list(string)
default = ["gasida", "hyungwook"]
}
// User with name hyungwook already exists -> 오류가 생성되면서 리소스 재생성함
C. 간단한 예제보다는 실제 예제를 통한 반복문 학습(악분님 감사합니다!)
``` main.tf
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
tags = {
Name = "terraform VPC"
}
}
resource "aws_subnet" "main" {
count = length(var.subnets) // 2. 서브넷 마다 값들을 저장해두고 꺼내서 사용가능합니다!
vpc_id = aws_vpc.main.id
cidr_block = var.subnets[count.index].cidr
availability_zone = var.subnets[count.index].az
tags = var.subnets[count.index].tags
}
output "myvpc_id" {
value = aws_vpc.main.id
}
```
``` terraform.tfvars
vpc_cidr = "192.168.0.0/16"
subnets = [
{
cidr = "192.168.1.0/24",
az = "ap-northeast-2a",
tags = {
Name = "public-subnet"
Environment = "dev"
}
},
{
cidr = "192.168.2.0/24",
az = "ap-northeast-2c",
tags = {
Name = "private-subnet"
Environment = "dev"
}
}
]
```
``` variables.tf
variable "vpc_cidr" {
type = string
}
variable "subnets" { // 3. 다음과 같이 subnet에 대한 object를 생성해주기
type = list(object({ // subnet 설정 변수를 한 변수로 설정하도록 설정
cidr = string
az = string
tags = map(string)
}))
}
```

다음과 같이 깔끔하게 변수들로 vpc를 생성할 수 있습니다.
D. 주의사항: COUNT로 생성한 그룹은 임의로 변경하게 되면 모두 삭제되고 재 생성됩니다.
예시
subnets = [
#
# {
# cidr = "192.168.1.0/24",
# az = "ap-northeast-2a",
# tags = {
# Name = "public-subnet"
# Environment = "dev"
# }
# },
# {
# cidr = "192.168.5.0/24",
# az = "ap-northeast-2a",
# tags = {
# Name = "public-subnet"
# Environment = "dev"
# }
# },
{
cidr = "192.168.2.0/24",
az = "ap-northeast-2a",
tags = {
Name = "private-subnet"
Environment = "dev"
}
},
// 만약 다음과 같이 두개의 요소들에 대해서 주석처리하고 terraform apply 하게 되면
밑의 그림과 같이 인덱스값이 한칸씩 땡겨온다.
// 그로인해, RESOURCE 값이 제대로 생성되있지 않은것으로 보고, 모두 재생성하게 됩니다.

예상치 못한 장애 요소를 만날 수 있으니 foreach를 사용하라는 조언과 함께 2주차의 스터디는 마무리가 됐다.
Last updated