Terraform Study #3
โํ ๋ผํผ์ผ๋ก ์์ํ๋ IaCโ ์ฑ ์ผ๋ก ์งํํ๋ Terraform ์คํฐ๋[T101] 3์ฃผ์ฐจ ์ ๋ฆฌ๋ด์ฉ์ ๋๋ค.
3์ฃผ์ฐจ
์ด๋ฒ์๊ฐ์ ํ ๋ผํผ ๊ธฐ๋ณธ์ฌ์ฉ ๋ง์ง๋ง ๋จ๊ณ(3/3)์ด๋ค. ์ด๋ฒ์ฃผ์ฐจ์์๋ ์กฐ๊ฑด๋ฌธ, ํจ์, ํ๋ก๋น์ ๋, data block์ ๋ํด ๋ฐฐ์ด ๋ค ํ๋ก๋ฐ์ด๋๋ฅผ ๊ฒฝํํด๋ณด๊ณ ๋ง๋ฌด๋ฆฌ๋๋ค. ๊ฐ์ธ์ ์ผ๋ก null_resource์ ๋ํด ์๋ชฐ๋๋ค. ๋ง์ด ์ฌ์ฉํ ํ๋ฌ๊ทธ์ธ ์ค ํ๋๋ผ๊ณ ํ๋ค. ์ด๋ฒ ๊ธฐํ์ ์ ๋ฐฐ์๋๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค. (์ง๊ธ์ terraform_data๊ฐ ๊ฐ์ ๊ธฐ๋ฅ์ ์ํํ๋ค.)
Conditional(์กฐ๊ฑด๋ฌธ)
์กฐ๊ฑด ๋ฌธ์ ๊ฒฝ์ฐ C์ธ์ด์ ์ผํญ์ฐ์ฐ์์ ์ ์ฌํ๋ค. ๊ทธ ์ธ์๋ ์ง์ํ์ง ์๋ ๋ชจ์์ด๋ค.
ํ์: condition ? true_val : false_val
์ค์ต
- main.tf
1
2
3
4
5
6
7
8
9
10
11
12
13
variable "enable_file" {
default = true
}
resource "local_file" "foo" {
count = var.enable_file ? 1 : 0
content = "foo!"
filename = "${path.module}/foo.bar"
}
output "content" {
value = var.enable_file ? local_file.foo[0].content : ""
}
์์ ์ฝ๋์ ๋ด์ฉ์ var.enable_file์ ๊ฐ์ ์ ๋ ฅํ์ง ์๊ฑฐ๋, true๋ก ์ค์ ํ๋ฉด foo.bar๋ผ๋ local file์ ์์ฑํ๋ค. ๋ฐ๋์ ๊ฒฝ์ฐ๋ผ๋ฉด ๋ฆฌ์์ค๋ฅผ ์์ฑํ์ง ์๋๋ค.
false
๋ฅผ ์ง์ ํ ๊ฒฝ์ฐ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ export TF_VAR_enable_file=false
$ export | grep TF_VAR_enable_file
TF_VAR_enable_file=false
$ terraform init && terraform plan && terraform apply -auto-approve
...
Changes to Outputs:
+ content = ""
You can apply this plan to save these new output values to the Terraform state, without changing any real
infrastructure.
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
content = ""
true
๋ฅผ ์ง์ ํ๊ฒฝ์ฐ(=์๋ฌด๊ฒ๋ ์ ๋ ฅํ์ง ์์)
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
# ์๋ฌด๊ฒ๋ ์
๋ ฅํ์ง ์์์ ๋
$ terraform init && terraform plan && terraform apply -auto-approve
...
+ content = "foo!"
local_file.foo[0]: Creating...
local_file.foo[0]: Creation complete after 0s [id=4bf3e335199107182c6f7638efaad377acc7f452]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Outputs:
content = "foo!"
$ terraform state list
local_file.foo[0]
$ echo "local_file.foo[0].content" | terraform console
โท
โ Warning: Value for undeclared variable
โ
โ The root module does not declare a variable named "ec2_instance_type" but a value was found in file
โ "terraform.tfvars". If you meant to use this value, add a "variable" block to the configuration.
โ
โ To silence these warnings, use TF_VAR_... environment variables to provide certain "global" settings to
โ all configurations in your organization. To reduce the verbosity of these warnings, use the
โ -compact-warnings option.
โต
"foo!"
์์ ์์์ฒ๋ผ, ์กฐ๊ฑด๋ฌธ์ด ์์ฃผ ์ ์ ์ฉ๋๋ค.
ํจ์
ํจ์๋ ๋ด์ฅํจ์๋ง ์ฌ์ฉ๊ฐ๋ฅํ๋ค. ์ฌ์ฉ์ ์ ์ํจ์์ ๊ฐ์ด ์ง์ ๋ง๋ค ์ ์๋ค. ๊ณต์๋ฌธ์์์ ํ์ธํ๋ฉด์ ํ์ธํ ํจ์๋ฅผ ๊ฐ๋จํ๊ฒ ์ ๋ฆฌํด๋ดค๋ค.
toset
: ํด๋น ํจ์๋ ์งํฉ๊ณผ ๊ฐ์ด ์ค๋ณต๋ ์์๋ฅผ ์ ๊ฑฐํ๊ณ , ์ ๋ ฌ์ํจ๋ค.toset(["b", "a","b"]) =[โaโ, โbโ]
Slice
: ๋ชฉ๋ก ๋ด์์ ์ผ๋ถ ์ฐ์ ์์(elements)๋ฅผ ์ถ์ถํฉ๋๋ค. ์์ ์ธ๋ฑ์ค(startindex
)๋ ํฌํจ๋์ง๋ง ๋ ์ธ๋ฑ์ค(endindex
)๋ ์ ์ธ[**length](https://developer.hashicorp.com/terraform/language/functions/length)
:** list, map ๋๋ string์ ๊ธธ์ด๋ฅผ ๊ณ์ฐํฉ๋๋ค. ๋ฆฌ์คํธ ๋๋ ๋งต์ด๋ฉด ์ปฌ๋ ์ (collection)์ ์์ ์, ๋ฌธ์์ด์ด๋ฉด ๋ฌธ์ ์๋ฅผ ๋ฐํํฉ๋๋ค.- ์ซ์ ๊ด๋ จ ํจ์
min, max, ceil, floor
ํจ์๋ ์กด์ฌํ๋ค.- min(-1,2,var.temp) = -1, ceil(10.1) = 11
- ๋ฌธ์์ด ๊ด๋ จ ํจ์
- split(โ,โ, โami-xyz,AMI-ABC,ami-efgโ) =
[ "ami-xyz","AMI-ABC","ami-efg" ]
- lower, upper : lower(var.ami)=
[ "ami-xyz","ami-abc","ami-efg" ]
- substr(var.ami.0,7) = ami-xyz
- join(โ,โ , [ โami-xyzโ,โAMI-ABCโ,โami-efgโ ]) :
"ami-xyz,AMI-ABC,ami-efg"
- split(โ,โ, โami-xyz,AMI-ABC,ami-efgโ) =
- Collection ํจ์
- length(var.ami) = 3
- index(var.ami, โAMI-ABCโ) = 1
- element(var.ami,2) = ami-efg
- contains(var.ami, โAMI-ABCโ) = true (์์๊ฐ ์๋ ์ง ์๋ ์ง)
- MAP ๊ด๋ จ ํจ์ โ map ํจ์๋ ์ง์ํ์ง ์๊ณ ,
tomap
ํจ์๋ฅผ ์ง์
1
2
3
4
5
6
7
8
9
variable "ami" {
type = map
default = {
"us-east-1" = "ami-xyz",
"ca-central-1" = "ami-efg",
"ap-south-1" = "ami-ABC"
}
description = "A map of AMI ID's for specific regions"
}
lookup (var.ami, "us-east-1")
๋ช
๋ น์ด๋ฅผ ์คํํ๋ฉด ami-xyz
๋ฅผ ๋ฐํํ๋ค.
ํ๋ก๋น์ ๋
ํ๋ก๋น์ ๋๋ ํ๋ก๋ฐ์ด๋๋ก ์คํ๋์ง ์๋ ์ปค๋งจ๋์ ํ์ผ ๋ณต์ฌ ๊ฐ์ ์ญํ ์ ์ํํ๋ค.
ํ๋ก๋น์ ๋๋ก ์คํ๋ ๊ฒฐ๊ณผ๋ ํ ๋ผํผ์ ์ํ ํ์ผ๊ณผ ๋๊ธฐํ๋์ง ์์ผ๋ฏ๋ก ํ๋ก๋น์ ๋์ ๋ํ ๊ฒฐ๊ณผ๊ฐ ํญ์ ๊ฐ๋ค๊ณ ๋ณด์ฅํ ์ ์๋ค โ ์ ์ธ์ ๋ณด์ฅ ์๋จ
๊ทธ๋ ๊ธฐ์, ํ๋ก๋น์ ๋๋ณด๋จ userdata ๋ฑ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
ํ๋ก๋น์ ๋๋ ์์ฑํ ๋๋ง ์คํ๋๊ณ ์ถํ ์์
์ ์๋ค. ๊ทธ๋์ย provisioner
๊ฐ ์คํจํ๋ฉด ๋ฆฌ์์ค๊ฐ ์๋ชป๋์๋ค๊ณ ํ๋จํ๊ณ ๋ค์ย terraform apply
ย ํ ๋ ์ ๊ฑฐํ๊ฑฐ๋ ๋ค์ ์์ฑํ๋ค.ย
provisioner
์์ย when = "destroy"
๋ฅผ ์ง์ ํ๋ฉด ํด๋น ํ๋ก๋น์ ๋๋ ๋ฆฌ์์ค๋ฅผ ์ ๊ฑฐํ๊ธฐ ์ ์ ์คํ๋๊ณ ํ๋ก๋น์ ๋๊ฐ ์คํจํ๋ค๋ฉด ๋ค์ย terraform apply
ย ํ ๋ ๋ค์ ์คํํ๊ฒ ๋๋ค. ๋ฌธ์์ ๋ฐ๋ฅด๋ฉด ์ด ๋๋ฌธ์ ์ ๊ฑฐ ํ๋ก๋น์ ๋๋ ์ฌ๋ฌ ๋ฒ ์คํํด๋ ๊ด์ฐฎ๋๋ก ์์ฑํด์ผ ํ๋ค๊ณ ํ๋ค.
์ฐธ๊ณ ์๋ฃ
์ค์๋ธ๊ณผ ์ฐ๋ํด์ ์ธ๊ฑฐ๋ฉด, ์๋์ ๋งํฌ๋ก ์งํํ๋ฉด ๋๋ค.
https://github.com/ansible/terraform-provider-ansible/tree/main/examples
์๋์ ๊ฐ์ด ์๊ฒฉ์ ๋ด์ฉ์ ์ ๋ฌํ ์ ์์ง๋ง, ๊ฐ๊ธ์ user_data๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
user_data = base64encode(templatefile("${path.module}/ubuntu_docker.tftpl", {}))
connection: remote-exec์ file ํ๋ก๋น์ ๋๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด, ์๊ฒฉ์ ์ฐ๊ฒฐํ ์ ๋ณด๋ฅผ ๋ช ์ํด์ผ ํ๋ค. ์ฃผ๋ก SSH/WinRM๋ง ์กด์ฌํ๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
resource "aws_instance" "web" {
...
connection {
type = "ssh"
user = "root"
password = var.root_password
host = self.public_ip
}
provisioner "file" {
source = "script.sh"
destination = "/tmp/script.sh"
}
provisioner "remote-exec" {
inline = [
"chmod +x /tmp/script.sh",
"/tmp/script.sh args",
]
}
}
null resource
์๋ฌด์์ ๋ ์ํํ์ง ์๋ ๋ฆฌ์์ค์ด๋ค.
์ด๋ฐ ๋ฆฌ์์ค๊ฐ ํ์ํ ์ด์ ๋ ํ ๋ผํผ ํ๋ก๋น์ ๋ ๋์์ ์ค๊ณํ๋ฉด์ ์ฌ์ฉ์๊ฐ ์๋์ ์ผ๋ก ํ๋ก๋น์ ๋ํ๋ ๋์์ ์กฐ์จํด์ผ ํ๋ ์ํฉ์ด ๋ฐ์ํ์ฌ, ํ๋ก๋ฐ์ด๋๊ฐ ์ ๊ณตํ๋ ๋ฆฌ์์ค ์๋ช ์ฃผ๊ธฐ ๊ด๋ฆฌ๋ง์ผ๋ก๋ ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ด๋ ต๊ธฐ ๋๋ฌธ์ด๋ค.
์ฃผ๋ก ์ฌ์ฉ๋๋ ์๋๋ฆฌ์ค
- ํ๋ก๋น์ ๋ ์ํ ๊ณผ์ ์์ ๋ช ๋ น์ด ์คํ
- ํ๋ก๋น์ ๋์ ํจ๊ป ์ฌ์ฉ
- ๋ชจ๋, ๋ฐ๋ณต๋ฌธ, ๋ฐ์ดํฐ ์์ค, ๋ก์ปฌ ๋ณ์์ ํจ๊ป ์ฌ์ฉ
- ์ถ๋ ฅ์ ์ํ ๋ฐ์ดํฐ ๊ฐ๊ณต
์์ ์ํฉ
EC2์ ์ธ์คํด์ค๋ก ์น์๋น์ค๋ฅผ ์คํํ๋ค. ์น์๋น์ค ์ค์ ์ ๊ณ ์ ๋ IP(EIP)๊ฐ ํ์ํ๋ค.
์๋์ ๊ฐ์ด ์ํ์ฐธ์กฐ ์๋ฌ๊ฐ ๋ฐ์ํ๋ ์ํฉ์์, null_resource๋ฅผ ์ถ๊ฐํด ํด๊ฒฐํ ์ ์์
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_security_group" "instance" {
name = "t101sg"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_instance" "example" {
ami = "ami-0c9c942bd7bf113a2"
instance_type = "t2.micro"
subnet_id = "subnet-dbc571b0"
private_ip = "172.31.1.100"
vpc_security_group_ids = [aws_security_group.instance.id]
user_data = <<-EOF
#!/bin/bash
echo "Hello, T101 Study" > index.html
nohup busybox httpd -f -p 80 &
EOF
tags = {
Name = "Single-WebSrv"
}
# (1) ์ฌ๊ธฐ์์ eip ๋ฆฌ์์ค์ ๋ํ ์ ๊ทผ์ ํ๋ฉด ์ํ์ฐธ์กฐ๋ก ์๋ฌ๊ฐ ๋ฐ์ํจ.
provisioner "remote-exec" {
inline = [
"echo ${aws_eip.myeip.public_ip}"
]
}
}
# (1)๋ฒ์ ๋ด์ฉ์ ๋์ฒดํ ์ ์๋ Null_resource
resource "null_resource" "echomyeip" {
provisioner "remote-exec" {
connection {
host = aws_eip.myeip.public_ip
type = "ssh"
user = "ubuntu"
private_key = file("/home/kaje/kp-kaje.pem") # ๊ฐ์ ์์ ์ EC2 SSH Keypair ํ์ผ ์์น ์ง์
#password = "qwe123"
}
inline = [
"echo ${aws_eip.myeip.public_ip}"
]
}
}
resource "aws_eip" "myeip" {
#vpc = true
instance = aws_instance.example.id
associate_with_private_ip = "172.31.1.100"
}
output "public_ip" {
value = aws_instance.example.public_ip
description = "The public IP of the Instance"
}
terraform_data
์ด ๋ฆฌ์์ค ๋ํ, null_resource์ ๋์ผํ ์ญํ ์ ํ๋, ํ ๋ผํผ ์์ฒด์ ํฌํจ๋ ๊ธฐ๋ณธ ์๋ช ์ฃผ๊ธฐ ๊ด๋ฆฌ์๊ฐ ์ ๊ณต๋๋ค.
triggers_replace: ์ธ์คํด์ค์ ์ํ๋ฅผ ์ ์ฅํ๋ฉฐ, ์ํ๊ฐ ๋ณ๊ฒฝ๋๋ฉด ์๋์ ๋ช ๋ น์ด๋ฅผ ์ํํ๋ค.
์๋์ ์์๋ฅผ ํตํด ํ์ธํ๋ฉด,
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
resource "terraform_data" "foo" {
triggers_replace = [
local_file.foo
]
provisioner "local-exec" {
command = "echo 'terraform_data test'"
}
}
output "terraform_data_output" {
value = terraform_data.foo.output # ์ถ๋ ฅ ๊ฒฐ๊ณผ๋ "world"
}
variable "enable_file" {
default = true
}
resource "local_file" "foo" {
count = var.enable_file ? 1 : 0
content = "foo!"
filename = "${path.module}/foo.bar"
}
output "content" {
value = var.enable_file ? local_file.foo[0].content : ""
}
- terraform apply ์ดํ, foo.bar์ ๋ด์ฉ์ ์์ ํ์ ๋
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ terraform apply -auto-approve
local_file.foo[0]: Refreshing state... [id=4bf3e335199107182c6f7638efaad377acc7f452]
terraform_data.foo: Refreshing state... [id=bdfbfd37-fccc-4f02-6542-08f1bbb3d2a1]
...
terraform_data.foo: Destroying... [id=bdfbfd37-fccc-4f02-6542-08f1bbb3d2a1]
terraform_data.foo: Destruction complete after 0s
local_file.foo[0]: Creating...
local_file.foo[0]: Creation complete after 0s [id=4bf3e335199107182c6f7638efaad377acc7f452]
terraform_data.foo: Creating...
terraform_data.foo: Provisioning with 'local-exec'...
terraform_data.foo (local-exec): Executing: ["/bin/sh" "-c" "echo 'terraform_data test'"]
terraform_data.foo (local-exec): terraform_data test
terraform_data.foo: Creation complete after 0s [id=4301eef8-bbc6-58f0-6948-a6f6ac176b6c]
Apply complete! Resources: 2 added, 0 changed, 1 destroyed.
Outputs:
content = "foo!"
- (triggers_replace๋ฅผ ์ฃผ์์ผ๋ก ์ ๊ฑฐํ ๋ค)terraform apply ์ดํ, foo.bar์ ๋ด์ฉ์ ์์ ํ์ ๋
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
33
34
35
36
37
38
39
40
41
$ terraform apply
terraform_data.foo: Refreshing state... [id=3396b6e8-ffca-dac3-f0d5-c41455864c42]
local_file.foo[0]: Refreshing state... [id=4bf3e335199107182c6f7638efaad377acc7f452]
Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
+ create
Terraform will perform the following actions:
# local_file.foo[0] will be created
+ resource "local_file" "foo" {
+ content = "foo!"
+ content_base64sha256 = (known after apply)
+ content_base64sha512 = (known after apply)
+ content_md5 = (known after apply)
+ content_sha1 = (known after apply)
+ content_sha256 = (known after apply)
+ content_sha512 = (known after apply)
+ directory_permission = "0777"
+ file_permission = "0777"
+ filename = "./foo.bar"
+ id = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
local_file.foo[0]: Creating...
local_file.foo[0]: Creation complete after 0s [id=4bf3e335199107182c6f7638efaad377acc7f452]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Outputs:
content = "foo!"
moved
state์ ๊ธฐ๋ก๋๋ ๋ฆฌ์์ค์ ์ด๋ฆ์ด ๋ณ๊ฒฝ๋๋ฉด ๊ธฐ์กด ๋ฆฌ์์ค ์ญ์ ํ ์ฌ์์ฑํ๋ค. ์ด๋ฆ์ ๋ณ๊ฒฝํ์ง๋ง, ์ธํ๋ผ๋ฅผ ์ ์งํ๊ณ ์ถ์ ๋ moved block์ ์ฌ์ฉํ๋ค.
- ์๋ณธ
1
2
3
4
5
6
7
8
resource "local_file" "a" {
content = "foo!"
filename = "${path.module}/foo.bar"
}
output "file_content" {
value = local_file.a.content
}
- ์ด๋ฆ ์์ ํ
1
2
3
4
5
6
7
8
9
10
11
12
13
resource "local_file" "b" {
content = "foo!"
filename = "${path.module}/foo.bar"
}
moved {
from = local_file.a
to = local_file.b
}
output "file_content" {
value = local_file.b.content
}
์ด์ ๊ฐ์ด moved block์ ์ฌ์ฉํ๋ฉด, ์ธํ๋ผ๋ฅผ ์ ์งํ ์ ์๋ค.
ํ๋ก๋ฐ์ด๋
ํ๋ก๋ฐ์ด๋๋ ์ธํ๋ผ ๋ฆฌ์์ค๋ฅผ ์ ๊ณตํ๋ ์ ์ฒด๋ผ๊ณ ์๊ฐํ๋ฉด ๋๋ค. Terraform์ ํ๋ฌ๊ทธ์ธ์ ์ฌ์ฉํ์ฌ ํ๋ก๋ฐ์ด๋๋ผ๊ณ ๋ถ๋ฆฌ๋ ํด๋ผ์ฐ๋, SaaS, ๋ค๋ฅธ API์ ์ํธ์์ฉํ๋ค.
Terraform ์ด ์ด๋ค ๊ณต๊ธ์์ ์ฌ์ฉํ ์ง ํํํ๊ธฐ ์ํด, provider.tf
์ ๋ณ๋๋ก ์ ์ํ๋ค.
ํ๋ก๋ฐ์ด๋๋ terraform init
๋ช
๋ น์ด๋ฅผ ํตํด, ํ์ํ ํ๋ฌ๊ทธ์ธ์ ๊ฒ์ ๋ฐ ๋ค์ด๋ก๋ํ๋ฉฐ lock.hcl ํ์ผ์ ํ๋ก๋ฐ์ด๋๋ฅผ ๋ช
์ํ์ฌ ์์ผ๋ก์ ์ฝ๋ ์ํ์์ ์ฌ์ฉ๋๋ ํ๋ฌ๊ทธ์ธ์ ์ ํํ๋ค. (์์ํ์ง ๋ชปํ, ๋์์ ๋ฐฉ์งํ๋ ์ญํ ์ ํ๋ค.) terraform init
๋ช
๋ น์ด๋ ๋ฐฑ์๋ ์ค์ ํน์ ํ๋ก์ ํธ ์์์ ์ํํ๊ธฐ์ ์ฌ๋ฌ ์์
์ด ์ผ์ด๋๋ค. ํ๋ก๋ฐ์ด๋๋ง ์
๊ทธ๋ ์ด๋ํ๊ณ ์ถ์ผ๋ฉด, terraform init -upgrade
๋ฅผ ์ํํ๋ค.
์คํฐ๋๋ฅผ ๋ฏธ๋ฆฌ ์งํํด์ฃผ์ ์ ๋ถ๋์ด ํ๋์ ์ดํดํ ์ ์๋ ๊ทธ๋ฆผ์ ๊ทธ๋ ค์ฃผ์ จ๋ค.
์ถ์ฒ:[์ ๋ถ๋ ํฐ์คํ ๋ฆฌ](https://malwareanalysis.tistory.com/619)
์๋์ ๊ฐ์ด, ํํธ๋์ฌ ํน์ ํ๋ฌ๊ทธ์ธ์ ์ ๊ณตํ๋ ์
์ฒด๋ผ๋ฉด ํ
๋ผํผ์ ํตํด ๋ฆฌ์์ค๋ฅผ ์ ์ํ ์ ์๋ค. Terraform๊ณผ ํํธ๋ ๋ชฉ๋ก์ ์๋์ ์ด๋ฏธ์ง ์ฐธ๊ณ
- kubernetes ํ๊ฒฝ ์ธํ๋ผ ๊ตฌ์ถํ๊ธฐ
provider
1 2 3 4 5 6 7 8 9 10 11
terraform { required_providers { kubernetes = { source = "hashicorp/kubernetes" } } } provider "kubernetes" { config_path = "~/.kube/config" }
kubernetes.tf
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
resource "kubernetes_deployment" "nginx" { metadata { name = "nginx-example" labels = { App = "t101-nginx" } } spec { replicas = 2 selector { match_labels = { App = "t101-nginx" } } template { metadata { labels = { App = "t101-nginx" } } spec { container { image = "nginx:1.7.8" name = "example" port { container_port = 80 } } } } } } resource "kubernetes_service" "nginx" { metadata { name = "nginx-example" } spec { selector = { App = kubernetes_deployment.nginx.spec.0.template.0.metadata[0].labels.App } port { node_port = 30080 port = 80 target_port = 80 } type = "NodePort" } }
- ์คํ๊ฒฐ๊ณผ(๋ฏธ๋ํ๋ธ๋ก ํ ์คํธ)
1
2
3
4
5
6
7
8
9
10
11
12
$ terraform init && terraform plan && terraform apply -auto-approve
...
Plan: 2 to add, 0 to change, 0 to destroy.
kubernetes_deployment.nginx: Creating...
kubernetes_deployment.nginx: Still creating... [10s elapsed]
kubernetes_deployment.nginx: Creation complete after 16s [id=default/nginx-example]
kubernetes_service.nginx: Creating...
kubernetes_service.nginx: Creation complete after 0s [id=default/nginx-example]
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
kubernetes_deployment.nginx
kubernetes_service.nginx
1
2
3
4
5
6
7
8
9
Every 1.0s: kubectl get pods,svc MacBook-Pro.local: Wed Sep 13 21:30:54 2023
NAME READY STATUS RESTARTS AGE
pod/nginx-example-868fbd6dcc-8r9bv 1/1 Running 0 89s
pod/nginx-example-868fbd6dcc-xp4rg 1/1 Running 0 89s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 114d
service/nginx-example NodePort 10.103.116.226 <none> 80:30080/TCP 74s
์ด์ฒ๋ผ ์ ์์ ์ผ๋ก ํ ์คํธ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.