테라폼으로 시작하는 IaC 책을 기준으로 정리하였습니다.
데이터 소스는 테라폼으로 정의되지 않은 외부 리소스
또는 저장된 정보
를 테라폼 내에서 참조할 때 사용한다.
# Terraform Code
data "<리소스 유형>" "<이름>" {
<인수> = <값>
}
# 데이터 소스 참조
data.<리소스 유형>.<이름>.<속성>
도전과제1
리전 내에서 사용 가능한 가용영역 목록 가져오기를 사용한 VPC 리소스 생성 실습 진행 - 링크 혹은 아무거나 데이터 소스를 사용한 실습 진행
# Create a VPC for the region associated with the AZ
resource "aws_vpc" "myvpc" {
cidr_block = "10.10.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "repush"
}
}
# Declare the data source
data "aws_availability_zones" "available" {
state = "available"
}
resource "aws_subnet" "primary" {
vpc_id = aws_vpc.myvpc.id
cidr_block = "10.10.1.0/24"
availability_zone = data.aws_availability_zones.available.names[0]
# e.g. ap-northeast-2a
}
resource "aws_subnet" "secondary" {
vpc_id = aws_vpc.myvpc.id
cidr_block = "10.10.2.0/24"
availability_zone = data.aws_availability_zones.available.names[2]
# e.g. ap-northeast-2c
}
입력 변수는 인프라를 구성하는 데 필요한 속성 값을 정의해 코드의 변경 없이 여러 인프라를 생성하는 데 목적이 있다.
테라폼에서는 이것을 입력변수 Input Variables로 정의한다.
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-\"."
}
}
결과
# terraform apply -auto-approve var.image_id The id of the machine image (AMI) to use for the server. Enter a value: ami-12345678 ...
var.<이름>
으로 참조된다.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 ... # 확인 terraform state list terraform state show local_file.abc cat abc.txt ; echo
확인 : 민감한 변수로 지정해도 terraform.tfstate 파일에는 결과물이 평문으로 기록되므로 State 파일의 보안에 유의해야 한다. [참고 Docs - sensitive-variables , State 암호화]
variable "my_password" {
default = "password"
sensitive = true
}
resource "local_file" "abc" {
content = var.my_password
filename = "${path.module}/abc.txt"
}
결과
# 출력부분에 내용 안보임! terraform apply -auto-approve terraform state show local_file.abc # 결과물 파일 확인 cat abc.txt ; echo # terraform.tfstate 파일 확인 cat terraform.tfstate | grep '"content":' "content": "password",
아래 순위와 같이 변수는 우선순위에 따라 결정되게 된다.
도전과제2
: 위 3개 코드 파일 내용에 리소스의 이름(myvpc, mysubnet1 등)을 반드시! 꼭! 자신의 닉네임으로 변경해서 배포 실습해보세요!
리소스의 유형은 테라폼에서 미리 정의되어 있는 리소스 템플릿을 활용한다는 의미이고 리소스의 이름은 고유하게 커스텀한 리소스에 대하여 이름을 정의하고 참조하거나 활용할 수 있게 하는 것이다.
vpc.tf
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_vpc" "repush_vpc" {
cidr_block = "10.10.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "t101-study"
}
}
resource "aws_subnet" "repush_subnet_1" {
vpc_id = aws_vpc.repush_vpc.id
cidr_block = "10.10.1.0/24"
availability_zone = "ap-northeast-2a"
tags = {
Name = "t101-subnet1"
}
}
resource "aws_subnet" "repush_subnet_2" {
vpc_id = aws_vpc.repush_vpc.id
cidr_block = "10.10.2.0/24"
availability_zone = "ap-northeast-2c"
tags = {
Name = "t101-subnet2"
}
}
resource "aws_internet_gateway" "repush_igw" {
vpc_id = aws_vpc.repush_vpc.id
tags = {
Name = "t101-igw"
}
}
resource "aws_route_table" "repush_rt" {
vpc_id = aws_vpc.repush_vpc.id
tags = {
Name = "t101-rt"
}
}
resource "aws_route_table_association" "repush_rtassociation1" {
subnet_id = aws_subnet.repush_subnet_1.id
route_table_id = aws_route_table.repush_rt.id
}
resource "aws_route_table_association" "repush_rtassociation2" {
subnet_id = aws_subnet.repush_subnet_2.id
route_table_id = aws_route_table.repush_rt.id
}
resource "aws_route" "repush_default_route" {
route_table_id = aws_route_table.repush_rt.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.repush_igw.id
}
output "aws_vpc_id" {
value = aws_vpc.repush_vpc.id
}
sg.tf
resource "aws_security_group" "repush_sg" {
vpc_id = aws_vpc.repush_vpc.id
name = "T101 SG"
description = "T101 Study SG"
}
resource "aws_security_group_rule" "repush_sginbound" {
type = "ingress"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.repush_sg.id
}
resource "aws_security_group_rule" "repush_sgoutbound" {
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.repush_sg.id
}
ec2.tf
data "aws_ami" "repush_amazonelinux2" {
most_recent = true
filter {
name = "owner-alias"
values = ["amazon"]
}
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-ebs"]
}
owners = ["amazon"]
}
resource "aws_instance" "repush_ec2" {
depends_on = [
aws_internet_gateway.repush_igw
]
ami = data.aws_ami.repush_amazonelinux2.id
associate_public_ip_address = true
instance_type = "t2.micro"
vpc_security_group_ids = ["${aws_security_group.repush_sg.id}"]
subnet_id = aws_subnet.repush_subnet_1.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
RZAZ=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone-id)
IID=$(curl 169.254.169.254/latest/meta-data/instance-id)
LIP=$(curl 169.254.169.254/latest/meta-data/local-ipv4)
echo "<h1>RegionAz($RZAZ) : Instance ID($IID) : Private IP($LIP) : Web Server</h1>" > index.html
nohup ./busybox httpd -f -p 80 &
EOF
user_data_replace_on_change = true
tags = {
Name = "t101-repush_ec2"
}
}
output "repush_ec2_public_ip" {
value = aws_instance.repush_ec2.public_ip
description = "The public IP of the Instance"
}
결과
코드 내에서 사용자가 지정한 값 또는 속성 값을 가공해 참조 가능한 local (지역 값)은 외부에서 입력되지 않고, 코드 내에서만 가공되어 동작하는 값을 선언한다.
local
은 입력 변수와 달리 선언된 모듈 내에서만 접근 가능하고, 변수처럼 실행 시에 입력받을 수 없다.
로컬은 사용자가 테라폼 코드를 구현할 때 값이나 표현식을 반복적으로 사용할 수 있는 편의를 제공한다.
하지만 빈번하게 여러 곳에서 사용되는 경우 실제 값에 대한 추적이 어려워져 유지 관리 측면에서 부담이 발생할 수 있으므로 주의해야 한다.
도전과제4
: local를 활용해서 리소스(어떤 리소스든지 상관없음)를 배포해보고, 해당 코드를 정리해주세요!
provider "aws" {
region = "ap-northeast-2"
}
locals {
name = "repushtest"
team = {
group = "dev"
}
} # local을 활용해서 name 및 team에 대한 값을 등록한다.
resource "aws_iam_user" "repushiamuser1" {
name = "${local.name}1"
tags = local.team
} # local에서 정의한 값을 사용한다.
resource "aws_iam_user" "repushiamuser2" {
name = "${local.name}2"
tags = local.team
}
출력 값은 주로 테라폼 코드의 프로비저닝 수행 후의 결과 속성 값을 확인하는 용도로 사용된다.
또한 프로그래밍 언어에서 코드 내 요소 간에 제한된 노출을 지원하듯, 테라폼 모듈 간, 워크스페이스 간 데이터 접근 요소로도 활용할 수 있다.
예를 들면 자바의 getter와 비슷한 역할이다. 출력 값의 용도는 다음과 같이 정의할 수 있다.
list 형태의 값 목록이나 Key-Value 형태의 문자열 집합인 데이터가 있는 경우 동일한 내용에 대해 테라폼 구성 정의를 반복적으로 하지 않고 관리할 수 있다.
도전과제5
: count, for_each 반복문, for문, dynamic문 을 활용해서 리소스(어떤 리소스든지 상관없음)를 배포해보고, 해당 코드를 정리해주세요!
variables.tf
variable "user_names" {
description = "Create IAM users with these names"
type = list(string)
default = ["repush", "minchan", "bigmnt"]
}
iam.tf
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_iam_user" "repushiam" {
count = length(var.user_names)
name = var.user_names[count.index]
}
output "first_arn" {
value = aws_iam_user.repushiam[0].arn
description = "The ARN for the first user"
}
output "all_arns" {
value = aws_iam_user.repushiam[*].arn
description = "The ARNs for all users"
}
결과