본문 바로가기

Terraform

[테라폼] State & Module

반응형

1. terraform.state 의 목적

terraform으로 코드로 작성하고 apply시 terraform.tfstae 파일이 생성되며 tfstate파일은 실제 인프라가 프로비저닝되면서 생성된 리소스등의 정보를 기록한 파일이다.

terraform 코드를 수정하고 다시 apply하면 작성한 terraform code, tfstate, 실제 인프라의 상태를 비교해서 인프라가 프로비저닝되거나 destroy된다.

  • 팀 단위 테라폼 코드 운영시 관리
    • 팀 단위에서 테라폼 운영 시 각 팀원이 동일한 테라폼 state 파일 관리 
    • 동일한 tfstate 관리를 위한 지원되는 백앤드 : AWS S3, Azure Blob Storage, Google Cloud Storage, Consul, Postgres database 등 (https://developer.hashicorp.com/terraform/language/settings/backends/local)
    • terraform cloud 또는 terraform enterprise를 통해 vcs(github,gitlab,bitbucket 등) 연동하여 remote 방식으로 관리

Challenge1

AWS DynamoDB / S3를 원격 저장소로 tfstate 관리 실습

코드 참고 : https://github.com/junho102/Terraform-Study/tree/main/Week4/challenge1

# S3 생성
resource "aws_s3_bucket" "s3_bucket" {
  bucket = "${var.name}-t101study-tfstate"
}

# 상태 파일의 전체 개정 내역을 볼 수 있도록 버전 관리를 활성화
resource "aws_s3_bucket_versioning" "s3bucket_versioning" {
  bucket = aws_s3_bucket.s3_bucket.id
  versioning_configuration {
    status = "Enabled"
  }
}

# DynamoDB 생성
resource "aws_dynamodb_table" "dynamodb_table" {
  name         = "terraform-locks"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}
terraform {
  backend "s3" {
    bucket = "ljh-t101study-tfstate"
    key    = "dev/terraform.tfstate"
    region = "ap-northeast-2"
    dynamodb_table = "terraform-locks"
    # encrypt        = true
  }
}

※ 코드설명

- 백앤드(원격 저장소)로 사용할 S3와 DynamoDB를 생성

- 새롭게 배포할 테라폼 코드를 준비하고 terraform block에 backend로 s3로 설정하여 원격 저장소로 사용

 

※ 결과 확인

 

 

2.  Module

테라폼에서 module이란 재사용성을 위해 리소스를 하나의 묶음으로 만들어 관리하는 방법

module code를 작성하였다면 module block으로 Module을 불러와 사용 가능

terrarom 명령어를 실행하는 작업 경로를 보통 root module이라 하며, root module에서 사용하는 module을 child module이라 한다.

 

Challenge2

각자 사용하기 편리한 리소스를 모듈화 해보고, 해당 모듈을 활용해서 반복 리소스들을 배포

코드 참고 : https://github.com/junho102/Terraform-Study/tree/main/Week4/challenge2

1) vpc, subnet, route, gateway 를 각각 child module 작성 (하위 코드 설명에서는 vpc와 gateway만 설명으로 나머지 코드는 코드참고링크를 참고 부탁드립니다)

 

1-1) vpc module 작성

# vpc
resource "aws_vpc" "vpc" {
  cidr_block           = local.vpc_cidr
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "${local.env}-vpc"
  }
}
output "vpc_id" {
  value = aws_vpc.vpc.id
}
variable "env" {}

variable "vpc_cidr" {}

locals {
  vpc_cidr = var.vpc_cidr
  env      = var.env
}

 

1-2) gateway module 작성

# Internet GW
resource "aws_internet_gateway" "igw" {
  vpc_id = local.vpc_id
  tags = {
    Name = "${local.env}-igw"
  }
}

# NAT GW EIP
resource "aws_eip" "natgw_ip" {
  domain = "vpc"
}

# NAT GW
resource "aws_nat_gateway" "natgw_az1" {
  allocation_id = aws_eip.natgw_ip.id
  subnet_id     = local.pub_subnet[0].id

  tags = {
    Name = "${local.env}-natgw"
  }

  depends_on = [aws_internet_gateway.igw]
}
output "igw" {
  value = aws_internet_gateway.igw
}

output "natgw_az1" {
  value = aws_nat_gateway.natgw_az1
}
variable "env" {}

variable "pub_subnet" {}

variable "vpc_id" {

}

locals {
  env        = var.env
  pub_subnet = var.pub_subnet
  vpc_id     = var.vpc_id
}

 

2) terraform 명령어를 실행할 root module 생성

module "vpc" {
  source   = "../modules/vpc"
  vpc_cidr = local.vpc_cidr
  env      = local.env
}

module "subnets" {
  source = "../modules/subnets"
  vpc_id = module.vpc.vpc_id

  env      = local.env
  pub_cidr = local.pub_cidr
  pri_cidr = local.pri_cidr
}

module "gateway" {
  source     = "../modules/gateway"
  vpc_id     = module.vpc.vpc_id
  pub_subnet = module.subnets.pub_subnet

  env = local.env
}

module "routingTable" {
  source     = "../modules/routetables"
  vpc_id     = module.vpc.vpc_id
  igw        = module.gateway.igw
  natgw_az1  = module.gateway.natgw_az1
  pub_subnet = module.subnets.pub_subnet
  pri_subnet = module.subnets.pri_subnet

  env = local.env
}
variable "env" {
  description = "environment"
  default     = "dev"
}

### cidr valiable ###
#####################
variable "vpc_cidr" {
  description = "VPC CIDR BLOCK : x.x.x.x/x"
  default     = "192.168.0.0/16"
}

variable "pub_cidr" {
  description = "pub CIDR BLOCK : x.x.x.x/x"
  type        = list(string)
  default     = ["192.168.1.0/24", "192.168.2.0/24"]
}

variable "pri_cidr" {
  description = "pri CIDR BLOCK : x.x.x.x/x"
  type        = list(string)
  default     = ["192.168.3.0/24", "192.168.4.0/24"]
}

locals {
  env      = var.env
  vpc_cidr = var.vpc_cidr
  pub_cidr = var.pub_cidr
  pri_cidr = var.pri_cidr
}

 

※ 코드설명

- child module에서는 variable들을 빈값으로 생성

- child module간에 필요한 값을 호출하기 위해 output block생성

- root module에서 vpc의 cidr, 필요한 subnet의 cidr값을 variable로 생성

- root module에서 module block을 활용하여 필요한 variable들의 값을 root module에서 생성한 variable 또는 다른 child module의 output 값으로 작성하여 코드 실행

 

 

Challenge3

테라폼 레지스트리에 공개된 모듈을 사용하여 리소스들을 배포

코드 참고 : https://github.com/junho102/Terraform-Study/tree/main/Week4/challenge3

 

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.1.0"

  name = "my-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["ap-northeast-2a", "ap-northeast-2b", "ap-northeast-2c"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

  enable_nat_gateway = true
  enable_vpn_gateway = false

  tags = {
    Terraform = "true"
    Environment = "dev"
  }
}

module "security-group" {
  source  = "terraform-aws-modules/security-group/aws"
  version = "5.1.0"

  name        = "web-server"
  description = "Security group for web-server with HTTP ports open within VPC"
  vpc_id      = module.vpc.vpc_id

  ingress_cidr_blocks = ["0.0.0.0/0"]
}

module "ec2-instance" {
  source  = "terraform-aws-modules/ec2-instance/aws"
  version = "5.2.1"

  for_each = toset(["one", "two", "three"])

  name = "instance-${each.key}"

  instance_type          = "t2.micro"
  key_name               = "test"
  monitoring             = true
  vpc_security_group_ids = ["${module.security-group.security_group_id}"]
  subnet_id              = "${module.vpc.public_subnets[0]}"

  tags = {
    Terraform   = "true"
    Environment = "dev"
  }
}

※ 코드설명

- vpc 공식 모듈을 source를 활용하여 vpc를 생성

- security group 공식 모듈 source를 활용하여 SG 생성하되, vpc_id값을 vpc module에서 id값을 가져와서 생성된 vpc 안에 SG 생성

- ec2 공식 모듈을 source를 활용하여 instance를 생성하되, vpc모듈에서 생성된 public subnet에 인스턴스를 생성하며 for_each를 활용하여 ec2를 3대 설치하며 sg는 module.security-group에서 id를 가져와 sg 적용

 

Challenge4

자신의 깃허브를 모듈 소스로 설정하고 테라폼 클라우드에 module Registry에 등록하여 리소스를 배포

Terraform Cloud에서는 모듈을 사용하기위해 모듈 디렉터리 이름 형식을 다음과 같이 지정하여야 합니다.

(terraform-<프로바이더이름>-<모듈 이름>)

참고 코드 : https://github.com/junho102/Terraform-Study/tree/main/Week4/challenge4

 

1) vpc 모듈로 사용할 코드를 깃허브에 등록 및 태그 설정

resource "aws_vpc" "vpc" {
  cidr_block = local.vpc_cidr
  enable_dns_support = true
  enable_dns_hostnames = true

  tags = {
    Name =  "${local.company_name}-${local.server_env}-VPC-test"
  }
}

resource "aws_vpc_ipv4_cidr_block_association" "secondary_cidr" {
  vpc_id = aws_vpc.vpc.id
  cidr_block = "100.64.0.0/16"
  depends_on = [
    aws_vpc.vpc
  ]
}

resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.vpc.id
  tags = { 
    Name = "${local.company_name}-${local.server_env}-IG" 
  }
}

 

2) terraform cloud에 VCS(github) 연동

- 먼저 terraform cloud에 접속하여 Registry -> Publish -> Module을 선택합니다.

 

- 연결할 VCS를 Github를 선택하여 연동합니다.

 

- 작성한 VPC module을 Registry에 등록할 것이기 때문에 생성해둔 git repo를 선택합니다.

 

- 등록한 repo를 확인 후 Publish module을 클릭합니다.

 

- 등록확인

 

 

3) terraform login 진행

terraform cloud의 Registry에 등록된 module을 사용하기 위해 terraform cloud의 token을 발급받습니다.

 

- terraform cloud에 접속하여 User Setting -> Tokens -> Create an API token을 선택하여 token을 발급

 

 

- 발급받은 토큰으로 terraform login 진행

 

Token for app.terraform.io:
  Enter a value: {해당 부분에 token을 입력하면 다음과 같은 화면으로 로그인 성공을 확인 할 수 있습니다.)

terraform login 
Terraform will request an API token for app.terraform.io using your browser.

If login is successful, Terraform will store the token in plain text in
the following file for use by subsequent commands:
    /Users/mzc01-lwnsgh/.terraform.d/credentials.tfrc.json

Do you want to proceed?
  Only 'yes' will be accepted to confirm.

  Enter a value: yes


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

Terraform must now open a web browser to the tokens page for app.terraform.io.

If a browser does not open this automatically, open the following URL to proceed:
    https://app.terraform.io/app/settings/tokens?source=terraform-login


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

Generate a token using your browser, and copy-paste it into this prompt.

Terraform will store the token in plain text in the following file
for use by subsequent commands:
    /Users/mzc01-lwnsgh/.terraform.d/credentials.tfrc.json

Token for app.terraform.io:
  Enter a value: 


Retrieved token for user jh_lee


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

                                          -                                
                                          -----                           -
                                          ---------                      --
                                          ---------  -                -----
                                           ---------  ------        -------
                                             -------  ---------  ----------
                                                ----  ---------- ----------
                                                  --  ---------- ----------
   Welcome to Terraform Cloud!                     -  ---------- -------
                                                      ---  ----- ---
   Documentation: terraform.io/docs/cloud             --------   -
                                                      ----------
                                                      ----------
                                                       ---------
                                                           -----
                                                               -


   New to TFC? Follow these steps to instantly apply an example configuration:

   $ git clone https://github.com/hashicorp/tfc-getting-started.git
   $ cd tfc-getting-started
   $ scripts/setup.sh

 

4) terraform init & apply

Terraform Cloud에 등록된 모듈을 사용하는 코드는 다음과 같습니다.

module "vpc" {
  source  = "app.terraform.io/jh-proj/vpc/aws"
  version = "1.0.0"

  vpc_cidr     = "10.0.0.0/16"
  company_name = "mzc"
  server_env   = "dev"
}

 

terraform init을 하게되면 다음과 같이 terraform cloud에서 모듈을 Initializing하는 것을 확인할 수 있으면 코드를 사용할 수 있습니다.

terraform init 

Initializing the backend...
Initializing modules...
Downloading app.terraform.io/jh-proj/vpc/aws 1.0.0 for vpc...
- vpc in .terraform/modules/vpc

Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v5.10.0...
- Installed hashicorp/aws v5.10.0 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
반응형