728x90
반응형
SMALL
SMALL

저번 시간에는 Terraform Registry에 있는 모듈을 가져다가 사용하는 것 까지는 해봤다. 이번에는 내가 스스로 모듈을 만들어서 그 모듈을 사용해보자.

 

Directory path

우선, 나의 모듈을 가지고 사용하는 테라폼 소스 코드의 구조는 다음과 같다.

 

account 라는 폴더가 하나의 모듈로서 기능을 할 것이고 그 모듈을 루트 디렉토리에 있는 main.tf 에서 사용할 것이다. 그럼 account 디렉토리에 각각의 파일을 하나씩 알아보자.

 

참고로 파일명은 정해져 있는게 아니라 관습적으로 사용되는 명칭이다. 그니까 꼭 저것을 따르지 않아도 되지만 관습이니 안 따라야할 이유도 없다.

 

versions.tf

이 파일은 테라폼과 프로바이더의 버전을 명시한 파일이다. 소스 코드는 다음과 같다.

terraform {
  required_version = ">= 0.15"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 3.45"
    }
  }
}

 

variables.tf

이 파일은 모듈에서 사용하는 변수를 정의한 파일이다. 소스 코드는 다음과 같다.

variable "name" {
  description = "The name for the AWS account. Used for the account alias."
  type        = string
}

variable "password_policy" {
  description = "Password Policy for the AWS account."
  type = object({
    minimum_password_length        = number
    require_numbers                = bool
    require_symbols                = bool
    require_lowercase_characters   = bool
    require_uppercase_characters   = bool
    allow_users_to_change_password = bool
    hard_expiry                    = bool
    max_password_age               = number
    password_reuse_prevention      = number
  })
  default = {
    minimum_password_length        = 8
    require_numbers                = true
    require_symbols                = true
    require_lowercase_characters   = true
    require_uppercase_characters   = true
    allow_users_to_change_password = true
    hard_expiry                    = false
    max_password_age               = 0
    password_reuse_prevention      = 0
  }
}

 

outputs.tf

이 파일은 모듈에서 만들어내는 outputs을 정의한 파일이다. 특정 테라폼 소스에서 어떤 모듈을 가져다가 사용할 때 모듈이 내뱉는 attribute를 참조해야 하는 경우가 많은데 그 참조할 수 있는 값들은 모듈에서 뱉어내는 output 뿐이다. 그래서 적절한 output이 중요하다.

소스 코드는 다음과 같다.

output "id" {
  description = "The AWS Account ID"
  value       = data.aws_caller_identity.this.account_id
}

output "name" {
  description = "Name of the AWS account. The account alias."
  value       = aws_iam_account_alias.this.account_alias
}

output "signin_url" {
  description = "The URL to signin for the AWS account."
  value       = "https://${var.name}.signin.aws.amazon.com/console"
}

output "password_policy" {
  description = "Password Policy for the AWS Account. `expire_passwords` indicates whether passwords in the account expire. Returns `true` if `max_password_age` contains a value greater than 0."
  value       = aws_iam_account_password_policy.this
}

 

main.tf

모듈의 main.tf 파일이다. 소스 코드는 다음과 같다.

data "aws_caller_identity" "this" {}

resource "aws_iam_account_alias" "this" {
  account_alias = var.name
}

resource "aws_iam_account_password_policy" "this" {
  minimum_password_length        = var.password_policy.minimum_password_length
  require_numbers                = var.password_policy.require_numbers
  require_symbols                = var.password_policy.require_symbols
  require_lowercase_characters   = var.password_policy.require_lowercase_characters
  require_uppercase_characters   = var.password_policy.require_uppercase_characters
  allow_users_to_change_password = var.password_policy.allow_users_to_change_password
  hard_expiry                    = var.password_policy.hard_expiry
  max_password_age               = var.password_policy.max_password_age
  password_reuse_prevention      = var.password_policy.password_reuse_prevention
}

 

README.md

이 파일은 이 모듈이 어떤 형식으로 만들어지고 무엇이 필수값이고 아닌지 또는 버전은 어떻게 되는지 이 모듈의 outputs은 무엇인지를 명시한 파일이다. 그리고 이 파일은 직접 작성한 게 아니고 terraform-docs 라는 툴을 사용했다.

 

terraform-docs

Generate Terraform modules documentation in various formats

terraform-docs.io

이 녀석을 다운받고 시키는 대로 하면 다음과 같이 날 위해 README 파일을 만들어준다.

$ terraform-docs markdown path/to/module

## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 0.15 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 3.45 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 3.45 |

## Modules

No modules.

## Resources

| Name | Type |
|------|------|
| [aws_iam_account_alias.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_account_alias) | resource |
| [aws_iam_account_password_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_account_password_policy) | resource |
| [aws_caller_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_name"></a> [name](#input\_name) | The name for the AWS account. Used for the account alias. | `string` | n/a | yes |
| <a name="input_password_policy"></a> [password\_policy](#input\_password\_policy) | Password Policy for the AWS account. | <pre>object({<br>    minimum_password_length        = number<br>    require_numbers                = bool<br>    require_symbols                = bool<br>    require_lowercase_characters   = bool<br>    require_uppercase_characters   = bool<br>    allow_users_to_change_password = bool<br>    hard_expiry                    = bool<br>    max_password_age               = number<br>    password_reuse_prevention      = number<br>  })</pre> | <pre>{<br>  "allow_users_to_change_password": true,<br>  "hard_expiry": false,<br>  "max_password_age": 0,<br>  "minimum_password_length": 8,<br>  "password_reuse_prevention": 0,<br>  "require_lowercase_characters": true,<br>  "require_numbers": true,<br>  "require_symbols": true,<br>  "require_uppercase_characters": true<br>}</pre> | no |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_id"></a> [id](#output\_id) | The AWS Account ID |
| <a name="output_name"></a> [name](#output\_name) | Name of the AWS account. The account alias. |
| <a name="output_password_policy"></a> [password\_policy](#output\_password\_policy) | Password Policy for the AWS Account. `expire_passwords` indicates whether passwords in the account expire. Returns `true` if `max_password_age` contains a value greater than 0. |
| <a name="output_signin_url"></a> [signin\_url](#output\_signin\_url) | The URL to signin for the AWS account. |

 

그리고 이제 모듈을 가져다가 사용하는 루트 디렉토리에 있는 main.tf 파일을 보자.

 

main.tf

하단 소스 코드를 보자.

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

module "account" {
  source = "./account"

  name = "cwchoiit-terraform"
  password_policy = {
    minimum_password_length        = 8
    require_numbers                = true
    require_symbols                = true
    require_lowercase_characters   = true
    require_uppercase_characters   = true
    allow_users_to_change_password = true
    hard_expiry                    = false
    max_password_age               = 0
    password_reuse_prevention      = 0
  }
}

output "id" {
  value = module.account.id
}

output "account_name" {
  value = module.account.name
}

output "signin_url" {
  value = module.account.signin_url
}

output "account_password_policy" {
  value = module.account.password_policy
}

 

저번에는 Registry에 있는 module을 사용할 때 source 형태가 저런식이 아니었다. 그리고 이건 로컬에 있는 모듈을 사용할 때 쓰는 source 형식이다. 이 두 차이점을 잘 알아둬야한다.

 

그리고 account 라는 모듈이 필요한 속성인 name, password_policy 값을 작성한다.

output은 모듈이 주는 output을 그대로 가져다가 사용했다.

 

이 상태에서 Apply를 해보자. 다음과 같이 Apply는 정상적으로 됐다. 

 

그럼 내 계정의 Alias가 저렇게 변경됐는지 확인해보자. 다음은 그 결과이다.

 

 

결론

이렇게 로컬에서 모듈을 직접 만들어보고 사용해보았다. 모듈은 이런식으로 로컬에서도 사용가능하고 Registry에서 가져다가 사용하는 것도 된다. 그리고 한 가지 더 유용한 `terraform-docs`도 사용해봤다.

 

728x90
반응형
LIST

'IaC(Infrastructure as Code)' 카테고리의 다른 글

Terraform Provisioner/EC2 Userdata  (2) 2024.03.11
terraform_remote_state  (0) 2024.03.10
Terraform Cloud  (0) 2024.03.10
Terraform Workspace  (0) 2024.03.08
Terraform Commands (taint / untaint)  (0) 2024.03.08
728x90
반응형
SMALL
SMALL

 

목표

이번에는 모듈을 사용해서 인프라를 구축해보자. VPC, Subnet, Route Tables 등등을 모듈로 정의하고 가져다가 사용해서 인프라를 구축한다. 

 

Module

모듈은 쉽게 말해서, 어떤 특정 컴포넌트(예: VPC)를 만들기 위해 필요한 정보들을 미리 구현해놓은 누군가(또는 나의)의 것을 가져다가 사용한다고 생각하면 된다. 개발할 때 패키지나 모듈을 다운받아서 가져다가 쓰는 원리랑 동일하다.

 

그래서 테라폼 레지스트리에서 올려놓은 여러 모듈 중 하나를 가져다가 사용해서 인프라를 구성해보자.

 

테라폼 레지스트리에 등록된 모듈 중 이 모듈을 사용할 것이다.

 

Terraform Registry

 

registry.terraform.io

 

여기 보면 AWS 네트워크 관련된 모듈들이 있다.

 

Terraform Registry

 

registry.terraform.io

 

 

main.tf

다음과 같이 main.tf 파일을 만든다. 하나하나 뜯어보자.

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

module "vpc" {
	source = "tedilabs/network/aws//modules/vpc"
	version = "0.24.0"

	name = "tf-vpc"
	cidr_block = "10.0.0.0/16"

	internet_gateway_enabled = true

	dns_hostnames_enabled = true
	dns_support_enabled = true

	tags = {}
}

module "subnet_group__public" {
	source = "tedilabs/network/aws//modules/subnet-group"
	version = "0.24.0"

	name = "${module.vpc.name}-public"
	vpc_id = module.vpc.id
	map_public_ip_on_launch = true

	subnets = {
		"${module.vpc.name}-public-001/az1" = {
			cidr_block = "10.0.0.0/24"
			availability_zone_id = "apne2-az1"
		}
		"${module.vpc.name}-public-002/az2" = {
			cidr_block = "10.0.1.0/24"
			availability_zone_id = "apne2-az2"
		}
	}
	
	tags = {}
}

module "subnet_group__private" {
	source = "tedilabs/network/aws//modules/subnet-group"
	version = "0.24.0"

	name = "${module.vpc.name}-private"
	vpc_id = module.vpc.id
	map_public_ip_on_launch = false

	subnets = {
		 "${module.vpc.name}-private-001/az1" = {
       cidr_block = "10.0.10.0/24"
 	     availability_zone_id = "apne2-az1"
      }
      "${module.vpc.name}-public-002/az2" = {
        cidr_block = "10.0.11.0/24"
        availability_zone_id = "apne2-az2"
      }	
	}

	tags = {}
}

 

 

VPC 모듈 

module "vpc" {
	source = "tedilabs/network/aws//modules/vpc"
	version = "0.24.0"

	name = "tf-vpc"
	cidr_block = "10.0.0.0/16"

	internet_gateway_enabled = true

	dns_hostnames_enabled = true
	dns_support_enabled = true

	tags = {}
}

 

우선 모듈을 작성할 때 source와 version을 작성해줘야 하는데, source는 이 모듈이 Local, Terraform Registry, Github 등 어디서 가져오냐에 따라 작성 방식이 살짝 다르다. 나의 경우 Terraform Registry에서 가져왔기 때문에 저렇게 source, version을 명시해줘야 한다. 이 내용은 다음 링크에서 자세히 확인이 가능하다.

 

Module Sources | Terraform | HashiCorp Developer

The source argument tells Terraform where to find child modules's configurations in locations like GitHub, the Terraform Registry, Bitbucket, Git, Mercurial, S3, and GCS.

developer.hashicorp.com

 

그리고 이제 다음 name, cidr_block, internet_gateway_enabled 등등은 이 모듈을 제공하는 제공자가 작성하라고 명시한 값이다. 이는 당연히 해당 모듈에 대한 문서에 나와있어야 하고 그것을 가져다가 사용할 뿐이다.

 

Subnet Group 모듈

module "subnet_group__public" {
	source = "tedilabs/network/aws//modules/subnet-group"
	version = "0.24.0"

	name = "${module.vpc.name}-public"
	vpc_id = module.vpc.id
	map_public_ip_on_launch = true

	subnets = {
		"${module.vpc.name}-public-001/az1" = {
			cidr_block = "10.0.0.0/24"
			availability_zone_id = "apne2-az1"
		}
		"${module.vpc.name}-public-002/az2" = {
			cidr_block = "10.0.1.0/24"
			availability_zone_id = "apne2-az2"
		}
	}
	
	tags = {}
}

module "subnet_group__private" {
	source = "tedilabs/network/aws//modules/subnet-group"
	version = "0.24.0"

	name = "${module.vpc.name}-private"
	vpc_id = module.vpc.id
	map_public_ip_on_launch = false

	subnets = {
		 "${module.vpc.name}-private-001/az1" = {
       cidr_block = "10.0.10.0/24"
 	     availability_zone_id = "apne2-az1"
      }
      "${module.vpc.name}-public-002/az2" = {
        cidr_block = "10.0.11.0/24"
        availability_zone_id = "apne2-az2"
      }	
	}

	tags = {}
}

 

 

이렇게 main.tf 파일을 만들고 이 파일을 init - apply 해보자.

 

이러한 결과가 나온다. 잘 만들어졌는지 AWS Console에서 확인해보자.

 

 

결론

작성한 대로, VPC와 Subnet들이 생성됐음을 확인할 수 있다. 이렇게 모듈을 사용해서 Resources를 하나하나 만들어내는게 아니라 원하

는 모듈 하나를 가져와서 그 모듈이 제공하는 리소스를 가져다가 사용할 수도 있다. 모듈이 주는 장점은 재사용성을 높인다는 것이다. 만약 VPC를 만들어 내려고 할 때마다 VPC Resource를 직접 작성해서 만들 수도 있겠지만, 같은 구성 같은 환경이라면 하나의 모듈을 만들어서 그것을 여러번 사용하는게 좀 더 효율적이지 않을까.

728x90
반응형
LIST

'IaC(Infrastructure as Code)' 카테고리의 다른 글

AWS + Terraform (Conditions)  (0) 2024.03.07
AWS + Terraform (For-Each)  (0) 2024.03.06
AWS + Terraform  (2) 2024.03.05
Terraform 소개 및 간단하게 다루어보기  (0) 2024.03.05
패커(Packer), Ansible 설치 및 설정  (0) 2024.03.05

+ Recent posts