AI Briefing

통합 개발과 배포: Monorepo와 GitOps의 매력적인 조합

·2024.04.08 00:00

Monorepo와 GitOps를 결합해 FE 개발부터 배포까지 컨테이너 기반으로 통합했다.

사람인 FE개발팀은 레거시를 점진적으로 개선하는 과정에서 주요 서비스의 FE 분리를 준비했고, 그 해법으로 Monorepo를 선택했다. 첫 서비스 배포를 앞두고 배포 방식까지 함께 재설계하면서 GitOps를 도입했다.

기존 파이프라인은 feature 브랜치에서 review 서버로 확인하고, develop으로 머지하면 dev 서버에 배포한 뒤 최종 QA를 거쳐 main으로 운영 배포하는 구조였다. 운영 배포에서는 여러 대의 웹서버를 순차적으로 내리고, builddeploy를 수행한 뒤 pm2 reloadLB 복구까지 직접 처리해야 했다.

문제는 DevOps 전담 조직이 없어 FE개발자가 환경을 직접 구성해야 했다는 점이다. next build로 만든 산출물을 배포하고 next start로 띄운 뒤 nginx로 프록시하는 방식이었는데, featurehotfix 브랜치는 수시로 바뀌어서 웹서버와 브랜치를 유연하게 매칭하기 어려웠다. 결국 review 서버를 3개 정도 따로 운영해야 했고, 더 유연한 컨테이너 기반 배포환경이 필요하다는 결론에 도달했다.

Image build

먼저 Dockerfile/apps 아래에 두고, 향후 비슷한 스택의 서비스에도 재사용할 수 있게 구성했다. 베이스는 node:20-alpine이고, libc6-compatcorepack enable을 적용해 pnpmturbo를 사용할 수 있게 했다.

빌드 단계는 Multi Stage로 나뉜다.

  • builder stage: 전체 소스를 복사한 뒤 turbo prune --scope=${APP_NAME} --docker로 필요한 패키지만 추린다.
  • installer stage: prune 결과를 바탕으로 turbo run build:${APP_ENV} --filter=${APP_NAME}를 실행해 빌드한다.
  • runner stage: 비루트 사용자(nextjs)를 만들고, .next/standalone, static, public만 복사해 실행 이미지를 최소화한다.

CI 빌드는 kaniko로 진행했다. Docker Daemon 없이 컨테이너 안에서 이미지를 만들 수 있고, Host root 권한이 필요하지 않아 더 적합했다. 이미지 저장소는 사내 Harbor를 사용했고, 레지스트리 접속 정보는 GitLab 변수로 관리했다.

유지 정책도 함께 설정했다. /web1/develop은 최근 푸시된 이미지 10개를 유지하고, /web1/feature*는 최근 5개이면서 7일 이내 푸시된 이미지만 남기도록 정리했다.

Chart override

배포 리소스는 선언적으로 관리하기 위해 Helm chart를 선택했다. kustomizeHelm chart 중에서, 환경별·서비스별 values 파일로 유연하게 대응할 수 있다는 점이 결정적이었다.

차트는 values.yaml, deployment.yaml, service.yaml, ingress.yaml, hpa.yaml, secrets.yaml 등으로 구성했다. 기본 리소스는 CPU 100m, 메모리 128Mi로 잡았고, nodeAffinity를 통해 FE 전용 노드(sri-fe)에만 배포되도록 했다. 헬스체크는 livenessProbereadinessProbe 모두 tcpSocket3000 포트를 사용했다.

파이프라인에서는 sample/ 폴더의 값을 복사한 뒤 yq로 다음 항목들을 자동 수정했다.

  • nameOverride, fullnameOverride
  • image.repository, image.tag
  • imagePullSecrets, secretsName
  • imageCredentials.*
  • ingress.hosts[0].host

수정된 values는 다시 차트 repo에 커밋되고 푸시된다. 이 방식은 ArgoCD가 감시하는 파일을 직접 갱신해 배포를 유도하는 구조다.

App create & update

마지막으로 ArgoCD Application을 선언적으로 생성하고 갱신했다. Dashboard에서 수동 관리하는 대신 argocd app create CLI를 사용해 application.yaml을 기반으로 앱을 만들고, --upsert로 업데이트까지 처리했다.

이렇게 Monorepo, kaniko, Helm chart, ArgoCD를 이어 붙여, FE 서비스의 개발부터 이미지 빌드, 배포 설정, 클러스터 반영까지 하나의 Git 흐름으로 묶었다. 결과적으로 브랜치 단위의 유연한 배포와 운영 자동화를 동시에 노릴 수 있는 구조를 만들었다.

이 요약은 원문 이해를 돕기 위한 큐레이션입니다. 저작권은 원저작자에게 있으며, 정확한 내용과 맥락은 원문을 확인하세요.

요약 오류, 출처 표기 문제, 삭제 요청은 문의 · 건의로 알려주세요.