4 분 소요

서론

학생 수준에서 진행하는 프로젝트의 인프라 구조는 되게 정형화되어 있는 것 같습니다. 학생은 만 원도 정말 비싼 가격이기 때문에 AWS 서비스에 과금을 하기에는 상당한 부담감이 있습니다. 그래서 AWS의 프리티어 서비스를 굉장히 많이 사용하고 있는데, 웹 애플리케이션의 3 Tier를 구성할 때 Front는 AWS Cloud Front, Back은 AWS EC2에 도커 컨테이너로 데이터베이스와 WAS를 올립니다. 실제 제가 학교에서 진행하고 있는 대부분의 프로젝트의 인프라 구조는 Cloud Front, EC2, ECR을 사용하고 가끔 API Gateway를 사용하곤 있습니다.

최근 클라우드 컴퓨팅 텀 프로젝트를 진행하게 되었는데, 과금을 하기 싫어 똑같은 인프라 구조로 프로비저닝을 준비하고 있습니다. 제 개인 블로그에 EC2 생성하는 방법을 정리해두긴 했는데, GUI로 생성하는 과정은 매우 번거롭고 지겹고, 재사용성이 너무 떨어집니다. 이러한 이유로 Terraform 도입을 생각했고, 공부하고 있습니다.

클라우드 컴퓨팅 텀프로젝트를 위해서 Terraform을 이용한 코드를 작성하고 있는데, 코드를 작성하면서 느낀 의문점에 대해서 알아보겠습니다. 또, 오늘 인프라 스터디를 진행하면서 선배님들의 생각을 듣고 추가 자료 조사를 한 후 Terraform을 어떻게 바라보고 있는지 정리하고 글을 마무리 하겠습니다.

테라폼은 언어에 대한 자세한 학습보다 재사용성을 위한 디렉토리 구조를 생각해야 한다.

테라폼 언어는 굉장히 쉽습니다. Java, Python과 C언어 보다 훨씬 러닝 커브가 적고, 애초에 언어 자체가 최소한의 기능만을 제공합니다. 간단한 문법에 대한 내용은 Terraform - IAM 자동화 블로그 글에 정리되어 있습니다. 제가 처음 테라폼을 공부하고 기능에 대해 생각했을 때 테라폼은 오토스케일링과 서버 프로비저닝을 공장처럼 찍어내는 툴이라고 생각했습니다. 공장처럼 찍어내기 위해서는 재사용성이 높게 코드를 작성해야 하는데, 어떻게 해야 좋은 구조도를 가질 수 있는지에 대한 레퍼런스는 많이 없었습니다.

찾은 레퍼런스는 DevOps팀의 Terraform 모험terraform-best-practice 두 개 뿐이였습니다.

Kurly에서 작성한 테라폼 구조는 terraform best practice를 보고 시작해서, 두 구조도는 매우 비슷합니다. 차이점은 Kurly 팀은 env 라는 디렉토리 안에서 실제 프로비저닝 되는 디렉토리를 구성했고, terraform 공식 문서는 env 디렉토리 없이 바로 프로비저닝 되는 디렉토리를 두었습니다. 그래서 크게 env 디렉토리(이하, dir)와 modules dir로 나눠볼 수 있습니다.

moduels dir

modules dir에는 IAM, EC2, S3 등 실제 AWS Serivce의 이름으로 dir 구조를 짰습니다. 컬리 팀은 iam, rds 등이 있고, 제가 작성한 코드에는 iam, ec2, key 등이 있습니다. 이 하나의 module에는 main.tf, output.tf, variables.tf, versions.tf가 있습니다. 관례적으로 보면 main.tf에는 실제 프로비저닝 되는 resource를 정의합니다.

# main.tf

# Create User

resource "aws_iam_user" "admin_user" {
  name = var.admin_user_name
}

# Attach group policy

## admin
resource "aws_iam_group_policy_attachment" "admin_full_access" {
  group      = aws_iam_group.admin_group.name
  policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}

# Add user to group

resource "aws_iam_group_membership" "admin_group_membership" {
  name = var.admin_group_name

  users = [
    aws_iam_user.admin_user.name
   ]

   group = aws_iam_group.admin_group.name
}

output.tf에는 프로비저닝 후 생성된 자원을 추출하고, variables.tf는 변수를 선언하는 곳입니다.

# variables.tf

# User name

variable "admin_user_name" {
  type = string
  default = "admin_user"
  description = "AWS IAM AdminFullAccess 권한의 그룹에 속한 User의 이름"
}

# Group name

variable "admin_group_name" {
  type = string
  default = "admin_group"
  description = "AWS IAM Admin 권한을 가진 Group의 이름"
}

terraform.tfvars는 variable에서 정의한 변수에 맞는 값을 입력하는 곳 입니다.

admin_group_name = "ggang9_admin"

env dir

env dir도 modules dir 과 동일한 구조를 가지고 있습니다. 다만 main.tf에서 resource를 사용하는 것이 아니라 module(여기서 말하는 module은 dir의 modules가 아니라 테라폼 문법의 module을 의미합니다)을 사용합니다. Terraform을 사용해서 리소스를 공장처럼 찍어내기 위해서는 module을 정말 잘 사용해야 한다고 하는데, resource와 module의 차이점을 아직 잘 모르겠습니다.

그나마 머리 속에서 정리한 내용은 resource는 자바 언어에서 class이고, modules는 tfvars에 정의된 variable을 토대로 class의 인스턴스를 찍어내는 것이다 정도로 정리했습니다.

이정도로 정리하고 다시 Kerly의 디렉토리 구조도를 살펴봤을 때 조금 이해가 가기 시작했습니다. modules dir 밑에 .tfvars가 없는 이유가 resource(자바의 class)를 정의할 때는 구체적인 이름을 variable로 설정할 필요가 없고, env dir 밑에는 .tfvars가 있는 이유가 실제 인스턴스(리소스)를 찍어내기 위해서는 구체저인 변수 이름을 지정해 줘야 하기 때문입니다. 글을 작성한 지금 best practice의 dir 구조가 조금 이해되기 시작했습니다.

Terraform은 오토스케일링을 위한 Tool은 아닌 것 같다

[우아콘 2020] 배달의민족 마이크로서비스 여행기에서 “트래픽이 많을 경우 오토스케일링을 통해 해결했다”고 말씀을 해 주셨는데, 이 한마디에 너무 많은 과정이 생략되었습니다. 그래서 혼자 어떻게 하면 테라폼을 사용해서 오토스케일링을 할 수 있을까 고민을 해 본 결과는 아래와 같습니다.

모니터링으로 서버의 자원을 확인함 -> 리로스의 임계점이 넘어가고 지속되는 경우 -> Jenkins + Terraform으로 프로비저닝 -> 마스터 노드에 연결 -> 파드 생성

위의 플로우로 오토스케일링을 할 수 있지 않을까 생각을 했습니다. 제 뇌피셜이 맞는지 실무에서는 어떻게 하는지 궁금해서 선배님께 여쭤보니, 노드에 연결하는 시간이 길기 때문에 위의 방식은 조금 힘들고, 이미 놀고 있는 서버가 많다고 말씀을 해 주셨습니다. 스터디가 끝나고, 다시 한번 마이크로서비스 여행기를 보는데, 아래의 같이 서버 100대를 깔고 시작하는 모습을 확인할 수 있었습니다. 클라우드 컴퓨팅에서 배운 일치전략(수요가 증가하는 만큼 조금씩 IT 자원을 추가하는 전략)이 아니라 대기업은 그냥 대량으로 깔고 시작하는 것 같습니다

이걸 보고 든 생각이, 테라폼은 오토스케일링을 할 때 사용하는 것이 아니라, 오토스케일링을 하기위한 환경을 구축할 때 사용하는 툴인 것을 깨달았습니다. k8s 환경의 서버를 프로비저닝 할 때 Terraform을 사용하고 오토스케일링은 k8s의 영역인 것 같습니다. 물론 이 생각이 틀린 것 일 수 있지만, 현재까지 공부한 내용을 바탕으로는 그렇습니다. (혹시 잘못 이해하고 있다면 알려주시면 감사하겠습니다!!)

Terraform은 인프라 명세서일 뿐이다.

Terraform의 Resource는 자기만의 라이프사이클을 가집니다. 변경을 감지해서 update된 resource를 생성하고 기존 resource를 삭제하는 방법과 아예 destory되는 것을 방지할 수 있습니다. 전자의 방식을 create_before_destory 옵션이라고 부르고, 후자의 옵션을 prevent_destory 옵션이라고 부릅니다.

create_before_destory 라이프사이클은 Spring Jpa에서 어플리케이션을 껏다 킬 경우 계속 데이터베이스가 초기화되는 옵션과 비슷하다고 생각했고, 실무에서는 사용하지 않을 것 같다고 판단했습니다. 이미 프로비저닝 되고, 잘 사용하고 있는 서버를 내릴 필요는 없다고 생각했습니다. 그래서 prevent_destory 옵션을 사용할 것 같은데 이 옵션을 사용할 경우 인프라 리소스가 변경될 경우 이전 리소스와 새롭게 생기는 리소스가 동기화가 될 수 없습니다.

테라폼의 장점 중 하나로 인프라 리소스 동기화를 말하고 있는데, 이는 아직까지는 선뜻 동의를 못 하겠습니다. 실무에서 resource가 변경되면 기존의 리소스를 갈아치우는 방법을 사용하는지, 아니면 과거에 리소스의 스펙을 코드로 표현하는 것(일종의 명세서)에서 그치는지 의문이 가득합니다.

결론

Terraform의 디렉토리 구조는 best-practice의 구조를 따라가면 좋을 것 같습니다. 하지만 팀 바이 팀이므로 dir 구조는 사전에 잘 협의만 한다면 문제없을 것 같습니다. Terraform은 오토스케일을 위한 Tool이 아니라 오토스케일링 환경을 구축하기 위한 프로비저닝 Tool인 것 같습니다. 또, 인프라 리소스 동기화를 장점으로 내세우고 있지만, 실무 경험이 없는 저에게는 약간의 의문점이 들긴 합니다.

카테고리:

업데이트: