Terraform Study #2
โํ ๋ผํผ์ผ๋ก ์์ํ๋ IaCโ ์ฑ ์ผ๋ก ์งํํ๋ Terraform ์คํฐ๋[T101] 2์ฃผ์ฐจ ์ ๋ฆฌ๋ด์ฉ์ ๋๋ค.
2์ฃผ์ฐจ
๋ฐ์ดํฐ ์์ค
๋ฐ์ดํฐ ์์ค(data
)๋ ์ธ๋ถ์ ๋ฆฌ์์ค ํน์ ์ ์ฅ๋ ์ ๋ณด๋ฅผ ๋ด๋ถ๋ก ๊ฐ์ ธ์ฌ ๋ ์ฌ์ฉํ๋ค.
๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ์ 2๊ธฐ ์คํฐ๋์ Ssoon๋์ด ๋ธ๋ก๊ทธ์ ์ ์ ๋ฆฌํด์ฃผ์ จ๋ค.
์๋์ ๊ฐ์ด AMI๋ AZ์ ๊ฐ์ด ๊ธฐ์กด์ ์๋ ์ ๋ณด๋ฅผ ์ด์ฉํด์ผ ํ ๋ ์ ์ฉํ๋ค.
- ubuntu AMI ์กฐํ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"]
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
filter {
name = "architecture"
values = ["x86_64"]
}
filter {
name = "root-device-type"
values = ["ebs"]
}
filter {
name = "state"
values = ["available"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
- AZ ๊ฒ์
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
data "aws_availability_zones" "available" {
group_names = [
"ap-northeast-2",
]
id = "ap-northeast-2"
names = [
"ap-northeast-2a",
"ap-northeast-2b",
"ap-northeast-2c",
"ap-northeast-2d",
]
state = "available"
zone_ids = [
"apne2-az1",
"apne2-az2",
"apne2-az3",
"apne2-az4",
]
}
์ ๋ ฅ ๋ณ์
๋ณ์๋ Terrraform ์ฝ๋๋ฅผ ๋์ ์ผ๋ก ๊ตฌ์ฑํ ์ ์๊ฒ ํ๋ค. ํ ๋ผํผ์์๋ ์ด๊ฒ์ ์ ๋ ฅ ๋ณ์ Input Variables ๋ก ์ ์ํ๋ค.
- ์ ์ธ ์์
1
2
3
4
5
6
7
variable "<์ด๋ฆ>" {
<์ธ์> = <๊ฐ>
}
variable "image_id" {
type = string
}
์์ ๊ฐ์ด ๋ณ์๋ฅผ ์ ์ํ ๋ ๋ค์ํ ๋ฉํ์ธ์๋ฅผ ๋ฃ์ ์ ์๋ค. ๊ด๋ จ ์ ๋ณด๋ ์๋์ ๊ฐ๋ค.
- ์ฐ์ ์์
1๋ฒ ๋ถํฐ ๋ณ์๋ฅผ ๋์ ํ๋ฉฐ, ํ ์์๊ฐ ์ ์์๋ฅผ ๋ฎ์ด์ฐ๊ธฐ ํฉ๋๋ค. ๊ฒฐ๋ก ์ ์ผ๋ก ๊ฐ์ฅ ์๋์ ์๋ ์ต์ ์ด ์ฐ์ ์์๊ฐ ๊ฐ์ฅ ๋์ต๋๋ค.
Order | Option |
---|---|
1 | Environment Variables |
2 | terraform.tfvars |
3 | terraform.tfvars.json |
4 | *.auto.tfvars (alphabetical order) |
5 | -var or โvar-file (command-line flags) |
Local
local์ ์ธ๋ถ์์ ์ ๋ ฅ๋์ง ์๊ณ , ์ฝ๋ ๋ด์์๋ง ๊ฐ๊ณต๋์ด ๋์ํ๋ ๊ฐ์ด๋ค. ์ธ๋ถ์์ ์ ๋ ฅ๋์ง ์์ง๋ง Local ์ ์ธ ์์ฒด์ ์ผ๋ฐ ๋ณ์๋ฅผ ๋ฃ์ ์ ์๋ค. (์๋์ ์์ ์ฐธ๊ณ )
local์ ํ์ฌ๋ด์ ํด๋ผ์ฐ๋ ์๋น์ค๋ฅผ ์ด์ฉํ ๋, ๋ฆฌ์์ค์ ํ๊ทธ๋ฅผ ๊ฑธ์ด์ผํ๋ค. ex) Owner, Purpose ๋ฑ
์ด ๋ Local ๋ณ์๋ฅผ ์ฌ์ฉํ๋ฉด ์๋์ ๊ฐ์ด ํธํ๊ฒ ๋ฆฌ์์ค์ ํ๊ทธ๋ฅผ ๊ฑธ ์ ์๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
locals {
additional_tags = {
Purpose = var.purpose
Owner = var.owner
}
}
...
resource "aws_instance" "app" {
...
tags = merge(
{
Name = "web-app"
},
local.additional_tags
)
}
์ค์ต
- VPC DNS ์ต์ ํ์ฑํ
1
2
3
4
5
6
7
8
9
resource "aws_vpc" "myvpc" {
cidr_block = "10.10.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "t101-study"
}
}
[[๋์ ๊ณผ์ 1]
๋ฆฌ์ ๋ด์์ ์ฌ์ฉ ๊ฐ๋ฅํ ๊ฐ์ฉ์์ญ ๋ชฉ๋ก ๊ฐ์ ธ์ค๊ธฐ๋ฅผ ์ฌ์ฉํ VPC ๋ฆฌ์์ค ์์ฑ ์ค์ต ์งํ]
์๋์ ๊ฐ์ด, data ์์ค๋ฅผ ์ด์ฉํ์ฌ AZ๋ฅผ ๊ฐ์ ธ์จ๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
resource "aws_subnet" "mysubnet1" {
vpc_id = aws_vpc.myvpc.id
cidr_block = "10.10.1.0/24"
availability_zone = data.aws_availability_zones.available.names[2]
tags = {
Name = "t101-subnet1"
}
}
resource "aws_subnet" "mysubnet2" {
vpc_id = aws_vpc.myvpc.id
cidr_block = "10.10.2.0/24"
availability_zone = "ap-northeast-2c"
tags = {
Name = "t101-subnet2"
}
}
[ec2 ์์ฑ ์ฝ์์์ ํ์ธ]
Vscode ์์ ์ถ์ถํ Graph์ธ๋ฐ, ๋ฆฌ์์ค๊ฐ ๋ง์ ๋ณด๊ธฐ ๋ถํธํ๋ค.
[๋ฐฐํฌ ํ์ธ] ์ด์ ๋ฐฐํฌ๋ EC2์ ์ ์ํ์ฌ, ํ ๋ผํผ ์ฝ๋๊ฐ ์ ์์ ์ผ๋ก ์ํ๋์๋ ์ง ํ์ธํ๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
$ MYIP=$(terraform output -raw kane_ec2_public_ip)
$ echo $MYIP
3.35.173.67
$ while true; do curl --connect-timeout 1 http://$MYIP/ ; echo "------------------------------"; date; sleep 1; done
<h1>RegionAz(apne2-az1) : Instance ID(i-0ca40805a20604dbe) : Private IP(10.10.1.34) : Web Server</h1>
------------------------------
Mon Sep 4 00:50:56 KST 2023
<h1>RegionAz(apne2-az1) : Instance ID(i-0ca40805a20604dbe) : Private IP(10.10.1.34) : Web Server</h1>
------------------------------
Mon Sep 4 00:50:57 KST 2023
<h1>RegionAz(apne2-az1) : Instance ID(i-0ca40805a20604dbe) : Private IP(10.10.1.34) : Web Server</h1>
------------------------------
Mon Sep 4 00:50:58 KST 2023
Output
terraform apply ์ดํ ํ์ผ์ ์ ํ ์ถ๋ ฅ๊ฐ์ ์ฝ์์ ์ถ๋ ฅํด์ค๋ค. ์ฃผ๋ก Ec2์ ํผ๋ธ๋ฆญ ip๊ฐ์ด ๊ผญ ํ์ธํด์ผ ํ๋ ๊ฒ๋ค์ ์ฃผ๋ก ์ถ๋ ฅํ๋ค. ์์ฑ ํ์ ์ ๋ณด๋ฅผ ์ถ๋ ฅํ๋ฉฐ ๊ฐ๋ค์ ์ถํ ํ์ดํ๋ผ์ธ ๊ตฌ์ฑ, shell script ํน์ ansible
์ ์ฌ์ฉํ ์๋ ์๋ค.**
๊ธฐ๋ณธ ์์
1
2
3
4
output "instance_ip_addr" {
value = aws_instance.server.private_ip
description = "The private IP address of the main server instance."
}
์กฐ๊ฑด ๊ฒ์ฌ ์งํ
1
2
3
4
5
6
7
8
9
output "api_base_url" {
value = "https://${aws_instance.example.private_dns}:8433/"
# The EC2 instance must have an encrypted root volume.
precondition {
condition = data.aws_ebs_volume.example.encrypted
error_message = "The server's root volume is not encrypted."
}
}
- Option
sensitive
: CLI ์์ ์ถ๋ ฅ๋์ง ์๊ฒ ํ ์ ์๋ค.- **
depends_on
: ์ ์๊ด๊ณ๋ฅผ ์ ํ ์ ์๋ค.(๋จผ์ , ์ถ๋ ฅ๋๋ ๊ฒ์ ๊ฒฐ์ ํ ์ ์๋ค.)
1
2
3
4
5
6
7
8
9
10
output "instance_ip_addr" {
value = aws_instance.server.private_ip
description = "The private IP address of the main server instance."
depends_on = [
# Security group rule must be created before this IP address could
# actually be used, otherwise the services will be unreachable.
aws_security_group_rule.local_access,
]
}
๋ฐ๋ณต๋ฌธ
Terraform์์ ๋ฐ๋ณต๋ฌธ์ ์๋์ 3๊ฐ์ง ๋ฌธ๋ฒ์ด ์๋ค.
[count] ์ํ๋ ์ ์ ๊ฐ๋งํผ ๋ฆฌ์์ค๋ ๋ชจ๋์ ์์ฑํ๋ค. ์ฃผ๋ก ๋ฆฌ์์ค์ ์์ฑ๊ฐ์ด ๋์ผํ ๊ฒฝ์ฐ Count๊ฐ ์ ์ ํ๋ค.
count, count.index
๋ก ์ ๊ทผํ ์ ์๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
variable "subnet_ids" {
type = list(string)
}
resource "aws_instance" "server" {
# Create one instance for each subnet
count = length(var.subnet_ids)
...
subnet_id = var.subnet_ids[count.index]
tags = {
Name = "Server ${count.index}"
}
}
[for_each] MAP ํ์์ ์๋ฃ๊ตฌ์กฐ๋ก {key, value}ํํ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ค. ์ ์ธ๋ key ๊ฐ ๊ฐ์๋งํผ ๋ฆฌ์์ค๋ฅผ ์์ฑํ๋ค.
1
2
3
4
5
6
7
8
resource "aws_instance" "example" {
# One VPC for each element of var.vpcs
for_each = var.instances
# each.value here is a value from var.vpcs
name = each.key
ami = each.value.ami
}
[for]
๋ง์ฝ [ ]์ผ๋ก ๋์ด์์ผ๋ฉด tuple ํ์์ผ๋ก ์ปจํ ์ด๋๋ฅผ ๋ฐํํ๊ณ , {}์ด๋ฉด ์ค๋ธ์ ํธ๋ก ๋ฐํํ๋ ๋ฐ๋ณต๋ฌธ์ด๋ค.
๋ํ for
๋ค์ If
๋ฅผ ํตํด ํํฐ๋ง ๊ธฐ๋ฅ๋ ๊ฐ๋ฅํ๋ค.(if ์ธ ๊ฐ๋ง ์ฌ์ฉ)
1
2
3
4
[for s in var.list : upper(s) if s != ""]
[for i, v in var.list : "${i} is ${v}"]
# object ํ์์ผ๋
[for k, v in var.map : length(k) + length(v)]
[Dynamic Block]
ํน์ํ ๋ชฉ์ ์ Dynamic Block์ ํตํด ๋์ ์ผ๋ก ๋ง๋ค์ด์ง๋ ๋ณ์์ ๋ํด ๋ฐ๋ณต ๊ฐ๋ฅํ ๋ธ๋ญ์ ๋ง๋ค ์ ์๋ค. ๊ธฐ์กด์ for_each, count ๋ฑ ๋ฐ๋ณต๋ฌธ์ ๋ฆฌ์์ค block ๋ฑ ์์ ์ ๋ฐ๊นฅ ๋ธ๋ญ์ ๋ฐ๋ณตํด์ ์ฐ์ด๋ด๋ ๊ฒ์ ๋นํด dynamic block์ block์์ฒด๋ฅผ ์ ์ํ๋ฉฐ ๋ฐ๋ณต์ ์ผ๋ก ์ฐ์ด๋ธ๋ค. (resource์ ๊ฐ์ ๋จ์ผ๋ธ๋ฝ์ด ์๋ ๋ด๋ถ ๋ธ๋ฝ์ผ๋ก๋ง ์ฌ์ฉ๋๋ค.) ์ฌ์ฉ๋ฐฉ๋ฒ์ Argument๋ฅผ ํ์ธํ๋ฉด ๋๋ค.
์ฐพ์๋ณด๋, ๋ค์๊ณผ ๊ฐ์ ์๋ด์ฌํญ๋ ์์๋ค.
- ๊ณผ๋ํ ์ฌ์ฉ์ ํผํ๋ค. (๋์ ๋ธ๋ก์ ๊ณผ๋ํ๊ฒ ์ฌ์ฉํ๋ฉด ๊ตฌ์ฑ์ ์ฝ๊ณ ์ ์งํ๊ธฐ ์ด๋ ค์ธ ์ ์๋ค.)
- ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ๋ชจ๋์ ์ํ ๊นจ๋ํ ์ฌ์ฉ์ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌ์ถํ๊ธฐ ์ํด ์ธ๋ถ ์ ๋ณด๋ฅผ ์จ๊ฒจ์ผ ํ ๋ ์ฌ์ฉํฉ๋๋ค
- ๊ฐ๋ฅํ ๊ฒฝ์ฐ ํญ์ ์ค์ฒฉ๋ ๋ธ๋ก์ ๋ฌธ์ ๊ทธ๋๋ก ์จ๋ผ.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
resource "aws_security_group" "backend-sg" {
name = "backend-sg"
vpc_id = aws_vpc.backend-vpc.id
dynamic "ingress" {
for_each = var.ingress_ports
content {
from_port = ingress.value
to_port = ingress.value
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
}
# ์๋์ ๊ฐ์ด ํ๊ธฐ ์ซ์ด์ ์์ฒ๋ผ ์งํ
resource "aws_security_group" "backend-sg" {
name = "backend-sg"
vpc_id = aws_vpc.backend-vpc.id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 8080
to_port = 8080
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
๋์ ๊ณผ์ 3
๋์ ๊ณผ์ 3
: ์ ๋ ฅ๋ณ์๋ฅผ ํ์ฉํด์ ๋ฆฌ์์ค(์ด๋ค ๋ฆฌ์์ค๋ ์ง ์๊ด์์)๋ฅผ ๋ฐฐํฌํด๋ณด๊ณ , ํด๋น ์ฝ๋๋ฅผ ์ ๋ฆฌํด์ฃผ์ธ์!
์์์ ์งํํ EC2 ๋ฐฐํฌ ์ฝ๋๋ฅผ ์ด์ฉํ๋ค. ๋ณ์๋ฅผ ํตํด ์ธ์คํด์ค์ ํ์ ์ ๋์ ์ผ๋ก ๊ตฌ์ฑํ๋ค.
- EC2 ๊ตฌ์ฑ
1
2
3
4
5
6
7
8
9
10
11
12
13
resource "aws_instance" "kane_ec2" {
depends_on = [
aws_internet_gateway.kane_igw
]
ami = data.aws_ami.amazonlinux2.id
associate_public_ip_address = true
// ์๋์ ๋ด์ฉ์ ์์ !
instance_type = var.ec2_instance_type
vpc_security_group_ids = ["${aws_security_group.kane_sg.id}"]
subnet_id = aws_subnet.kane_subnet1.id
...
- variable.tf ํ์ผ์ ์์ฑํ ๋ค, ์๋์ ๋ด์ฉ ์ถ๊ฐ
1
2
3
4
variable "ec2_instance_type" {
type = string
description = "The type of EC2 instance to launch"
}
- terraform.tfvars ํ์ผ์ ์์ฑํ ๋ค ์๋์ ๋ด์ฉ์ ์ถ๊ฐํ๋ค.
- ํด๋น ํ์ผ์ด ์กด์ฌํ๋ฉด, ํ ๋ผํผ์ ์๋์ผ๋ก ๋ณ์์ ๊ฐ์ ๊ฐ์ ธ๊ฐ๋ค. ์ฐ์ ์์์ ๋ฐ๋ผ ๋ฎ์ด์จ์ง ์ ์๊ธด ํ๋ค. ํ์ง๋ง ์ฌ๊ธฐ์ ๋ณ์ ์ ๋ ฅ์ ํด๋น ํ์ผ๋ก๋ง ํ๋ ์๊ด์๋ค.
1
ec2_instance_type = "t2.small"
์ด์ Terraform apply
๋ช
๋ น์ด๋ฅผ ํตํด ์ธํ๋ผ๋ฅผ ๊ตฌ์ถํ๋ค.
๊ธฐ์กด๊ณผ๋ ๋ค๋ฅด๊ฒ t2.micro
๊ฐ ์๋ t2.small
์ด ์์ฑ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
๋์ ๊ณผ์ 4
๋์ ๊ณผ์ 4
: local๋ฅผ ํ์ฉํด์ ๋ฆฌ์์ค(์ด๋ค ๋ฆฌ์์ค๋ ์ง ์๊ด์์)๋ฅผ ๋ฐฐํฌํด๋ณด๊ณ , ํด๋น ์ฝ๋๋ฅผ ์ ๋ฆฌํด์ฃผ์ธ์!
local์ ํตํด, EC2์ ํ๊น ์์ ์ ์งํํ๋ค.
- local ์ ์ธ
1
2
3
4
5
6
7
locals {
additional_tags = {
Environment = "Dev"
Purpose = "Test"
Owner = "Kane"
}
}
- EC2์ ์ถ๊ฐ
1
2
3
4
5
6
7
8
9
10
11
12
13
resource "aws_instance" "kane_ec2" {
depends_on = [
aws_internet_gateway.kane_igw
]
...
tags = merge({
Name = "t101-kane_ec2"
}
, local.additional_tags)
}
terraform apply
๋ฅผ ์คํํ๋ค.
์ด์ AWS ์ฝ์์ ๋ค์ด๊ฐ EC2 > Tags ํ์ด์ง๋ฅผ ํ์ธํ๋ฉด ๋ค์๊ณผ ๊ฐ์ด ํ๊น ์ด ์ฌ๋ฐ๋ฅด๊ฒ ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.