본문 바로가기

AWS

테라폼 맨땅에서 부터 적용하기 2

진짜 한땀 한땀 넘겨놓고 나니 이젠 어지간한 리소스 그림으로 그려보라면 그릴 수 있을 거 같다.

그리고 모든 브랜치의 리소스도 파악하여 (terraform에 import 된 것 한정) apply도 확인해가며 돌릴 자신은 생겼다.

이 상태에서 2 ~ 3주간의 일상적인 리소스 변경활동도 이어 갔다.

 

단 1편에서 나온 모듈화 되어 있지 않은 널브러진 파일은 가독성이 떨어지는 부분이 있어서 폴더화가 필요해 보였다.

 

이게 필요한 것은 알았지만, 적용시 몇가지 불편한 사항이 있었다.

1. state backup이 제대로 되지 않아 간간히 내가 삼실 컴에서 하던 것과 집 컴에서 할때 코드가 같아도 state의 문제로 다시 import 해야 하는 문제가 발생

2. 다른 브랜치가 바뀌는 중에 원하는 브랜치만 따로 적용이 불가능

 

다른 데봅스님과 식사를 하던중 backend라는 기능이 있다는 것을 알았다.

https://developer.hashicorp.com/terraform/language/settings/backends/s3

 

Backend Type: s3 | Terraform | HashiCorp Developer

Terraform can store state remotely in S3 and lock that state with DynamoDB.

developer.hashicorp.com

code만 맞으면 state는 s3에 올려놓고 통제가 가능하니 state가 꼬여 재 import를 하지 않아도 된다는 장점이 있었다.

사무실에서도, 집에서도 commit만 잘하고 다니면 언제든지 동일한 코드로 state 걱정없이 사용할 수 있다는 것이다.

 

그래. 이왕 이렇게 된 것 한번 모듈화 해보자 라고 생각하고 맘 먹고 작업 하기로 했다.

 

하지만 내가 미쳐 생각하지 못했던 한가지.

모듈화를 하려면 폴더만 나누는 것이 아니라 terraform state까지 이전해야 하는 것이었다.

 

모든 리소스를 다시 임포트를 해야 하는 중대한 문제가 있었다.

평일 낮에는 작업을 할 수 없었다. 중간에 들어오는 요청도 너무 많고 하다보니 일일이 대응하면서 테라폼 스크립트를 수정하기 너무 부담 스러웠다. 

 

IaC 작업 특성상 가독성은 높아지지만 실행력이 빠른 만큼 그만큼 사이드 이펙트도 크기 때문에 집중하는 환경에서 해야 했다.

몇 주간의 1 상태를 유지하다가 주말을 이용하여 스크립트를 모듈화 해보기로 했다.

Chapter 2. 모듈화

├── README.md
├── dev
│   ├── main.tf
│   ├── modules
│   │   ├── ec2
│   │   │   ├── main.tf
│   │   │   ├── output.tf
│   │   │   └── variables.tf
│   │   ├── ecs
│   │   │   ├── main.tf
│   │   │   ├── outputs.tf
│   │   │   └── variables.tf
│   │   ├── loadbalancer
│   │   │   ├── main.tf
│   │   │   ├── output.tf
│   │   │   └── variables.tf
│   │   ├── log_groups
│   │   │   ├── main.tf
│   │   │   └── outputs.tf
│   │   ├── network
│   │   │   ├── main.tf
│   │   │   ├── outputs.tf
│   │   │   └── variables.tf
│   │   ├── security_group
│   │   │   ├── main.tf
│   │   │   ├── outputs.tf
│   │   │   └── variables.tf
│   │   └── ssm_variables
│   │       ├── main.tf
│   │       └── outputs.tf
│   ├── terraform.tfstate
│   ├── terraform.tfstate.backup
│   └── variables.tf
├── modules
│   ├── acm
│   │   ├── main.tf
│   │   └── outputs.tf
│   ├── iam
│   │   ├── iam_group_policy_attach.tf
│   │   ├── iam_role.tf
│   │   ├── main.tf
│   │   └── outputs.tf
│   └── iam_user_policy
│       ├── iam_user_policy_document.tf
│       ├── main.tf
│       └── outputs.tf
├── prod
│   ├── main.tf
│   ├── modules
│   │   ├── ec2
│   │   │   ├── main.tf
│   │   │   ├── outputs.tf
│   │   │   └── variablest.tf
│   │   ├── ecs
│   │   │   ├── main.tf
│   │   │   └── variables.tf
│   │   ├── loadbalancer
│   │   │   ├── main.tf
│   │   │   ├── outputs.tf
│   │   │   ├── prod_customer_alb_rule.tf
│   │   │   └── variables.tf
│   │   ├── log_groups
│   │   │   ├── main.tf
│   │   │   └── outputs.tf
│   │   ├── network
│   │   │   ├── main.tf
│   │   │   ├── output.tf
│   │   │   ├── prod_vpc_endpoint.tf
│   │   │   └── variables.tf
│   │   ├── security_group
│   │   │   ├── main.tf
│   │   │   ├── outputs.tf
│   │   │   └── variables.tf
│   │   └── ssm_variables
│   │       ├── main.tf
│   │       └── outputs.tf
│   └── variables.tf
├── provider.tf
├── stage
│   ├── main.tf
│   ├── modules
│   │   ├── ec2
│   │   │   ├── main.tf
│   │   │   ├── outputs.tf
│   │   │   └── variables.tf
│   │   ├── ecs
│   │   │   ├── main.tf
│   │   │   ├── outputs.tf
│   │   │   └── variables.tf
│   │   ├── loadbalancer
│   │   │   ├── main.tf
│   │   │   ├── outputs.tf
│   │   │   └── variables.tf
│   │   ├── log_groups
│   │   │   ├── main.tf
│   │   │   └── outputs.tf
│   │   ├── network
│   │   │   ├── main.tf
│   │   │   ├── outputs.tf
│   │   │   └── variables.tf
│   │   ├── security_group
│   │   │   ├── main.tf
│   │   │   ├── outputs.tf
│   │   │   └── variables.tf
│   │   └── ssm_variables
│   │       ├── main.tf
│   │       └── outputs.tf
│   ├── outputs.tf
│   └── variables.tf
├── terraform.tfstate
├── terraform.tfstate.backup
├── terraform.tfstate.d
│   └── stg
├── tree.txt
└── variables.tf

 

이전보단 뭔가 깔끔해진 느낌일까???

사실 아직까진 좀 어지럽긴 하다.

 

메인 폴더의 구조는 다음과 같다.

- dev : 개발

- stage : 스테이지

- prod : 운영

- modules : 공통 모듈

 

- branch 폴더 구조

- modules : 모듈 집합

ㄴ 각 서비스

 

리스소 정리 자체는 생각보단 편했다.

왜냐면 마구잡이로 했던 코드를 모듈별 main.tf에 카피하고 맞추면서 다시 import 하고 plan 돌리면서 하면 되었기 때문이다.

 

여기에서 내가 어렵게 생각했던 부분은 outputs.tf와 variables.tf 부분이었다.

 

module에서 적용시 outputs.tf에 정의되어 있지 않으면 타 모듈에서 적용이 불가능 했고

브랜치 main.tf에서 강제로 모듈에 variable을 넣어줄때도 해당 모듈의 variables.tf에 variable로 정의가 되어 있지 않으면 입력을 받지 못해 에러가 난다는 것이었다.

 

어차피 variables.tf에 default로 넣을 수 있는 값은 한계가 있었기 때문에 일일이 얘도 한땀 한땀 맞춰 줬어야 했다.

당연히 outputs.tf도 variables에서 가져가는 만큼 모두 만들어 줬어야 했다.

ecs에서 변수를 가져가는 것이 ssm parameter store에서 가져가게 되어 있는데 문제는 변수가 너무 많아서 일일이 매칭하는데 시간이 걸리기도 했다.

 

dev, stage, prod 리소스 매칭 & import 후 브랜치 별 terraform plan 돌려서 no change 작업이 총 15시간 정도 걸린 것 같다.

생각보단 시간이 적게 걸렸다.

 

여기서 작업을 빠르게 하기 위해서 이런 방식을 도입했다.

1. dev : 손으로 그냥 한땀 한땀 outputs.tf, variables.tf 맞추고 import까지 함.

2. stage : 손으로 그냥 한땀 한땀 outputs.tf, variables.tf 맞추고 import까지 함.

3. 2에서 작업한 리소스의 outputs.tf는 그대로 copy하고 stg -> prod로 변수 네이밍 패턴 수정 후 브랜치 main.tf에 있는 variable값을 모두 copy하여 variables.tf에 넣고 variable 문법 패턴으로 변경 후 import

 

주의사항

1. 공통 리소스의 경우 바뀔때 마다 다시 import 해줘야 한다.

2. github code에 .gitignore에 terraform 모듈 들어가면 git push 할때 fail 뜨므로 미리 .gitignore에 추가해야 함.

3. variables.tf가 gitignore 될 수 있는데 이게 빠지면 모든 variables.tf를 다시 만들어야 해서 작업이 몇시간 중단 될 수 있음 

 

출근하여 써보고 있는 중이지만 테라폼 자체가 원체 복잡해서 그런지 아직은 적응이 안간다. 단 장점은 더욱 올라온거 같다.

 

Chapter 1 -> 2로의 장점

- 브랜치 단위 리소스 변경이 가능

 

Chapter 1 -> 2로의 단점

- 공통 리소스 변경은 여전히 각 브랜치 별로 돌면서 import를 해야 한다. (특히 acm...)

 

이 프로젝트 말고 다른 프로젝트 terraform 스크립트도 하나 더 해야 한다.

그 프로젝트도 동일하게 일단 Chapter 2까지 적용을 해야겠다.