<1> 모듈 작성 기본 원칙 <2> 모듈 실습 <3> 모듈과 프로바이더 실습1 <4> 루트 모듈에서 프로바이더 정의(실습) <5> 모듈의 반복문 - count 사용 <6> 모듈의 반복문 - for each 문 <7> 모듈 소스 관리 <8> 테라폼 레지스트리에 공개된 모듈을 사용하여 리소스 배포 <1> 모듈 작성 기본 원칙 1 기본 원칙 : 모듈은 대부분의 프로그래밍 언어에서 쓰이는 라이브러리나 패키지와 역할이 비슷하다 2 모듈 디렉터리 형식을 terraform-<프로바이더 이름>-<모듈 이름> 형식을 제안한다. 예) terraform-aws-module 디렉토리 또는 레지스트리 이름 - 어떤 프로바이더 - 모듈 이름 <2> 모듈 실습 1 구성 ? random_pet는 이름을 자동으로 생성 random_password는 사용자의 패스워드를 설정 https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/pet 2 자식 모듈을 만든다. root 모듈을 만들어 자식모듈을 불러 쓴다. 3 mkdir -p 06-module-traning/modules/terraform-random-pwgen cd 06-module-traning/modules/terraform-random-pwgen 4 자식 모듈 만든다 ? main.tf , variable.tf , output.tf 파일 3개를 만든다. vi main.tf resource "random_pet" "name" { keepers = { ami_id = timestamp() } } resource "random_password" "password" { length = var.isDB ? 16 : 10 special = var.isDB ? true : false override_special = "!#$%*?" } 5 vi variable.tf variable "isDB" { type = bool default = false description = "패스워드 대상의 DB 여부" } 6 vi output.tf output "id" { value = random_pet.name.id } output "pw" { value = nonsensitive(random_password.password.result) } 7 자식 모듈 테스트 # cd 06-module-traning/modules/terraform-random-pwgen # ls *.tf terraform init && terraform plan # 테스트를 위해 apply 시 변수 지정 terraform apply -auto-approve -var=isDB=true // 변수를 true로 해서 실행!!! Apply complete! Resources: 2 added, 0 changed, 0 destroyed. Outputs: id = "knowing-aardvark" pw = "Y5eeP0i2KLLE9gBa" # 확인 terraform state list terraform state show random_pet.name terraform state show random_password.password # tfstate에 모듈 정보 확인 cat terraform.tfstate | grep module # graph 확인 terraform graph > graph.dot 8 자식 모듈 호출 실습 mkdir -p 06-module-traning/06-01-basic vi main.tf module "mypw1" { source = "../modules/terraform-random-pwgen" } module "mypw2" { source = "../modules/terraform-random-pwgen" isDB = true } output "mypw1" { value = module.mypw1 } output "mypw2" { value = module.mypw2 } 9 실행 : 자식 모듈을 호출해 반복 재사용하는 루트 모듈의 결과 # cd 06-module-traning/06-01-basic # terraform init && terraform plan && terraform apply -auto-approve Apply complete! Resources: 2 added, 0 changed, 0 destroyed. Outputs: mypw1 = { "id" = "equipped-mustang" "pw" = "OXST1EYqQc" } mypw2 = { "id" = "diverse-impala" "pw" = "y8mEbOJhS6dCTiK#" } // 반복문처럼 Output이 나온다. 자식모듈을 호출해서 반복 사용을 했다. // 패스워드 길이가 다르다. 10자리, 16자리 # 확인 terraform state list 10 # tfstate에 모듈 정보 확인 cat terraform.tfstate | grep module 테라폼 root 모듈 state 파일의 resources 부분에 module 내용이 생긴다. 11 # terraform init 시 생성되는 modules.json 파일 확인 tree .terraform .terraform ├── modules │ └── modules.json ... ## 모듈로 묶여진 리소스는 module이라는 정의를 통해 단순하게 재활용하고 반복 사용할 수 있다. ## 모듈의 결과 참조 형식은 module.<모듈 이름>.으로 정의된다. cat .terraform/modules/modules.json | jq { "Modules": [ { "Key": "", "Source": "", "Dir": "." }, { "Key": "mypw1", "Source": "../modules/terraform-random-pwgen", "Dir": "../modules/terraform-random-pwgen" }, { "Key": "mypw2", "Source": "../modules/terraform-random-pwgen", "Dir": "../modules/terraform-random-pwgen" } ] } # graph 확인 terraform graph > graph.dot <3> 모듈과 프로바이더 실습1 1 Root module에 공통적으로 프로바이더를 설정하라. Child module에 설정하면 문제가 될수 있다. 자식모듈은 루트 모듈의 프로바이더에 종속된다. 모듈에는 다수의 프로바이더가 사용될 가능성이 있으므로 map타입으로 구성하는 provider로 정의한다. 문제 ? Root와 자식 모듈간에 조건 합의가 안되면 오류가 발생한다. Child module에서 프로바이더를 쓰면, 반복문을 쓸수 없다. 2 실습을 위한 디렉터리 구성의 예 06-module-traning ├─ modules # child │ └── terraform-aws-ec2 │ └──main.tf └─ multi_provider_for_module #root └──main.tf 3 # child mkdir -p 06-module-traning/modules/terraform-aws-ec2/ 4 # ec2 배포하는 내용 - 디폴트 vpc 사용 예제. vi main.tf terraform { required_providers { aws = { source = "hashicorp/aws" } } } resource "aws_default_vpc" "default" {} data "aws_ami" "default" { most_recent = true owners = ["amazon"] filter { name = "owner-alias" values = ["amazon"] } filter { name = "name" values = ["amzn2-ami-hvm*"] } } resource "aws_instance" "default" { depends_on = [aws_default_vpc.default] ami = data.aws_ami.default.id instance_type = var.instance_type tags = { Name = var.instance_name } } // depends_on = [aws_default_vpc.default] 디폴트 vpc가 있는지 디펜트온을 걸어 놓는다. ami = data.aws_ami.default.id // ami은 data에서 가져온다. instance_type = var.instance_type // 인스턴스는 var 변수에서 가져온다. 5 vi variable.tf variable "instance_type" { description = "vm 인스턴스 타입 정의" default = "t2.micro" } variable "instance_name" { description = "vm 인스턴스 이름 정의" default = "my_ec2" } 6 vi output.tf output "private_ip" { value = aws_instance.default.private_ip } <4> 루트 모듈에서 프로바이더 정의(실습) 1 06-module-traning/multi_provider_for_module/main.tf 과 output.tf 파일 생성 mkdir -p 06-module-traning/multi_provider_for_module/ cd 06-module-traning/multi_provider_for_module/ 2 vi main.tf provider "aws" { region = "ap-southeast-1" } provider "aws" { alias = "seoul" region = "ap-northeast-2" } module "ec2_singapore" { source = "../modules/terraform-aws-ec2" } module "ec2_seoul" { source = "../modules/terraform-aws-ec2" providers = { aws = aws.seoul } instance_type = "t3.small" } // 디폴트는 싱가포르로 생성된다. // 서울은 프로바이더에 값을 주어, 서버 타입을 t3로 변경한다. 3 vi output.tf output "module_output_singapore" { value = module.ec2_singapore.private_ip } output "module_output_seoul" { value = module.ec2_seoul.private_ip } 4 실행 : 프로바이더 구성을 테스트 cd 06-module-traning/multi_provider_for_module/ terraform init cat .terraform/modules/modules.json | jq // key라는 이름으로 싱가포르와 서울이 구분된다. # terraform apply -auto-approve terraform output terraform state list terraform state show module.ec2_seoul.data.aws_ami.default terraform state show module.ec2_singapore.data.aws_ami.default cat terraform.tfstate | grep module # graph 확인 terraform graph > graph.dot # aws cli로 ec2 확인 aws ec2 describe-instances --region ap-northeast-2 --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output text aws ec2 describe-instances --region ap-southeast-1 --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output text // 콘솔에서 확인 서울 리전에서 확인 싱가포르 리전에서 확인 # 실습 완료 후 리소스 삭제 terraform destroy -auto-approve <5> 모듈의 반복문 - count 사용 모듈내에서도 반복문을 사용할 수 있다. 1 디렉터리 생성 및 06-module-traning/module_loop_count/main.tf 파일 생성 2 mkdir -p 06-module-traning/module_loop_count/ 3 vi main.tf provider "aws" { region = "ap-northeast-2" } module "ec2_seoul" { count = 2 source = "../modules/terraform-aws-ec2" instance_type = "t3.small" } output "module_output" { value = module.ec2_seoul[*].private_ip } 4 실행 : 모듈의 반복문 테스트 cd 06-module-traning/module_loop_count/ terraform init cat .terraform/modules/modules.json | jq terraform apply -auto-approve 콘솔에서 ec2 생성 확인 terraform output terraform state list cat terraform.tfstate | grep module # graph 확인 terraform graph > graph.dot # aws cli로 ec2 확인 aws ec2 describe-instances --region ap-northeast-2 --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output text # 실습 완료 후 리소스 삭제 terraform destroy -auto-approve <6> 모듈의 반복문 - for each 문 모듈 묶음에 일관된 구성과 구조로 프로비저닝이 되는 경우라면 count가 간편한 방안이지만, 동일한 모듈 구성에 필요한 인수 값이 다르다면 for_each를 활용한다. 1 06-module-traning/module_loop_count/main.tf 파일 수정 cd 06-module-traning/module_loop_count 2 vi main.tf locals { env = { dev = { type = "t3.micro" name = "dev_ec2" } prod = { type = "t3.medium" name = "prod_ec2" } } } module "ec2_seoul" { for_each = local.env source = "../modules/terraform-aws-ec2" instance_type = each.value.type instance_name = each.value.name } output "module_output" { value = [ for k in module.ec2_seoul: k.private_ip ] } 3 # terraform plan terraform apply -auto-approve terraform output terraform state list cat terraform.tfstate | grep module # graph 확인 terraform graph > graph.dot # aws cli로 ec2 확인 aws ec2 describe-instances --region ap-northeast-2 --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output text # 실습 완료 후 리소스 삭제 terraform destroy -auto-approve <7> 모듈 소스 관리 1 https://developer.hashicorp.com/terraform/language/modules/sources https://developer.hashicorp.com/terraform/language/modules/sources#terraform-registry https://registry.terraform.io/?product_intent=terraform 2 테라폼 레지스트리 사용해보자. 테라폼 레지스트리 > 브라우저 모듈 사용할수 있다. https://registry.terraform.io/browse/modules https://registry.terraform.io/modules/terraform-aws-modules/vpc/aws/latest 3 aws vpc 모듈 실습 해보자~ https://registry.terraform.io/modules/terraform-aws-modules/vpc/aws/latest https://github.com/terraform-aws-modules/terraform-aws-vpc 예제 ) https://github.com/terraform-aws-modules/terraform-aws-vpc/tree/master/examples/simple mkdir work cd work git clone https://github.com/terraform-aws-modules/terraform-aws-vpc/ tree terraform-aws-vpc/examples -L 1 tree terraform-aws-vpc/examples -L 2 cd terraform-aws-vpc/examples/simple ls *.tf cat main.tf 4 코드 수정 : 서울 리전 변경, main.tf 파일 내용 확인 # 서울 리전 변경 grep 'eu-west-1' main.tf sed -i -e 's/eu-west-1/ap-northeast-2/g' main.tf # VPC CIDR 변경 grep '10.0.0.0' main.tf sed -i -e 's/10.0.0.0/10.10.0.0/g' main.tf # main.tf 파일 내용 확인 cat main.tf ... module "vpc" { source = "../../" name = local.name cidr = local.vpc_cidr azs = local.azs private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 4, k)] tags = local.tags } 5 # 모듈 확인 - 여기 내용을 참고한다. 자식모듈이다. tree ../../modules 6 terraform init cat .terraform/modules/modules.json| jq # 생성된 리소스들 확인해보자! terraform apply -auto-approve // vpc가 만들어진다!!!! terraform output // 아웃풋이 많다. 재활용하자!!! terraform state list 7 콘솔에서 VPC 확인하자!!! # 실습 완료 후 리소스 삭제 terraform destroy -auto-approve <8> 테라폼 레지스트리에 공개된 모듈을 사용하여 리소스 배포 1 - 깃의 원격 저장소로 널리 알려진 깃허브는 테라폼 구성에 대한 CI 용도로 사용할 수 있고, 저장된 구성을 테라폼 모듈의 소스로 선언할 수도 있다 - 6.3에서 사용한 06-module-traning/modules/terraform-aws-ec2/ 를 깃허브에 업로드하는 과정 1. 깃허브에 로그인 2. 새로운 깃허브 저장소 생성 [New repository] - Owner : 원하는 소유자 선택 - Repository name : 예시) **terraform-module-repo** - Public 선택 - Add .gitignore의 드롭박스에서 [Terraform]을 선택 3. 맨 아래 [Create repository] 클릭 4. 해당 저장소에 예시) ‘**terraform-aws-ec2**’ 디렉터리 생성 후 main.tf , variable.tf, output.tf 추가 후 업로드 2 디렉터리 생성 후 main.tf 파일 생성 mkdir module-source-mygithub 3 # main.tf provider "aws" { region = "ap-southeast-1" } module "ec2_seoul" { source = "github.com//terraform-module-repo/terraform-aws-ec2" instance_type = "t3.small" } 4 실행 # cd module-source-mygithub terraform init # 아래 디렉터리에 깃허브에 있던 파일이 다운로드 되어 있음을 확인 tree .terraform/modules # 배포 terraform apply -auto-approve terraform state list # 실습 완료 후 삭제 terraform destroy -auto-approve