테마
모노레포 마이크로프론트엔드 CI/CD 파이프라인 구축
모노레포 환경에서 변경된 패키지만 감지하여 선택적으로 빌드하고, Turborepo의 --filter와 캐싱을 활용해 CI/CD 파이프라인을 자동화하는 전략을 학습한다.
학습 목표
- 모노레포에서 변경 감지 기반 빌드 자동화의 필요성과 원리를 이해한다
- Turborepo의
--filter옵션을 활용하여 변경된 패키지만 빌드하는 방법을 익힌다 - 빌드 타임 의존성(UIKit, Shell Router 등)을 선행 빌드하는 파이프라인 순서를 설계할 수 있다
- GitHub Actions를 활용한 실제 CI/CD 워크플로 설정을 구현할 수 있다
1. 모노레포에서 빌드 자동화의 필요성
마이크로프론트엔드를 모노레포로 관리하면 수십 개의 워크스페이스가 하나의 저장소에 공존한다. 전체를 매번 빌드하면 시간과 비용이 낭비된다.
전체 빌드 vs 선택적 빌드 비교
| 항목 | 전체 빌드 | 선택적 빌드 |
|---|---|---|
| 빌드 범위 | 모든 워크스페이스 | 변경된 워크스페이스 + 의존 패키지 |
| 소요 시간 | 10~30분 | 1~5분 |
| CI 비용 | 매 커밋마다 높은 비용 | 변경 범위에 비례 |
| 배포 위험 | 불필요한 배포 포함 가능 | 변경 사항만 정확히 배포 |
| 캐시 활용 | 비효율적 | Turborepo 캐시로 극대화 |
2. 빌드 타임 의존성 선행 빌드
마이크로앱을 빌드하기 전에, 빌드 시점에 참조하는 공유 패키지를 먼저 빌드해야 한다. 커리어업 프로젝트에서는 ui-kit과 shell-router가 빌드 타임 의존성에 해당한다.
package.json에 선행 빌드 스크립트 추가
json
// monorepo root package.json
{
"scripts": {
"build": "turbo build",
"build:packages": "turbo build --filter=shell-router --filter=ui-kit"
}
}build:packages는 전체 프로젝트가 아닌, 빌드 타임에 공유되는 패키지 두 개만 필터링하여 빌드한다.
각 마이크로앱의 빌드 스크립트 구성
json
// apps/posting/package.json
{
"scripts": {
"build": "pnpm --filter monorepo build:packages && webpack --mode production",
"build:dev": "pnpm --filter monorepo build:packages && webpack --mode development"
}
}핵심은 &&로 연결하여 패키지 빌드가 완료된 후에만 마이크로앱 빌드가 시작되도록 하는 것이다.
3. Turborepo --filter 활용
Turborepo의 --filter 플래그는 특정 워크스페이스만 빌드 대상으로 지정하는 핵심 기능이다.
주요 --filter 패턴
bash
# 특정 워크스페이스만 빌드
turbo build --filter=posting
# 여러 워크스페이스 지정
turbo build --filter=shell-router --filter=ui-kit
# glob 패턴 (접두사가 동일한 패키지 일괄 빌드)
turbo build --filter='@career-up/*'
# 특정 워크스페이스와 그 의존성 전부 빌드
turbo build --filter=posting...
# 변경된 파일 기반 (Git 비교)
turbo build --filter='[HEAD^1]'
# 특정 브랜치 기준 변경 감지
turbo build --filter='[origin/main...HEAD]'--filter 옵션 요약
| 패턴 | 설명 | 예시 |
|---|---|---|
--filter=name | 이름으로 특정 | --filter=posting |
--filter=name... | 해당 패키지 + 모든 의존성 | --filter=posting... |
--filter='@scope/*' | 스코프로 그룹 지정 | --filter='@career-up/*' |
--filter='[ref]' | Git ref 이후 변경된 패키지 | --filter='[origin/main]' |
--filter='[ref1...ref2]' | 두 ref 사이 변경된 패키지 | --filter='[HEAD^1...HEAD]' |
Turborepo 캐싱 메커니즘
4. GitHub Actions CI 워크플로 설정
기본 CI 워크플로
yaml
# .github/workflows/ci.yml
name: CI - Build & Test
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 2 # 변경 감지를 위해 이전 커밋 포함
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Turborepo cache
uses: actions/cache@v4
with:
path: .turbo
key: turbo-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
turbo-${{ runner.os }}-
- name: Build changed packages
run: pnpm turbo build --filter='[HEAD^1]'
- name: Run tests
run: pnpm turbo test --filter='[HEAD^1]'마이크로앱별 독립 배포 워크플로
yaml
# .github/workflows/deploy-posting.yml
name: Deploy Posting App
on:
push:
branches: [main]
paths:
- 'apps/posting/**'
- 'packages/ui-kit/**'
- 'packages/shell-router/**'
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
- run: pnpm install --frozen-lockfile
- name: Build shared packages
run: pnpm build:packages
- name: Build posting app
run: pnpm --filter posting build
- name: Deploy to CDN
run: |
# dist/ 폴더를 S3나 CDN에 업로드
aws s3 sync apps/posting/dist/ s3://cdn-bucket/posting/ \
--cache-control "public, max-age=31536000"paths 트리거 핵심: apps/posting/** 외에도 packages/ui-kit/**과 packages/shell-router/**를 포함한다. 공유 패키지가 변경되면 해당 패키지에 의존하는 마이크로앱도 재빌드/재배포 해야 하기 때문이다.
5. 환경 변수 기반 엔드포인트 관리
CI/CD에서 빌드할 때 환경별로 다른 엔드포인트를 주입해야 한다. 로컬 개발 시에는 localhost를 사용하지만, QA/스테이징/프로덕션에서는 각각 다른 URL을 사용한다.
.env 파일 구성
bash
# .env (개발)
REACT_APP_MICRO_POSTING=http://localhost:3001
REACT_APP_MICRO_EDU=http://localhost:3002
REACT_APP_MICRO_NETWORK=http://localhost:3003
REACT_APP_MICRO_JOB=http://localhost:3004
REACT_APP_FRAGMENT_RECOMMEND_CONNECTIONS=http://localhost:5001
REACT_APP_SERVER_URL=http://localhost:4000bash
# .env.production (프로덕션)
REACT_APP_MICRO_POSTING=https://posting.cdn.example.com
REACT_APP_MICRO_EDU=https://edu.cdn.example.com
REACT_APP_MICRO_NETWORK=https://network.cdn.example.com
REACT_APP_MICRO_JOB=https://job.cdn.example.com
REACT_APP_FRAGMENT_RECOMMEND_CONNECTIONS=https://fragment-rc.cdn.example.com
REACT_APP_SERVER_URL=https://api.example.comShell에서 환경 변수 사용
typescript
// apps/shell/src/components/AppPosting.tsx
importRemote<{ default: InjectFunctionType }>({
url: process.env.REACT_APP_MICRO_POSTING!,
scope: "posting",
module: "./injector",
remoteEntryFileName: "remoteEntry.js"
});이렇게 환경 변수로 관리하면, CI/CD 파이프라인에서 빌드 시점에 환경별 .env 파일만 교체하면 된다.
6. CI/CD 파이프라인 전체 아키텍처
핵심 정리
- 모노레포에서 전체 빌드는 비효율적이다. Turborepo의
--filter와 캐싱을 활용하면 변경된 패키지만 빌드하여 CI 시간을 80% 이상 단축할 수 있다 - 마이크로앱 빌드 전에 빌드 타임 의존성(ui-kit, shell-router)을 반드시 선행 빌드해야 한다.
build:packages스크립트로 이를 자동화한다 - GitHub Actions의
paths트리거를 사용하면 변경된 파일 경로에 따라 해당 마이크로앱의 배포 워크플로만 실행할 수 있다 - 환경 변수로 리모트 엔트리 URL을 관리하면, 개발/QA/프로덕션 환경 전환이 빌드 시점에
.env파일 교체만으로 완료된다 - Turborepo의 해시 기반 캐싱은 입력(소스, 의존성, 환경 변수)이 동일하면 빌드를 완전히 스킵하므로, CI 반복 실행 비용을 획기적으로 줄인다
다음 단계
- 02-선택적-배포-전략.md: 마이크로앱 추가 개발 후 배포 범위를 결정하는 방법과, UIKit 같은 공유 패키지 변경 시 영향 범위를 분석하여 빌드타임 의존성과 런타임 의존성에 따라 배포 전략을 수립하는 방법을 학습한다