by SuperbAI의 백엔드 개발자

 

System Backend

 

dev : Korea, USA

prod : Korea, USA

 

이렇게 총 네 종류의 클러스터가 있다.

(Multi-Region, Multi-Stage)

 

네 종류의 클러스터를 하나씩 관리하기에는 품이 많이 들어간다.

그래서 고려하게 된 것이 Terraform이다.

 

Terraform 사용으로 얻으려고 한 가치:

 

1. Repetitive steps in multi-stage & -region -> Automation

애플리케이션이 점점 늘어나는데 4개의 클러스터에 배포를 해야되다보니

필연적으로 반복이 있을 수 밖에 없다.

 

운영중인 ECS cluster에 새로운 애플리케이션 A를 배포한다고 해보자.

컨테이너 레지스트리 생성 -> API Secret을 위한 저장소 생성 -> S3/EBS 위한 PV 배포 -> Fargate 생성 -> CI/CD 위한 Code Deploy 생성해서 IAM 바인딩 / 생성되는 인프라 사이에 공유해야 할 변수들도 많다.

 

이런 것들을 웹 콘솔이나 CLI를 사용해서 매번 반복하는건 시간 낭비가 너무 크다.

 

2. Standardization

일반적으로 App이 추가될 때마다 새로 배포될 인프라가 대부분 비슷했기 때문에

배포 과정을 자동화하는 것 뿐만 아니라 재사용 가능하게 만드는 것이 매우 중요했다.

 

A를 배포할 때 재사용이 가능하게 잘 만들어두면, 차후 B,C,D를 배포할 때 configuration을 조금만 변경하면 

큰 노력이 안들고 배포할 수 있기 때문에 큰 이점이 있다.

-> 애플리케이션간 인프라 스택의 일관성을 유지할 수 있었다.

 

 

Towards Monorepo

 

Initial Layout

Don't reinvent the wheel

Fork and customize AWS registry modules.

처음에 모든 코드를 다 작성하려고 하지 말고 잘 작성된 코드를 가져와서 커스터마이징 했다.

AWS의 경우, 활발한 커뮤니티 덕분에 최신 인프라에 대한 모듈도 금방 테라폼 레지스트리에 올라온다.

VPC, ECR, Fargate, Code Deploy에 대한 예제 코드들이 올라와있어서

Fork해서 일차적 커스터마이징을 했다.

 

이런 Code들을 조립해서 본인 Application에 대한 모듈을 만들었다.

해당 모듈들은 네 개의 클러스터에 각각 배포할 수 있도록 서로 다른 부분은 변수로 조정 가능하게 만들었다.

ex. ECS 클러스터에 올라갈 컨테이너의 갯수, CPU/Memory 자원에 대한 할당을 설정 가능하게 작성해서 배포.

 

개발 사이클을 최대한 빠르게 가져가고자 했다.

설립 초기에는 인프라 코드에 대한 CI/CD나 브랜치 전략을 강제하기는 어려웠다.

모든 모듈과 deployments를 별도 repository에 저장하게 되었다.

 

서비스가 성장하게 되니 점점 더 많은 애플리케이션이 추가되었다.

 

Problems

Unwanted Result

 

Complexity

ex) one additional service = (1 module repo + 4 deployment repos) x (number of modules)

게다가 하나의 서비스가 성격에 따라 둘 이상의 모듈을 생성하는 경우도 있을 수 있다.

 

이 회사의 경우 DNS, LB 같이 한번 배포 후에 건드릴 일이 없는 정적인 인프라 / Container Defenition, Code Deployment처럼 동적인 인프라를 분리해서 배포하고 있다.

 

그러면 서비스 A를 위해 새로운 레포지토리가 10개 이상이 생겨나게 되어서 관리 포인트가 10배로 늘어나게 된다는 단점이  생긴다.

 

inefficiency

More repositories -> consistency gradually lost

레포지토리가 늘어나면서 처음에 고안했던 재사용성이나 표준화의 장점이 점점 사라진다.

Scattered documents -> high barrier to entry

레포지토리 갯수가 많아지니까 찾고 싶은 내용 있어도 찾기 어렵고, 서비스 하나마다 PR을 하더라도 5개에 해줘야하고, 신입 개발자들은 장애물이 너무 커진다.

 

그래서 기존 Terraform layout의 Refactoring을 고민하게 됐다.

 

The Great Debate

Multi Repo vs Mono Repo

 

Multi Repo (= 모든 모듈과 배포를 분리하는 방식을 Multi-Repo / Poly-Repo라고 한다.) 

Good

- submodule versioning 각각을 독립적으로 버저닝

- independent testing 독립적 테스트

- separate access control 관리에 대한 권한 분리 가능

Bad

- multiple source of truth (= more PRs which leads to inefficiency) 온보딩이 늘어나고 PR/Code Review 늘어난다

- inconsistency across projects 프로젝트간 규칙성과 일관성 유지하기에 불리한 구조다

 

Mono Repo

Good

- single source of truth (= lower barrier to entry)

- consistency across projects

Bad

- submodule versioning is hard

- separate CI pipelines is hard

- separate access control is hard

 

Multi Repo의 단점은 Initial Goals와 명백히 상충했다고 한다.

그런데 Mono Repo의 단점은 초창기 세팅만 잘 하면 분명 달성하기 어려운 목표지만 가능은 하리라고 판단했다고 함.

그래서 Mono Repo를 선택했다고 함.

 

대규모 refactoring 수행

 

New Layout

Improvement

 

3 mono repos

- Reference Modules

- Service Modules

- Live Deployments

 

Reference Modules (기존에 작성된 코드를 fork해서 수정한 것)

 

. terraform-aws-alb, terraform-aws-bastion, 등등) -> Service Modules (개발 모듈들) -> Live Repository (dev/korea,usa, prod/korea,usa)

 

Why not just 1 big mono repo?

- Separate modules from deployments

- Prevent self-reference

디플로이먼트와 모듈을 분리함으로써 모노 리포간 일관성을 갖추되, repository 내의 자기 참조를 방지하기 위해 모듈들을 두 종류로 구분할 수 있게 했다.

 

Continuous Integration

1. check formatting

2. fetch dependenies

3. validate project

 

 

Future Plan

만약 협업 과정에서 multiple apply가 동시에 일어나면? Conflict가 일어나지 않을까?

-> 그래서 현재 S3 state Bucket과 DynamoDB Lock Table을 사용해 state locking으로 어느정도 방지하고 있대.

 

근데 이게 모든걸 해결해주나?

누군가가 강제로 force-unlock으로 해제해버리든가, 타겟을 지정해서 부분적으로 apply 한다든가 하는 모든 변칙적인 상황에 다 대응하기 어렵다. 그래서 CI/CD에 테라폼 커맨드를 바인딩해서 배포 과정을 자동화하는 것이 다음 목표

-> Terraform Enterprise 도입도 하나의 옵션.

 

 

모듈에 대한 관리 강화

Use git tags for versioning

 

How to prevent potential misconfigurations?

-> use static analysis tools such as tfsec, checkov

 

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기