Terraform Study #1

4주 동안 Terraform Study에 참여하였고 이번 주에 중간 과제를 제출해야 한다.

어떤 주제로 진행을 할까 고민하였는데 지금까지 배웠던 내용들을 간략하게 정리하면서 가장 최근에 배운 기능인 모듈을 활용해서 각기 다른 환경에 리소들을 배포한 뒤 테스트하는 내용으로 결정했다.

실습 환경

랩탑 M1 Macbook Pro 10core 32GB RAM, macOS 12.6.1

VSCode, iTerm2, AWS

실습 내용

모듈을 사용하여 환경을 나누어(PRD, DEV) 리소스 배포 후 curl 테스트

Mac OS에서 Terraform을 설치할 때는 단순한 설치보다는 tfenv을 설치해서 버저닝 기능을 사용하면 좋다.

최신 버전인 1.3.4를 설치하여 사용했다.

– IAM User을 생성하여 권한 부여
IAM User로 생성한 계정의 Access 정보를 변수로 입력해놓으면 터미널을 사용할 때 편리하다.
export AWS_ACCESS_KEY_ID=””
export AWS_SECRET_ACCESS_KEY=””

export AWS_DEFAULT_REGION=ap-northeast-2

– 테라폼을 간단하게 구성할 경우 variables.tf, output.tf, main.tf 등을 기본으로 해서 간단하게 배포가 가능하다.

–  기본적인 명령어는 3가지만 우선 알면 된다.

terraform init && terraform plan && terraform apply -auto-approve

-auto-approve는 별다른 확인 절차 없이 바로 배포를 진행하겠다는 의미로 운영계에서는 가급적 삼가는 게 좋을 것 같다.

– variables.tf 을 활용할 때는 아래와 같이 사용한다.

– ubuntu 최신 버전을 사용하려면 아래와 같이 data 소스를 생성

data "aws_ami" "ubuntu" {
    most_recent = true

    filter {
        name   = "name"
        values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
    }

    filter {
        name   = "virtualization-type"
        values = ["hvm"]
    }

    owners = ["099720109477"] # Canonical
}

– output 사용해서 생성 된 EC2의 Public IP 등을 확인할 수 있다.

output "public_ip" {
  value       = aws_instance.example.public_ip
  description = "The public IP of the Instance"
}

– userdata을 통해 배포되는 인스턴스에 웹서비스 설치 및 간단한 html을 배포하여 사용할 수 있다.

스터디에서 사용한 간단한 예제는 다음과 같다.

  user_data = <<-EOF
              #!/bin/bash
              wget https://busybox.net/downloads/binaries/1.31.0-defconfig-multiarch-musl/busybox-x86_64
              mv busybox-x86_64 busybox
              chmod +x busybox
              RZAZ=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone-id)
              IID=$(curl 169.254.169.254/latest/meta-data/instance-id)
              LIP=$(curl 169.254.169.254/latest/meta-data/local-ipv4)
              echo "<h1>RegionAz($RZAZ) : Instance ID($IID) : Private IP($LIP) : Web Server</h1>" > index.html
              nohup ./busybox httpd -f -p 80 &
              EOF

– 아직 상태 관리에 대한 부분은 이해를 다 하지 못해서 이 부분은 천천히 따로 복습해봐야 할 것 같다.

resource "aws_s3_bucket" "prj_s3bucket" {
  bucket = "${var.prj_name}-tfstate"
}

# Enable versioning so you can see the full revision history of your state files
resource "aws_s3_bucket_versioning" "prj_s3bucket_versioning" {
  bucket = aws_s3_bucket.prj_s3bucket.id
  versioning_configuration {
    status = "Enabled"
  }
}

output "s3_bucket_arn" {
  value       = aws_s3_bucket.prj_s3bucket.arn
  description = "The ARN of the S3 bucket"
}

resource "aws_dynamodb_table" "prj_dynamodbtable" {
  name         = "tfme--locks"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}

output "dynamodb_table_name" {
  value       = aws_dynamodb_table.prj_dynamodbtable.name
  description = "The name of the DynamoDB table"
}

– 이번 과제의 구조는 아래와 같이 생성했다.

조금 아쉬운 점은 Modules의 경우 compute와 network로 폴더 구조화해서 하위에 ec2.tf, sg,tf 등 tf을 리소스 종류 별로 구분하여 생성하고 싶었는데 그렇게 진행하지 못한 점이다. 그렇게 진행하지 못한 이유는 Compute 쪽에서 Network 쪽의 리소스 정보를 받아와야 하는데 그러지 못함에 있었다. 아마 별도로 호출하는 방안이 있을 것 같은데 다음에 시도해볼 예정이다.

– 구조는 최대한 단순하게 작성했다.

ASG에 웹서버만 설치한 인스턴스를 배포하였다. DB을 연결하여 특정 데이터를 호출하는 페이지를 생성하고 싶었지만 Module을 적용하는 과정에서 시간이 많이 소요되어 해당 기능들을 적용하지는 못했다. 추후 해당 기능은 추가할 예정이다.

– ALB을 사용하였기 때문에 CURL 테스트 때 적용할 DNS 값을 호출하기 위해 output.tf에 alb dns을 호출할 수 있도록 했다.

– 리소스 이름을 관리하기 위해 prd, dev 환경에 따라 prj_name을 입력 받고 Module에서 “prj_name-리소스명” 방식으로 이름을 입력하게끔 하였다. 이렇게 하면 프로젝트 이름과 Env 값을 받아 tfstudy-prd가 기본값이 되고 그 뒤에 리소스 명(ex:subnet1)이 결합하여 tfstudy-prd-subnet1이라는 서브넷이 생성되게 된다.

  resource~~{
  tags = {
    Name = "${var.prj_name}-subnet1"
  }
  }
  
  module "midexam" {
  source = "../Modules"

  prj_name           = "tfstudy-prd"
  }

– 환경에 따라 max, min 인스턴스 숫자와 인스턴스 크기의 차이점을 두고 vpc, subnet의 cidr 값을 설정했다.

개발계와 운영계는 IP을 다르게 설정하였다. 추후 확장했을 때 VPN을 연결하여 IDC와 연동한다고 한다면 중복되는 IP로 인해 충돌이 날 수 있기 때문에 이 부분을 고려하여 환경 간 IP  차이를 두었다.

#Dev 환경
module "midexam" {
  source = "../Modules"

  prj_name           = "tfstudy-dev"
  bucket_name = "tfstudy-dev-tfstate"
  instance_type = "t2.micro"
  min_size      = 2
  max_size      = 3
  vpc_cidr  = "192.168.0.0/16"
  subnet1_cidr  = "192.168.0.0/24"
  subnet2_cidr  = "192.168.1.0/24"
}

#Prd 환경
module "midexam" {
  source = "../Modules"

  prj_name           = "tfstudy-prd"
  bucket_name = "tfstudy-prd-tfstate"
  instance_type = "m4.large"
  min_size      = 2
  max_size      = 10
  vpc_cidr  = "172.16.0.0/16"
  subnet1_cidr  = "172.16.0.0/24"
  subnet2_cidr  = "172.16.1.0/24"
}

– 처음 dev 환경에서 배포를 시작했을 때 여러 오류가 발생했었다. 대표적으로는 valiables.tf에서 값을 불러오는 것에서 충돌이 많았는데 중복되는 설정값 등이 있어서 이 부분을 정리했다. 대부분의 변수값은 Modules에서 받아올 수 있도록 했다.

– Modules 안에서만 불러오고 밖에서 참조할 필요가 없는 값의 경우 locals 을 통해 Modules 내부에서 처리하였다.

대표적으로, Security Group 생성 시에 사용하는 port, cidr, protocol에 활용하였다. 추후 locals에 넣을 수 있는 변수들이 어떤 게 있을지 조금 더 고민해봐야 할 것 같다.

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

– 배포 후 리소스 목록은 아래와 같다.

– 배포를 완료하고 curl 테스트를 완료한 화면은 아래와 같다.

위 화면이 운영계에서의 테스트고 아래가 개발계에서의 테스트이다.

둘 다 정상적으로 ALB을 통해 각 인스턴스로 트래픽이 분배되는 것을 확인할 수 있었다.

모듈을 통한 배포를 진행했기 때문에 각 환경에서는 환경에 맞는 변수와 아이템을 추가해주기만 하면 되어서 여러 번을 거친 작업을 하지 않아도 되는 부분은 충분히 장점으로 인식 됐다.

아쉬운 점은, 폴더를 도식화했을 때 그 각 폴더를 참조하기 위해 source 경로를 입력해주는 부분이 조금 불편했다. 이 부분을 쉽게 읽어올 수 있는 방법이 있으면 좋을 것 같다. (이미 있을 수도 있는데 내가 못 찾은 건지도..)

위에 진행을 하는 과정에서도 적었던 아쉬운 점이지만, 아직 테라폼에 대한 이해도가 부족해 Module을 제대로 사용하지 못한 점과 여러 리소스를 활용하지 못한 점이 아쉽다.

이 과제는 지우지 않고 계속 보완해가면서 활용할 수 있으면 좋을 것 같다.

여기까지 직접 테라폼으로 만들어보니 앞으로 업무에 적용하거나 개인 프로젝트를 할 때도 활용할 수 있을 것 같다는 생각이 든 게 가장 큰 수확이라고 생각한다.

남은 스터디 기간 동안 더 열심히 해서 조금 더 나은 결과물을 만들어야겠다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다