ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Terraform Study 4주차
    Terraform 2023. 7. 29. 16:20

    도전과제 1 AWS DynamoDB/S3를 원격 저장소로 사용하는 실습을 따라해보세요!

    Terraform을 통한 리소스 배포를 혼자 하는것이 아닌 협업 하는 상황이라면 state파일을 local에서 관리하는 것이 아닌 원격에서 관리하는 작업이 필요하다. 이를 위해 AWS의 S3를 사용하는 방법과 Terraform Cloud를 사용하는 방법이 있으며 그 중 S3를 사용하는 방법에 대한 설명이다.
    S3에는 State파일을 저장할때 동시에 프로비저닝 하여 State파일이 꼬이는 상황을 막기 위해 S3뿐만 아니라 DynamoDB도 함께 사용해야 한다.

    resource "aws_s3_bucket" "tfstate" {
      bucket = "terraform_study"
    
      versioning {
        enabled = true
      }
    }
    resource "aws_dynamodb_table" "terraform_state_lock" {
      name         = "terraform-lock"
      hash_key     = "LockID"
      billing_mode = "PAY_PER_REQUEST"
    
      attribute {
        name = "LockID"
        type = "S"
      }
    }

    provider.tf

    terraform {
      required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "~> 5.0"
        }
      }
    
      backend "s3" {
        bucket         = "terraform_study"
        key            = "study/4week/terraform.tfstate"
        region         = "ap-northeast-2"
        encrypt        = true
        dynamodb_table = "terraform-lock"
      }
    }

    코드리뷰
    백엔드로 사용할 S3, DynamoDB를 생성하는 코드로 S3생성시 실수로 삭제하는 상황 및 변경을 파악하기 위해 버전관리를 사용하는것이 좋다.
    생성한 S3,DynamoDB를 백엔드로 사용하기 위한 설정은 provider.tf파일에 설정했으며 설정 내용을 보면 어떤 버킷의 어느 경로에 state파일을 저장하는지 설정했으며 dynamodb는 어떤것을 사용할지 설정함으로 써 백엔드로 사용할 수 있다. 또한 백엔드로 사용하기 위해 생성한 S3, DynamoDB는 Terraform으로 생성하더라고 Terraform으로 관리하지 않는것을 추천한다. Terraform 으로 관리 시 실수로 인해 변경되거나 삭제될 위험이 있다.
    더이상 state파일을 통해 관리하지 않으려면 terraform rm 을 통해 state 파일에서만 삭제할 수 있다.

    도전과제 2 각자 사용하기 편리한 리소스를 모듈화 해보고, 해당 모듈을 활용해서 반복 리소스들 배포해보세요!

    파일 구조

    구조는 위와 같으며 자세한 코드는 Github을 살펴보면 된다.
    vpc/main.tf

    resource "aws_vpc" "vpc" {
      cidr_block           = var.vpc_cidr
      enable_dns_hostnames = var.enable_dns_hostnames
      enable_dns_support   = var.enable_dns_support
    
      tags = merge(
        {
          Name = "${var.company}-${var.env}-vpc"
        }, var.tags
      )
    }
    output "vpc_id" {
      description = "created vpc id"
      value = aws_vpc.vpc.id
    }

    Subnets-Pub/main.tf

    resource "aws_subnet" "subnets" {
      count             = length(var.subnets)
      vpc_id            = var.vpc_id
      cidr_block        = var.subnets[count.index].cidr
      availability_zone = var.subnets[count.index].zone
    
      tags = merge({
        Name = "${var.company}-${var.env}-sbn-${var.subnets[count.index].name}"
      }, var.tags)
    }
    
    resource "aws_route_table" "rtb" {
      count  = var.single_nat_gateway ? 1 : length(aws_subnet.subnets)
      vpc_id = var.vpc_id
    
      tags = merge({
        Name = "${var.company}-${var.env}-${var.subnets[count.index].name}-rtb"
      }, var.tags)
    }
    
    resource "aws_route_table_association" "this" {
      count          = length(aws_subnet.subnets)
      subnet_id      = aws_subnet.subnets[count.index].id
      route_table_id = aws_route_table.rtb[var.single_nat_gateway ? 0 : count.index].id
    }

    Subnets-Pri/main.tf

    resource "aws_subnet" "subnets" {
      count             = length(var.subnets)
      vpc_id            = var.vpc_id
      cidr_block        = var.subnets[count.index].cidr
      availability_zone = var.subnets[count.index].zone
    
      tags = merge({
        Name = "${var.company}-${var.env}-sbn-${var.subnets[count.index].name}"
      }, var.tags)
    
    }
    
    resource "aws_internet_gateway" "igw" {
      vpc_id = var.vpc_id
    
      tags = merge({
        Name = "${var.company}-${var.env}-IGW"
      }, var.tags)
    }
    
    resource "aws_route_table" "rtb" {
      vpc_id = var.vpc_id
    
      route {
        cidr_block = "0.0.0.0/0"
        gateway_id = aws_internet_gateway.igw.id
      }
    
      tags = merge({
        Name = "${var.company}-${var.env}-PUB-RTB"
      }, var.tags)
    }
    
    resource "aws_route_table_association" "this" {
      count          = length(aws_subnet.subnets)
      subnet_id      = aws_subnet.subnets[count.index].id
      route_table_id = aws_route_table.rtb.id
    }

    main.tf

    module "vpc" {
      source = "./VPC"
    
      vpc_cidr             = var.vpc_cidr
      company              = var.company
      env                  = var.env
      enable_dns_hostnames = var.enable_dns_hostnames
      enable_dns_support   = var.enable_dns_support
      tags                 = var.tags
    }
    
    module "sbn_pub" {
      source = "./Subnets-Pub"
    
      company = var.company
      vpc_id  = module.vpc.vpc_id
      env     = var.env
      subnets = var.sbn_pub
      tags    = var.tags
    }
    
    module "sbn_pri" {
      source   = "./Subnets-Pri"
      for_each = var.sbn_pri
    
      company            = var.company
      env                = var.env
      vpc_id             = module.vpc.vpc_id
      single_nat_gateway = var.single_nat_gateway
      subnets            = var.sbn_pri[each.key]
      tags               = var.tags
    }

    코드리뷰
    간단한 VPC, Public Subnet, Private Subnet을 생성하는 코드로 각각의 기능을 모듈로 분리해 사용한 예시이다. 각 모듈간 값을 받아오기 위해선 output을 통해 값을 받아올 수 있으며 vpc쪽 코드를 보면 추후 서브넷에서 vpc의 id를 사용해야 하기 때문에 output으로 vpc.id를 사용했으며 subnet 모듈 호출 시 module.vpc.vpc_id로 output된 변수를 사용할 수 있다.
    프라이빗 서브넷의 경우 어떤 서브넷이 생길지 알 수 없기 때문에 범용성을 높이기 위하여 한 레이어의 서브넷만 생성하도록 모듈을 작성했으며 반복을 돌리기 위해 프라이빗 서브넷 변수를 map형태로 선언해 for_each를 통한 반복으로 서브넷을 생성 하도록 코드를 작성했다.

    'Terraform' 카테고리의 다른 글

    Terraform Cloud 활용하기 #2  (0) 2023.08.20
    Terraform Cloud 활용하기  (0) 2023.08.12
    Terraform Study 3주차  (0) 2023.07.22
    Terraform Study 2주차 도전 과제  (0) 2023.07.15
Designed by Tistory.