데이터 소스
Terraform의 데이터 소스는 테라폼 설정 내에서 읽기 전용의 값들을 제공한다. 이 값을 활용하면 이미 존재하는 리소스의 세부사항이나 외부 데이터를 참조할 수 있다.
데이터 소스 블록은 아래처럼 data로 시작하고 ‘데이터 소스 유형’과 '이름'을 정의한다.
data "<리소스 유형>" "<이름>" {
<인수> = <값>
}
# 참조 : data.<리소스 유형>.<이름>.<속성>
# 사용가능한 메타인수:
# depends_on : 종속성 선언
# count : 선언된 개수만큼 리소스를 생성
# for_each : map또는 set 타입 변수로 리소스 반복 생성
# lifecycle : 리소스 수명주기
예를 들면 아래 코드는 aws의 az 정보를 얻어와 각 az에 subnet을 생성할 수 있다.
data "aws_availability_zones" "available" {
state = "available"
}
resource "aws_subnet" "primary_AZ" {
availability_zone = data.aws_availability_zones.available.names[0]
}
resource "aws_subnet" "secondary_AZ" {
availability_zone = data.aws_availability_zones.available.names[1]
}
연습 코드 :
- data 모듈로 az 이름 받아와서 vpc, subnet 생성하기
data "aws_availability_zones" "available" {
state = "available"
}
resource "aws_vpc" "hwan001-vpc" {
cidr_block = "10.10.0.0/16"
tags = {
Name = "hwan001-vpc"
}
}
resource "aws_subnet" "primary_az" {
vpc_id = aws_vpc.hwan001-vpc.id
cidr_block = "10.10.1.0/24"
availability_zone = data.aws_availability_zones.available.names[0]
tags = {
Name = "hwan001-subnet-1"
}
}
resource "aws_subnet" "secondary_az" {
vpc_id = aws_vpc.hwan001-vpc.id
cidr_block = "10.10.2.0/24"
availability_zone = data.aws_availability_zones.available.names[1]
tags = {
Name = "hwan001-subnet-2"
}
}
변수(Variables) 종류 및 우선순위
변수 종류 :
변수 종류는 크게 기본 유형과 집합 유형으로 나뉜다.
기본 유형에는 string, number, bool, any가 있고, 집합 유형에는 list, map, set, object, tuple이 있다.
변수 정의할 땐 아래 메타인수가 사용 가능하다.
- default : 값이 전달되지 않은 경우의 기본 값, default가 없으면 apply 시 변수에 대한 정보를 물어봄
- type : 변수 유형 정의, string number bool list map set object tuple 와 유형을 지정하지 않으면 any 유형으로 간주
- description : 입력 변수의 설명
- validation : 변수 선언의 제약조건을 추가해 유효성 검사 규칙을 정의
- sensitive : 민감한 변수 값으로 테라폼의 출력문에서 값 노출을 제한함 (암호 등 민감 데이터의 경우)
- nullable : 변수에 값이 없어도 됨 (null 허용 여부)
사용 예시는 아래와 같다.
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 # google, 1이면 vmware
}
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" }]
}
variable "my_password" {
default = "password"
sensitive = true
}
우선 순위 :
변수가 선언되는 방식에 따라 우선순위가 존재한다.
실행 후 입력 < variable 블록의 default 값 < 환경 변수 (TF_VAR 변수 이름) < terraform.tfvars < *.auto.tfvars < *.auto.tfvars.json < CLI 실행 시 -var 인수에 지정 또는 -var-file로 파일 지정
오른쪽으로 갈수록 우선순위가 높다. 예를들어 변수의 값을 출력해주는 코드가 있을 때, terraform.tfvars 내부 변수에 1이라는 값이 정의되어 있고, 실행후에 3이라는 값을 입력 한다면 결과는 1이 나오게 된다.
# main.tf
variable "my_var" {
default = "var2"
}
resource "local_file" "abc" {
content = var.my_var
filename = "${path.module}/abc.txt"
}
#terraform.tf
my_var="var4"
기본 문법
local : 로컬에서만 사용하는 변수
output : 프로비저닝 수행 결과의 속성 값을 출력
반복문 : count, for each, for expression 등 여러개의 데이터를 한개의 리소스로 반복적으로 생성
# count
resource "local_file" "abc" {
count = 5
content = "abc"
filename = "${path.module}/abc.txt"
}
# for each
resource "local_file" "abc" {
for_each = {
a = "content a"
b = "content b"
}
content = each.value
filename = "${path.module}/${each.key}.txt"
}
# for
variable "names" {
default = ["a", "b", "c"]
}
resource "local_file" "abc" {
content = jsonencode([for s in var.names : upper(s)]) # 결과 : ["A", "B", "C"]
filename = "${path.module}/abc.txt"
}
# for의 다양한 활용
variable "names" {
type = list(string)
default = ["a", "b"]
}
output "A_upper_value" {
value = [for v in var.names : upper(v)]
}
output "B_index_and_value" {
value = [for i, v in var.names : "${i} is ${v}"]
}
output "C_make_object" {
value = { for v in var.names : v => upper(v) }
}
output "D_with_filter" {
value = [for v in var.names : upper(v) if v != "a"]
}
Dynamic : 리소스 내부 속성 블록을 동적인 블록으로 생성한다. dynamic을 사용할 경우 특정 리소스 블록 내부에서 하나의 속성 블록에서 여러 개의 속성을 부여할 수 있게 된다.
# 일반적인 속성 부여
resource "provider_resource" "name" {
name = "some_resource"
some_setting {
key = a_value
}
some_setting {
key = b_value
}
some_setting {
key = c_value
}
some_setting {
key = d_value
}
}
# dynamic을 활용한 부여
resource "provider_resource" "name" {
name = "some_resource"
dynamic "some_setting" {
for_each = {
a_key = a_value
b_key = b_value
c_key = c_value
d_key = d_value
}
content {
key = some_setting.value
}
}
}
연습 코드 :
- 입력받은 수 만큼 count로 sqs에 큐 생성하기
provider "aws" {
region = "ap-northeast-2"
}
variable "number_of_queue" {
type = number
}
resource "aws_sqs_queue" "main_queue" {
count = var.number_of_queue
name = "queue-${count.index+1}"
delay_seconds = 0
max_message_size = 1024
message_retention_seconds = 345600
visibility_timeout_seconds = 60
}
- dynamic을 활용한 security group 생성하기
variable "ingress_rules" {
type = list(object(
{
from_port = number
to_port = number
protocol = string
cidr_blocks = list(string)
}
))
default = [
{
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
},
{
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
},
{
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
},
{
from_port = 8080
to_port = 8080
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
]
}
resource "aws_security_group" "hwan001-sg" {
description = "hwan001 Security Group"
vpc_id = aws_vpc.hwan001-vpc.id
dynamic "ingress" {
for_each = var.ingress_rules
content {
from_port = ingress.value.from_port
to_port = ingress.value.to_port
protocol = ingress.value.protocol
cidr_blocks = ingress.value.cidr_blocks
}
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "hwan001-sg"
}
}
도전 과제
- 리전 내에서 사용 가능한 가용영역 목록 가져오기를 사용한 VPC 리소스 생성 실습 진행
- 위 3개 코드 파일 내용에 리소스의 이름(myvpc, mysubnet1 등)을 반드시! 꼭! 자신의 닉네임으로 변경해서 배포 실습해보세요!
- 입력변수를 활용해서 리소스(어떤 리소스든지 상관없음)를 배포해보고, 해당 코드를 정리해주세요!
- local를 활용해서 리소스(어떤 리소스든지 상관없음)를 배포해보고, 해당 코드를 정리해주세요!
- count, for_each, for, dynamic문 을 활용해서 리소스(어떤 리소스든지 상관없음)를 배포해보고, 해당 코드를 정리해주세요!
network.tf :
- data를 사용해 az 이름 가져오기
- vpc, subnet 생성하기
data "aws_availability_zones" "available" {
state = "available"
}
resource "aws_vpc" "hwan001-vpc" {
cidr_block = "10.10.0.0/16"
tags = {
Name = "hwan001-vpc"
}
}
resource "aws_subnet" "primary_az" {
vpc_id = aws_vpc.hwan001-vpc.id
cidr_block = "10.10.1.0/24"
availability_zone = data.aws_availability_zones.available.names[0]
tags = {
Name = "hwan001-subnet-1"
}
}
resource "aws_subnet" "secondary_az" {
vpc_id = aws_vpc.hwan001-vpc.id
cidr_block = "10.10.2.0/24"
availability_zone = data.aws_availability_zones.available.names[1]
tags = {
Name = "hwan001-subnet-2"
}
}
sg.tf :
- 다이나믹을 사용해서 여러 개의 ingress rule 정의하기
- 보안 그룹 생성
variable "ingress_rules" {
type = list(object(
{
from_port = number
to_port = number
protocol = string
cidr_blocks = list(string)
}
))
default = [
{
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
},
{
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
},
{
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
},
{
from_port = 8080
to_port = 8080
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
]
}
resource "aws_security_group" "hwan001-sg" {
description = "hwan001 Security Group"
vpc_id = aws_vpc.hwan001-vpc.id
dynamic "ingress" {
for_each = var.ingress_rules
content {
from_port = ingress.value.from_port
to_port = ingress.value.to_port
protocol = ingress.value.protocol
cidr_blocks = ingress.value.cidr_blocks
}
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "hwan001-sg"
}
}
main.tf :
- ubuntu 20.04 공식 ami 정보를 data로 가져오기
- 해당 ami를 사용해서 ec2 인스턴스 띄우기 (subnet, sg는 위에서 생성한 리소스로 사용)
provider "aws" {
region = "ap-northeast-2"
}
data "aws_ami" "ubuntu" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
owners = ["099720109477"] # Canonical
}
# EC2 Instance 생성
resource "aws_instance" "hwan001-ec2" {
ami = data.aws_ami.ubuntu.id
instance_type = "t2.micro"
subnet_id = aws_subnet.primary_az.id
vpc_security_group_ids = [aws_security_group.hwan001-sg.id]
associate_public_ip_address = true
tags = {
Name = "hwan001-ec2"
}
}
결과 :
'DevOps > IaC (Infrastructure as Code)' 카테고리의 다른 글
Terraform Backend 생성하기 (S3 버킷) (0) | 2023.10.22 |
---|---|
[T1012] Week 6. 테라폼으로 협업하기 (0) | 2023.08.13 |
[T1012] Week 4. State & module (0) | 2023.07.29 |
[T1012] Week 3. 테라폼 기본 사용법 정리 (3/3) (0) | 2023.07.22 |
[T1012] Week 1. 테라폼 기본 사용법 정리 (1/3) (0) | 2023.07.08 |
Infrastructure as Code : 코드를 통한 인프라 구축 (0) | 2022.12.30 |
댓글