사전 준비
aws로그인 https://console.aws.amazon.com/
명령서버에서 사용할 pem키 필요
access-key 필요
secret-key 필요
1
참고 자료
https://www.youtube.com/playlist?list=PL1mta2YyMpPXxFGBtSJyvoKnWTqZslm5p
aws cloudformation ?
기존 반복문이 없어 EC2를 5대 배포해야 하면, 코드 줄이 길어졌다.
반복문 ForEach 제공 시작 2023년 7월 26일
cd
mkdir 39
cd 39
2
count 사용
리소스 또는 모듈 블록에 count 값이 정수인 인수가 포함된 경우, 선언된 정수 값만큼 리소스나 모듈을 생성하게 된다
아래와 같이 count를 사용해 보자.
vi main.tf
resource "local_file" "abc" {
count = 5
content = "abc"
filename = "${path.module}/abc.txt"
}
output "filecontent" {
value = local_file.abc.*.content
}
output "fileid" {
value = local_file.abc.*.id
}
output "filename" {
value = local_file.abc.*.filename
}
3
terraform init && terraform apply -auto-approve
아래는 컨텐츠를 5번 실행하는 것이다.
Outputs:
filecontent = [
"abc",
"abc",
"abc",
"abc",
"abc",
]
fileid = [
"a9993e364706816aba3e25717850c26c9cd0d89d",
"a9993e364706816aba3e25717850c26c9cd0d89d",
"a9993e364706816aba3e25717850c26c9cd0d89d",
"a9993e364706816aba3e25717850c26c9cd0d89d",
"a9993e364706816aba3e25717850c26c9cd0d89d",
]
filename = [
"./abc.txt",
"./abc.txt",
"./abc.txt",
"./abc.txt",
"./abc.txt",
]
terraform state list
local_file.abc[0]
local_file.abc[1]
local_file.abc[2]
local_file.abc[3]
local_file.abc[4]
terraform state show local_file.abc[0]
terraform state show local_file.abc[4]
ls *.txt
abc.txt
4
결과?
파일명이 같은 파일1개가 생긴다.
abc.txt 1개
# 테라폼 콘솔로 상세 내역을 찍어보자~
terraform console
>
-----------------
local_file.abc
// 5개가 실행된다. 같은 파일이 5개이다.
local_file.abc[0]
local_file.abc[4]
exit
-----------------
#
terraform output
terraform output filename
[
"./abc.txt",
"./abc.txt",
"./abc.txt",
"./abc.txt",
"./abc.txt",
]
terraform output fileid
terraform output filecontent
rm -rf main.tf
vi main.tf
수정
// content 내용도 abc0, abc1
// filename 은 abc0.txt , abc1.txt , ........
resource "local_file" "abc" {
count = 5
content = "abc${count.index}"
filename = "${path.module}/abc${count.index}.txt"
}
output "fileid" {
value = local_file.abc.*.id
}
output "filename" {
value = local_file.abc.*.filename
}
output "filecontent" {
value = local_file.abc.*.content
}
Outputs:
filecontent = [
"abc0",
"abc1",
"abc2",
"abc3",
"abc4",
]
fileid = [
"062c648aaf68174757c50ab1aeebb61e059c1d1b",
"9ee036287b4cfbcfa3b5bbfcf92d46eb5e75df96",
"229d028063a11904f846c91224abaa99113f3a15",
"99bdd81005eaa37fa71ff0787cd1d65f63d3d293",
"5ac835798aa493440692c54c7ab76161f06c1b88",
]
filename = [
"./abc0.txt",
"./abc1.txt",
"./abc2.txt",
"./abc3.txt",
"./abc4.txt",
]
#
terraform apply -auto-approve
terraform state list
ls *.txt
terraform state list
local_file.abc[0]
local_file.abc[1]
local_file.abc[2]
local_file.abc[3]
local_file.abc[4]
ls
abc0.txt abc1.txt abc2.txt abc3.txt abc4.txt main.tf terraform.tfstate terraform.tfstate.backup
terraform console
>
-----------------
local_file.abc[0]
local_file.abc[4]
exit
-----------------
terraform output
terraform output filename
terraform output fileid
terraform output filecontent
[
"abc0",
"abc1",
"abc2",
"abc3",
"abc4",
]
# graph 확인 > graph.dot 파일 선택 후 오른쪽 상단 DOT 클릭
terraform graph > graph.dot
1
rm -rf main.tf
vi main.tf
// list 는 스트링 "a" "b" "c"
variable "names" {
type = list(string)
default = ["a", "b", "c"]
}
resource "local_file" "abc" {
count = length(var.names)
content = "abc"
# 변수 인덱스에 직접 접근
filename = "${path.module}/abc-${var.names[count.index]}.txt"
}
resource "local_file" "def" {
count = length(var.names)
content = local_file.abc[count.index].content
# element function 활용
filename = "${path.module}/def-${element(var.names, count.index)}.txt"
}
// default = ["a", "b", "c"] 리스트를 사용한다.
// count = length(var.names) 은 3 이 된다.
// abc 3번 , def 3 번 실행 = 총 6개 파일 생김.
7
terraform apply -auto-approve
terraform state list
local_file.abc[0]
local_file.abc[1]
local_file.abc[2]
local_file.def[0]
local_file.def[1]
local_file.def[2]
ls *.txt
abc-a.txt abc-b.txt abc-c.txt def-a.txt def-b.txt def-c.txt
ls
abc-a.txt abc-b.txt abc-c.txt def-a.txt def-b.txt def-c.txt main.tf terraform.tfstate
terraform.tfstate.backup
# more abc-a.txt
abc
# more abc-b.txt
abc
# more def-a.txt
abc
diff abc-a.txt abc-b.txt
(동일)
diff abc-a.txt def-c.txt
(동일)
terraform console
>
-----------------
local_file.abc[0]
local_file.def[4]
exit
-----------------
terraform output
terraform output filename
terraform output fileid
terraform output filecontent
terraform refresh
# graph 확인 > graph.dot 파일 선택 후 오른쪽 상단 DOT 클릭
terraform graph > graph.dot
8
변경 해보자~
cd
mkdir 391
cd 391
default = ["a", "b", "c"] 리스트를 사용한다.
b를 삭제해 본다.
default = ["a", "c"] 리스트를 사용한다.
외부 변수가 list 타입인 경우 중간에 값이 삭제되면 인덱스가 줄어들어 의도했던 중간 값에 대한 리소스만 삭제되는 것이 아니라 이후의 정의된 리소스들도 삭제되고 재생성된다
rm -rf *.tf
vi main.tf
variable "names" {
type = list(string)
default = ["a", "c"] # index 1자리의 b를 삭제
}
resource "local_file" "abc" {
count = length(var.names)
content = "abc"
# 변수 인덱스에 직접 접근
filename = "${path.module}/abc-${var.names[count.index]}.txt"
}
resource "local_file" "def" {
count = length(var.names)
content = local_file.abc[count.index].content
# element function 활용
filename = "${path.module}/def-${element(var.names, count.index)}.txt"
}
10
terraform init
terraform plan
ls -l *.txt
terraform apply -auto-approve
#
terraform state list
local_file.abc[0]
local_file.abc[1]
local_file.def[0]
local_file.def[1]
// index 0 , index 1이 들어감 = count는 정수 순번대로 생성되나, 중간 값을 삭제하면 장애 발생 우려됨.
// 이렇경우 for_each 사용을 권장한다.
1
선언된 key 값 개수만큼 리소스를 생성하게 된다.
rm -rf *
vi main.tf
resource "local_file" "abc" {
for_each = {
a = "content a"
b = "content b"
}
content = each.value
filename = "${path.module}/${each.key}.txt"
}
2
#
terraform apply -auto-approve
terraform state list
local_file.abc["a"]
local_file.abc["b"]
ls *.txt
a.txt b.txt
cat a.txt ;echo
cat b.txt ;echo
391]# cat a.txt ;echo
content a
391]# cat b.txt ;echo
content b
terraform console
>
-----------------
local_file.abc
local_file.abc[a]
Error: Invalid index
local_file.abc["a"]
{
"content" = "content a"
exit
3
main.tf 파일 수정 ?
local_file.abc는 변수의 map 형태의 값을 참조, local_file.def의 경우 local_file.abc 또한 결과가 map으로 반환되므로 다시 for_each 구문을 사용할 수 있다
rm -rf *
vi main.tf
variable "names" {
default = {
a = "content a"
b = "content b"
c = "content c"
}
}
resource "local_file" "abc" {
for_each = var.names
content = each.value
filename = "${path.module}/abc-${each.key}.txt"
}
resource "local_file" "def" {
for_each = local_file.abc
content = each.value.content
filename = "${path.module}/def-${each.key}.txt"
}
4
terraform apply -auto-approve
terraform state list
ls *.txt
# terraform state list
local_file.abc["a"]
local_file.abc["b"]
local_file.abc["c"]
local_file.def["a"]
local_file.def["b"]
local_file.def["c"]
# ls *.txt
abc-a.txt abc-b.txt abc-c.txt def-a.txt def-b.txt def-c.txt
# more abc-a.txt
content a
# more abc-b.txt
content b
5
중간 삭제 테스트 ?
key 값은 count의 index와는 달리 고유하므로 중간에 값을 삭제한 후 다시 적용해도 삭제한 값에 대해서만 리소스를 삭제한다
rm -rf *
vi main.tf
variable "names" {
default = {
a = "content a"
c = "content c"
}
}
resource "local_file" "abc" {
for_each = var.names
content = each.value
filename = "${path.module}/abc-${each.key}.txt"
}
resource "local_file" "def" {
for_each = local_file.abc
content = each.value.content
filename = "${path.module}/def-${each.key}.txt"
}
#
terraform apply -auto-approve
terraform state list
ls *.txt
# terraform state list
local_file.abc["a"]
local_file.abc["c"]
local_file.def["a"]
local_file.def["c"]
# ls *.txt
abc-a.txt abc-c.txt def-a.txt def-c.txt
1
cd
mkdir iam
cd iam
// 사용자 1명 생성 형식
vi iam.tf
provider "aws" {
region = "us-east-2"
}
resource "aws_iam_user" "example" {
name = "1000"
}
terraform init && terraform plan
terraform apply -auto-approve
terraform destroy -auto-approve
2
// 일반 for 문은 안됨. count나 for each 사용하세요~
# This is just pseudo code. It won't actually work in Terraform.
for (i = 0; i < 3; i++) {
resource "aws_iam_user" "example" {
name = "neo"
}
}
// neo를 3번 만들려고 해서 에러가 난다.
3
iam.tf
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_iam_user" "myiam" {
count = 3
name = "myuser.${count.index}"
}
4
terraform init && terraform plan
Plan: 3 to add, 0 to change, 0 to destroy.
terraform apply -auto-approve
// aws iam console 에서 확인 = user계정 3개가 생성 됨.
myuser.0
myuser.1
myuser.2
# 확인
terraform state list
aws_iam_user.myiam[0]
aws_iam_user.myiam[1]
aws_iam_user.myiam[2]
aws iam list-users | jq
:
#
terraform console
>
aws_iam_user.myiam
aws_iam_user.myiam[0]
aws_iam_user.myiam[1].name
"myuser.1"
exit
5
삭제
terraform destroy -auto-approve
// iam에서 계정 삭제됨
aws iam list-users | jq
rm -rf *
1
// 계정이 1000,2000,3000 3개의 계정을 만들고자 함.
입력 변수 코드 사용 =
vi variables.tf
variable "user_names" {
description = "Create IAM users with these names"
type = list(string)
default = ["1000", "2000", "3000"]
}
2
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_iam_user" "myiam" {
count = length(var.user_names)
name = var.user_names[count.index]
}
// count = length(var.user_names) 은 3 이 됨.
3
#
terraform plan
...
# aws_iam_user.myiam[0] will be created
# aws_iam_user.myiam[1] will be created
# aws_iam_user.myiam[2] will be created
4
// 출력해서 확인해보자~~
// * 를 사용 가능하다. value = aws_iam_user.myiam[*].arn
vi output.tf
output "first_arn" {
value = aws_iam_user.myiam[0].arn
description = "The ARN for the first user"
}
output "all_arns" {
value = aws_iam_user.myiam[*].arn
description = "The ARNs for all users"
}
5
#
terraform apply -auto-approve
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
Outputs:
all_arns = [
"arn:aws:iam::319485572629:user/1000",
"arn:aws:iam::319485572629:user/2000",
"arn:aws:iam::319485572629:user/3000",
]
first_arn = "arn:aws:iam::319485572629:user/1000"
terraform state list
aws_iam_user.myiam[0]
aws_iam_user.myiam[1]
aws_iam_user.myiam[2]
terraform output
all_arns = [
"arn:aws:iam::319485572629:user/1000",
"arn:aws:iam::319485572629:user/2000",
"arn:aws:iam::319485572629:user/3000",
]
first_arn = "arn:aws:iam::319485572629:user/1000"
terraform output all_arns
6
콘솔에서 계정 생성 확인
1000
2000
3000
7
중간 사용자 퇴사 하여 삭제 하고자함.
// 사번이 1000,2000,3000 중 2000번 사번자 퇴사함.
vi variables.tf
수정
variable "user_names" {
description = "Create IAM users with these names"
type = list(string)
default = ["1000", "3000"]
}
// 중간 항목을 제거하면, 인덱스가 하나씩 당겨짐. 문제 발생함.
// 모든 유형이 같을 때만 count 사용 필요
// count 사용 시 목록 중간 항목을 제거하면 테라폼은 해당 항목 뒤에 있는 모든 리소스를 삭제한 다음 해당 리소스를 처음부터 다시 만듬
# plan : 출력 내용 확인!
terraform plan
# aws_iam_user.myiam[2] will be destroyed
# (because index [2] is out of range for count)
- resource "aws_iam_user" "myiam" {
- arn = "arn:aws:iam::319485572629:user/3000" -> null
- force_destroy = false -> null
- id = "3000" -> null
- name = "3000" -> null
- path = "/" -> null
- tags = {} -> null
- tags_all = {} -> null
- unique_id = "AIDAUUYWS6YKXZ4IL5XUV" -> null
}
Plan: 0 to add, 1 to change, 1 to destroy.
Changes to Outputs:
~ all_arns = [
# (1 unchanged element hidden)
"arn:aws:iam::319485572629:user/2000",
- "arn:aws:iam::319485572629:user/3000",
]
8
terraform apply -auto-approve
aws_iam_user.myiam[2]: Destroying... [id=3000]
aws_iam_user.myiam[1]: Modifying... [id=2000]
aws_iam_user.myiam[2]: Destruction complete after 1s
╷
│ Error: updating IAM User (2000): EntityAlreadyExists: User with name 3000 already exists.
│ status code: 409, request id: 1f520af3-1a70-4ca6-8181-cdc3de0afe54
│
│ with aws_iam_user.myiam[1],
│ on iam.tf line 10, in resource "aws_iam_user" "myiam":
│ 10: resource "aws_iam_user" "myiam" {
│
╵
// 헉! 3000 사번이 지워짐. 2000 계정을 삭제 했는데 ~~
// 콘솔에 확인하면 1000 , 2000 계정만 존재함.
9
삭제
terraform destroy -auto-approve
aws iam list-users | jq
count : 반복문, 정수 값만큼 리소스나 모듈을 생성 권장함.
for_each 으로 계정 생성 테스트
// 반복문, 선언된 key 값 개수만큼 리소스를 생성
// key가 있어서 숫자가 틀리지 않는다.
1
rm -rf *.tf
vi iam.tf
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_iam_user" "myiam" {
for_each = toset(var.user_names)
name = each.value
}
2
variable "user_names" {
description = "Create IAM users with these names"
type = list(string)
default = ["1000", "2000", "3000"]
}
3
output.tf
output "all_users" {
value = aws_iam_user.myiam
}
4
#
terraform plan && terraform apply -auto-approve
# 확인
terraform state list
aws_iam_user.myiam["1000"]
aws_iam_user.myiam["2000"]
aws_iam_user.myiam["3000"]
terraform output
5
variables.tf 2명으로 수정
variable "user_names" {
description = "Create IAM users with these names"
type = list(string)
default = ["1000", "3000"]
}
6
terraform plan
terraform apply -auto-approve
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
- destroy
Terraform will perform the following actions:
# aws_iam_user.myiam["2000"] will be destroyed
# (because key ["2000"] is not in for_each map)
- resource "aws_iam_user" "myiam" {
- arn = "arn:aws:iam::319485572629:user/2000" -> null
- force_destroy = false -> null
- id = "2000" -> null
- name = "2000" -> null
- path = "/" -> null
- tags = {} -> null
terraform state list
aws_iam_user.myiam["1000"]
aws_iam_user.myiam["3000"]
// 원하는 데로 2000 계정 삭제됨!!
7
// 계정 모두 삭제
terraform destroy -auto-approve
aws iam list-users | jq
rm -rf *.tf
1
소문자를 대문자로 변경
vi main.tf
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"
}
// s가 var.names 으로 a ,b ,c 가 된다.
// upper(s)에 s에 a ,b, c 가 들어가서 대문자가 된다.
2
참고
title
https://developer.hashicorp.com/terraform/language/functions/title
#
terraform init
terraform apply -auto-approve
terraform state list
ls *.txt
cat abc.txt ;echo
# terraform state list
local_file.abc
# ls *.txt
abc.txt
# cat abc.txt ;echo
["A","B","C"]
# 참고 jsonencode Function
terraform console
>
-----------------
jsonencode([for s in var.names : upper(s)])
"[\"A\",\"B\",\"C\"]"
[for s in var.names : upper(s)]
[
"A",
"B",
"C",
]
[for txt in var.names : upper(txt)]
title("hello world")
exit
3
rm -rf *.tf
vi main.tf
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"]
}
4
#
terraform apply -auto-approve
Outputs:
A_upper_value = [
"A",
"B",
]
B_index_and_value = [
"0 is a",
"1 is b",
]
C_make_object = {
"a" = "A"
"b" = "B"
}
D_with_filter = [
"B",
terraform state list
#
terraform output
terraform output A_upper_value
[
"A",
"B",
]
terraform output D_with_filter
[
"B",
]
#
terraform console
>
-----------------
var.names
tolist([
"a",
"b",
])
[for v in var.names : upper(v)]
[
"A",
"B",
]
[for i, v in var.names : "${i} is ${v}"]
{ for v in var.names : v => upper(v) }
[for v in var.names : upper(v) if v != "a"]
exit
5
rm -rf *.tf
vi main.tf
variable "members" {
type = map(object({
role = string
}))
default = {
ab = { role = "member", group = "dev" }
cd = { role = "admin", group = "dev" }
ef = { role = "member", group = "ops" }
}
}
output "A_to_tupple" {
value = [for k, v in var.members : "${k} is ${v.role}"]
}
output "B_get_only_role" {
value = {
for name, user in var.members : name => user.role
if user.role == "admin"
}
}
output "C_group" {
value = {
for name, user in var.members : user.role => name...
}
}
6
#
terraform apply -auto-approve
Outputs:
A_to_tupple = [
"ab is member",
"cd is admin",
"ef is member",
]
B_get_only_role = {
"cd" = "admin"
}
C_group = {
"admin" = [
"cd",
]
"member" = [
"ab",
"ef",
]
}
terraform state list
#
terraform output
terraform output A_upper_value
// not fount
#
terraform console
>
-----------------
var.members
[for k, v in var.members : "${k} is ${v.role}"]
{for name, user in var.members : name => user.role}
{for name, user in var.members : name => user.role if user.role == "admin"}
{for name, user in var.members : user.role => name...}
exit
1
rm -rf *.tf
vi main.tf
// 속성을 4개 사용하는 경우 = 4번 입력하여 사용한다.
data "archive_file" "dotfiles" {
type = "zip"
output_path = "${path.module}/dotfiles.zip"
source {
content = "hello a"
filename = "${path.module}/a.txt"
}
source {
content = "hello b"
filename = "${path.module}/b.txt"
}
source {
content = "hello c"
filename = "${path.module}/c.txt"
}
}
2
#
terraform init -upgrade
terraform apply -auto-approve
terraform state list
data.archive_file.dotfiles
terraform state show data.archive_file.dotfiles
ls *.zip
dotfiles.zip
unzip dotfiles.zip
Archive: dotfiles.zip
inflating: a.txt
inflating: b.txt
inflating: c.txt
ls *.txt
cat a.txt ; echo
hello a
3
dynamic으로 재구성 해보자~~~~
rm -rf *
vi main.tf
variable "names" {
default = {
a = "hello a"
b = "hello b"
c = "hello c"
}
}
data "archive_file" "dotfiles" {
type = "zip"
output_path = "${path.module}/dotfiles.zip"
dynamic "source" {
for_each = var.names
content {
content = source.value
filename = "${path.module}/${source.key}.txt"
}
}
}
4
#
terraform apply -auto-approve
terraform state list
terraform state show data.archive_file.dotfiles
type = "zip"
source {
content = "hello a"
filename = "./a.txt"
}
source {
content = "hello b"
filename = "./b.txt"
}
source {
content = "hello c"
filename = "./c.txt"
}
}
ls *.zip
dotfiles.zip
https://brunch.co.kr/@topasvga/3370
몰아보기
https://brunch.co.kr/@topasvga/3347
https://gasidaseo.notion.site/gasidaseo/CloudNet-Blog-c9dfa44a27ff431dafdd2edacc8a1863
감사합니다.