Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
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
Tags
more
Archives
Today
Total
관리 메뉴

Study_note

[2주차] T013 테라폼 스터디 본문

카테고리 없음

[2주차] T013 테라폼 스터디

Study_note 2023. 9. 10. 14:43

입력 변수 Variable

입력 변수는 인프라를 구성하는 데 필요한 속성 값을 정의해 코드의 변경 없이 여러 인프라를 생성하는 데 목적이 있다.
테라폼에서는 이것을 입력변수 Input Variables로 정의한다.

데이터 소스 Data

데이터 소스는 테라폼으로 정의되지 않은 외부 리소스 또는 저장된 정보를 테라폼 내에서 참조할 때 사용한다.
 
도전과제1 :  리전 내에서 사용 가능한 가용영역 목록 가져오기를 사용한 VPC 리소스 생성 실습 진행 - 링크 혹은 아무거나 데이터 소스를 사용한 실습 진행
도전과제2 : 위 3개 코드 파일 내용에 리소스의 이름(myvpc, mysubnet1 등)을 반드시! 꼭! 자신의 닉네임으로 변경해서 배포 실습해보세요!
 

provider "aws" {
  region  = "ap-northeast-2"
}

resource "aws_vpc" "myvpc" {
  cidr_block           = "10.10.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "${var.name}"
  }
}

# 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]
  tags = {
    Name = "${var.name}-subnet2"
  }
}
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]
  tags = {
    Name = "${var.name}-subnet2"
  }
}

---
variable "name"{
  type    = string
  default = "jiheon"
  }

 

지역변수 Local

지역 변수를 사용하면  자주 바뀌는 값들을 변수 하나만 바꾸면 되기 때문에 효율이 높아진다.
(하드 코딩을 최대한 피하고 변수를 사용하여 자주 바뀌는 값들을 지정해서 효율을 높히자)
 

# 모듈에 아래와 같이 보안그룹 인그레스를 설정한다 할떄
# 포트같이 자주 바뀔수 있는 값은 변수를 취하면 효율적이기 때문에 local 지역변수로 바꿔보면 아래와 같다 

resource "aws_security_group_rule" "allow_http_inbound" {
  type              = "ingress"
  security_group_id = aws_security_group.alb.id

  from_port   = 80
  to_port     = 0
  protocol    = "-1"
  cidr_blocks = ["0.0.0.0/0"]
}


----------------------------
# 아래와 같이 포트, 프로토콜, cidr를 지역 변수 취했다

locals {
  http_port    = 80
  any_port     = 0
  any_protocol = "-1"
  tcp_protocol = "tcp"
  all_ips      = ["0.0.0.0/0"]
}


----------------------------

# 변수를 취한 후 아래와 같이 사용 (지역 변수는 모듈 내부에 있어야한다.) 

resource "aws_security_group_rule" "allow_http_inbound" {
  type              = "ingress"
  security_group_id = aws_security_group.alb.id

  from_port   = local.http_port
  to_port     = local.http_port
  protocol    = local.tcp_protocol
  cidr_blocks = local.all_ips
}

 
테라폼은 선언적 언어로서 실제 배포된 내용을 정확하게 나타내며, 추론하기 쉽지만 특정 유형의 작업을 하기 어렵다.
 
예를 들어 선언적 언어에는 for 반복문이 없다 ->  같은 리소스를 여러 개 만드는 반복 처리에 어려움이 있다
테라폼은 다행히도 특정 유형을 반복하거나 if문을 사용할 수 있도록 count 메타 변수, for each, for 표현식 등 다양한 함수 등을 제공하고 있다.
 
반복문은 아래와 같다.
 
count 매개 변수 : 리소스를 반복
for_each 표현식 : 리소스 내에서 리소스 및 인라인 블록 반복
for 표현식 : 리스트와 맵을 반복
for 문자열 지시어 : 문자열 내에서 리스트와 맵을 반복
 
count 매개 변수 
count는 테람폼의 가장 오래되고 단순하며 ㅈ제한된 반복 구조로써 count에 생성하고자 하는 리소스 사본수만 정의된다.
 

# 만약 neo라는 사용자를 3개 생성하고 싶다면 아래와 같이 리소스를 생성하면된다.
resource "aws_iam_user" "example" {
  count = 3
  name  = "neo"
}

----------------------------------------------------

하지만 위 처럼 구축한다면 같은 이름의 사용자는 생성이 안되기 때문에 에러가 발생한다.
그렇기 때문에 아래와 같이 count.index를 사용하여 반복문 안에 있는 각각의 반복을 가리키는 인덱스를 사용
resource "aws_iam_user" "example" {
  count = 3
  name  = "neo.${count.index}"
}

-> neo.0, neo.1, neo.2 같은 결과 값이 생성되는것을 확인 가능

----------------------------------------------------

아래와 같이 리스트 형식에 입력 변수를 생성하고 디폴값을 정의했을 경우
variable "user_names" {
  description = "Create IAM users with these names"
  type        = list(string)
  default     = ["neo", "trinity", "morpheus"]
}

디폴값을 정의한 값들을 사용자 이름으로 삽일할려면 아래와 같다
resource "aws_iam_user" "example" {
  count = length(var.user_names)   # length는 주어진 값의 항목수를 반환하는 함수
  name  = var.user_names[count.index] # count 값 하드 코딩하지 말고 변수 값 호출
}

-> neo, trinity, morpheus 값 생성되는것을 확인 가능

하지만 count 매개 변수에는 유용성을 저해하는 두 가지 제약이 있다.
1. 전체 리소스를 반복할 수는 있지만 리소스 내에서 인라인 블록을 반복할 수는 없다.
2. 변경할 때 문제 발생
 

첫 번쨰 제약 예
아래와 같이 오토스케일링 그룹을 생성할때 인스턴스의 이름 테그를 따로 지정 시
count는 인라인 블록내에서 사용을 지원하지 않아 다르게 설정할 수 없다. 

resource "aws_autoscaling_group" "example" {
  launch_configuration = X
  vpc_zone_identifier  = X
  target_group_arns    = X
  health_check_type    = "X"

  min_size = X
  max_size = X

  tag {
    key                 = "Name"
    value               = var.cluster_name
    propagate_at_launch = true
  }
}


----------------------------------------------------
두 번쨰 제약 예

aws_iam_user.eaxample[0] = neo
aws_iam_user.eaxample[1] = trinity
aws_iam_user.eaxample[2] = morpheus

이 구조에서 aws_iam_user.eaxample[1] = trinity 삭제 시
aws_iam_user.eaxample[2] = morpheus가 aws_iam_user.eaxample[1] =morpheus 가 된다.

즉 중간에서 삭제 시 해당 항목 뒤에있는 리소스를 삭제한다음 해당 리소르를 처음부터 만든다.
그래서 기존에 [2]를 가리키던 코드들은 삭제 되고 [1]의 코드들은 남아 있는 상태가 된다.

for_each
 
for_each를 사용하면 리스트, 집합, 맵을 사용 하여 리소스 내 인라인 블록의 여러 복사본을 생성할 수 있습니다.
또한 리소스를 맵으로 처리하면 컬렉션 중간의 항목도 안전하게 제거할 수 있어 count를 사용해 리소를 배열로 처리하는 것보다 이점이 크다.
 

for_each의 표현식은 아래와 같다.

for_each = <COLLECTION>   #  COLLECTION은 루프를 처리할 집합 또는 맵
[CONFIG....]

for_each의 값으로는 리스트를 사용할 수 없다.
resource "aws_iam_user" "example" {
  for_each = toset(var.user_names)
  name     = each.value
}

리스트인 var.user_names를 집합으로 변환하기 위해 toset을 사용
for_each를 반복하면 each.value에서 각 사용자 이름을 사용할 수 있다.
또한 for_each를 사용한 후에는 하나의 리소스 또는 배열이 되는 것이 아니라 리소스 맵이 된다

---------------------------

아래와 같이 생성한 배열 값이 아닌 집합으로 모든 사용자의 값을 출력 하면
리소스의 전체 출력인 맵을 포함 한다.

output "all_users" {
  value = aws_iam_user.example
}

---------------------------

# 위에서 다음과 같은 입력변수를 생성했었다.
# variable "user_names" {
#   description = "Create IAM users with these names"
#   type        = list(string)
#   default     = ["neo", "trinity", "morpheus"]
# }

---------------------------------

아래와 같이 커스텀 테그라는 입렵 변수 생성

variable "custom_tags" {
  description = "Custom tags to set on the Instances in the ASG"
  type        = map(string)
  default     = {}
}

------------------------------

위에 오토스케일링 그룹을 생성했던것과 같이 구문에서 인라인 블록을 동적으로 생성하는 구문은 아래와 같다
 
   dynamic "<var_name>" {  # 원하는 변수 이름 입력
    for_each = <collection> # collection은 생성할 정보를 전달받고 그 수만큼 block 이 생성
    }

    content {     # <var_name>.key, <var_name>.value를 사용해 입력 값 설정
      [config..]
    }
  }
 
 하지만 동적 블록을 과도하게 사용하면 구성을 읽고 유지하기 어렵게 만들 수 있음
 
 ------------------------------
 
 tag {
    key                 = "Name"
    value               = var.cluster_name
    propagate_at_launch = true
  }

  dynamic "tag" {
    for_each = var.custom_tags
    }

    content {
      key                 = tag.key
      value               = tag.value
      propagate_at_launch = true
    }
  }
---------------  
  모듈 사용하는 파일에 입력 변수 입력
    custom_tags = {
    Owner     = "team-foo"
    ManagedBy = "terraform"
  }
  
  -> 결과 값으로 tag외 동적으로 추가한 값들도 생성된것을 확인
  
   tag {
    key                 = "Owner"
    value               = "team-foo"
    propagate_at_launch = true
  }
  
   tag {
    key                 = "ManagedBy"
    value               = "terraform"
    propagate_at_launch = true
  }

 
for 표현식을 이용한 반복문
리소스와 인라인 블록을 반복하는 것이 아닌 단일 값을 생성하기 위해 반복이 필요할 때 사용
 

리스트 반복 구문 형식은 아래와 같다
for <item> in <list> : <output>

아래와 같이 리스트 형식의 변수를 생성하고 출력해보면

variable "names" {
  description = "A list of names"
  type        = list(string)
  default     = ["neo", "trinity", "morpheus"]
}

output "upper_names" {
  value = [for name in var.names : upper(name)]
}

결과 값이 아래와 같이 생성 확인 가능
upper_names = [
  "NEO",
  "TRINITY",
  "MORPHEUS",
]

-----------------------------

맵 반복 구문 형식은 아래와 같다
for <key>, <value> in <map> : <output>

아래와 같이 맵 형식의 변수를 생성하고 출력해보면

variable "hero_thousand_faces" {
  description = "map"
  type        = map(string)
  default     = {
    neo      = "hero"
    trinity  = "love interest"
    morpheus = "mentor"
  }
}

output "bios" {
  value = [for name, role in var.hero_thousand_faces : "${name} is the ${role}"]
}

결과 값이 아래와 같이 생성 확인 가능
bios = [
  "morpheus is the mentor",
  "neo is the hero",
  "trinity is the love interest",
]

 
조건문
조건문을 설정하는 여러 방법이 있으며 아래와 같다
 
count 매개 변수 -> 조건부 리소스에서 사용
for_each와 for 표현식 -> 리소스 내의 조건부 리소스 및 인라인 블록에 사용
if 문자열 지시자 -> 문자열 내의 조건문에서 사용
 

우선적으로 count 매개 변수 조건문은 bool을 사용하여 true or false에 따른 결과 값을 다르게 설정한다

아래와 같이 bool 값의 변수 값을 생성
variable "enable_autoscaling" {
  description = "If set to true, enable auto scaling"
  type        = bool
}

조건문 구문은 아래와 같다
  count = <condition> ? <true_val> : <false_val> # 컨디션의 bool 값의 변수 넣는다

모듈에 다음 count 매개변수 조건문 추가
resource "aws_autoscaling_schedule" "scale_in_at_night" {
  count = var.enable_autoscaling ? 1 : 0
  
모듈을 사용할 파일에서 bool 입력 변수 값이 true 즉 1 값으이고 false는 0값으로 지정했기 때문에
입력 값에 따라 생성된다.

-----------------------------------

하지만 bool 값이 문자열 등의 더 복잡한 비교의 결과인 경우 아래와 같다.

아래에 bool 값이 아닌 문자열 입력 변수가 있을때
variable "instance_type" {
  description = "The type of EC2 Instances to run (e.g. t2.micro)"
  type        = string
}

아래와 같이 format 함수를 사용하여 var.instance_type에서 첫 번쨰 문자만 추출하여
해당 문자가 "t"일 경우 count를 1로 설정하고 "t"가 아닐 경우 count가 0이 되어 생성되지 않는다.

resource "aws_cloudwatch_metric_alarm" "low_cpu_credit_balance" {
  count = format("%.1s", var.instance_type) == "t" ? 1 : 0
  
-----------------------------------

조금 더 효율적으로 사용하면 if-else 문을 생성할수 있다.

아래와 같이 t계열이면 low_cpu_credit_balance가 생성되고 t가 아니라면 high_cpu_credit_balance 생성
resource "aws_cloudwatch_metric_alarm" "low_cpu_credit_balance" {
  count = format("%.1s", var.instance_type) == "t" ? 1 : 0
  [config....]
  
resource "aws_cloudwatch_metric_alarm" "high_cpu_credit_balance" {
  count = format("%.1s", var.instance_type) == "t" ? 0 : 1
  [config....]


      key => upper(value)
      if key != "Name"
    }

    content {
      key                 = tag.key
      value               = tag.value
      propagate_at_launch = true
    }
  }

 
for_each와 for 표현식과 if 문자열 지시자 조건문도 있지만 생략한다.
일반적으로 리소스를 조건부로 생성할 때는 count를 사용하고 그 외 모든 유형의 반복문 및 조건문에서는 for_each를 사용하기 때문
 

일반적으로 리소스 조건 생성할 때 ->  count 매개 변수
이 외의 경우(인라인 블록 등)에서 반복 생성할 때 -> for_each와 for 표현식 사용

Comments