Files
zellyy-finance/docs/02_기술_문서/ci-cd-pipeline.md

562 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Zellyy Finance CI/CD 파이프라인 가이드
이 문서는 Zellyy Finance 앱의 CI/CD(지속적 통합/지속적 배포) 파이프라인 구축 및 사용 방법에 대해 설명합니다.
## 목차
1. [개요](#개요)
2. [CI/CD 파이프라인 구성](#cicd-파이프라인-구성)
3. [GitHub Actions 설정](#github-actions-설정)
4. [버전 관리 자동화](#버전-관리-자동화)
5. [테스트 빌드 배포 및 설치](#테스트-빌드-배포-및-설치)
6. [앱스토어 자동 배포](#앱스토어-자동-배포)
7. [비용 분석](#비용-분석)
8. [문제 해결 및 FAQ](#문제-해결-및-faq)
## 개요
CI/CD 파이프라인은 코드 변경사항을 자동으로 빌드, 테스트 및 배포하는 자동화된 프로세스입니다. Zellyy Finance 앱에서는 GitHub Actions를 사용하여 이 프로세스를 구현합니다.
### 주요 이점
- **개발 효율성 향상**: 반복적인 빌드 및 배포 작업 자동화
- **일관된 빌드 품질**: 동일한 환경에서 항상 일관된 방식으로 빌드
- **버전 관리 자동화**: 버전 코드 및 빌드 번호 자동 증가
- **배포 프로세스 간소화**: 앱스토어 제출 과정 자동화
- **팀 협업 개선**: 빌드 상태 및 결과 공유 용이
## CI/CD 파이프라인 구성
Zellyy Finance의 CI/CD 파이프라인은 다음과 같은 단계로 구성됩니다:
1. **코드 검증**: 린트 검사 및 단위 테스트 실행
2. **웹 앱 빌드**: React 앱 빌드
3. **네이티브 앱 빌드**: Capacitor를 통한 Android/iOS 앱 빌드
4. **테스트 배포**: Firebase App Distribution을 통한 테스터 배포
5. **앱스토어 배포**: Google Play Store 및 Apple App Store 배포
### 워크플로우 다이어그램
```
코드 푸시/PR → 코드 검증 → 웹 앱 빌드 → 네이티브 앱 빌드 → 테스트 배포 → 앱스토어 배포
```
## GitHub Actions 설정
### 워크플로우 파일 생성
`.github/workflows/ci-cd.yml` 파일을 생성하여 CI/CD 파이프라인을 구성합니다.
```yaml
name: Zellyy Finance CI/CD
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
workflow_dispatch:
inputs:
buildType:
description: '빌드 타입 (debug, release-apk, release-aab, ios-release)'
required: true
default: 'debug'
versionCode:
description: '버전 코드 (자동 증가는 1, 수동 지정은 원하는 숫자 입력)'
required: false
versionName:
description: '버전 이름 (예: 1.0.0)'
required: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 노드 설정
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- name: 종속성 설치
run: npm ci
- name: 린트 검사
run: npm run lint
- name: 버전 정보 설정
id: version
run: |
# 현재 버전 코드 가져오기
CURRENT_VERSION_CODE=$(grep -o 'versionCode [0-9]*' android/app/build.gradle | awk '{print $2}')
if [ -z "$CURRENT_VERSION_CODE" ]; then
CURRENT_VERSION_CODE=1
fi
# 현재 버전 이름 가져오기
CURRENT_VERSION_NAME=$(grep -o 'versionName "[^"]*"' android/app/build.gradle | sed 's/versionName "//' | sed 's/"//')
if [ -z "$CURRENT_VERSION_NAME" ]; then
CURRENT_VERSION_NAME="1.0.0"
fi
# 입력된 버전 정보 또는 기본값 사용
if [ "${{ github.event.inputs.versionCode }}" = "1" ] || [ -z "${{ github.event.inputs.versionCode }}" ]; then
NEW_VERSION_CODE=$((CURRENT_VERSION_CODE + 1))
else
NEW_VERSION_CODE=${{ github.event.inputs.versionCode }}
fi
VERSION_NAME="${{ github.event.inputs.versionName }}"
if [ -z "$VERSION_NAME" ]; then
VERSION_NAME=$CURRENT_VERSION_NAME
fi
BUILD_NUMBER=$NEW_VERSION_CODE
# 버전 정보 파일 업데이트
echo "buildNumber=$BUILD_NUMBER" > android/version.properties
echo "versionCode=$NEW_VERSION_CODE" >> android/version.properties
echo "versionName=$VERSION_NAME" >> android/version.properties
cp android/version.properties android/app/version.properties
# app_version.json 파일 업데이트
cat > android/app_version.json << EOF
{
"versionCode": $NEW_VERSION_CODE,
"versionName": "$VERSION_NAME",
"buildNumber": $BUILD_NUMBER,
"notes": "자동 빌드에 의해 생성된 버전 정보입니다."
}
EOF
echo "VERSION_CODE=$NEW_VERSION_CODE" >> $GITHUB_OUTPUT
echo "VERSION_NAME=$VERSION_NAME" >> $GITHUB_OUTPUT
echo "BUILD_NUMBER=$BUILD_NUMBER" >> $GITHUB_OUTPUT
- name: 웹 앱 빌드
run: npm run build
- name: Capacitor 동기화
run: npx cap sync android
- name: JDK 설정
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
cache: 'gradle'
- name: 안드로이드 앱 빌드
working-directory: android
run: |
if [ "${{ github.event.inputs.buildType }}" = "release-aab" ]; then
./gradlew clean bundleRelease
elif [ "${{ github.event.inputs.buildType }}" = "release-apk" ]; then
./gradlew clean assembleRelease
else
./gradlew clean assembleDebug
fi
- name: Firebase App Distribution 배포
if: github.event.inputs.buildType == 'debug'
uses: wzieba/Firebase-Distribution-Github-Action@v1
with:
appId: ${{ secrets.FIREBASE_APP_ID }}
serviceCredentialsFileContent: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}
groups: testers
file: android/app/build/outputs/apk/debug/app-debug.apk
releaseNotes: |
버전: ${{ steps.version.outputs.VERSION_NAME }} (${{ steps.version.outputs.BUILD_NUMBER }})
빌드 날짜: $(date +'%Y-%m-%d %H:%M:%S')
커밋: ${{ github.sha }}
- name: Google Play 배포
if: github.event.inputs.buildType == 'release-aab'
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.PLAY_STORE_SERVICE_ACCOUNT_JSON }}
packageName: com.zellyy.finance
releaseFiles: android/app/build/outputs/bundle/release/app-release.aab
track: internal
status: completed
releaseName: ${{ steps.version.outputs.VERSION_NAME }}
releaseNotes: |
ko-KR: 버전 ${{ steps.version.outputs.VERSION_NAME }} 업데이트
- 버그 수정 및 성능 개선
- name: 빌드 결과물 저장
uses: actions/upload-artifact@v3
with:
name: app-${{ steps.version.outputs.VERSION_NAME }}-${{ steps.version.outputs.BUILD_NUMBER }}
path: |
android/app/build/outputs/apk/debug/*.apk
android/app/build/outputs/apk/release/*.apk
android/app/build/outputs/bundle/release/*.aab
- name: 슬랙 알림
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
fields: repo,message,commit,author,action,eventName,ref,workflow,job,took
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
if: always()
```
### GitHub Secrets 설정
GitHub 저장소의 Settings > Secrets and variables > Actions에서 다음 시크릿을 설정해야 합니다:
- `FIREBASE_APP_ID`: Firebase 프로젝트의 앱 ID
- `FIREBASE_SERVICE_ACCOUNT`: Firebase 서비스 계정 JSON 파일 내용
- `PLAY_STORE_SERVICE_ACCOUNT_JSON`: Google Play 서비스 계정 JSON 파일 내용
- `SLACK_WEBHOOK_URL`: 슬랙 알림을 위한 웹훅 URL
## 버전 관리 자동화
### 버전 관리 스크립트
`scripts/version-manager.sh` 파일을 생성하여 버전 관리를 자동화합니다.
```bash
#!/bin/bash
# version-manager.sh
# 현재 버전 정보 가져오기
get_current_version() {
if [ -f "android/app_version.json" ]; then
VERSION_CODE=$(grep -o '"versionCode": [0-9]*' android/app_version.json | awk '{print $2}')
VERSION_NAME=$(grep -o '"versionName": "[^"]*"' android/app_version.json | sed 's/"versionName": "//' | sed 's/"//')
BUILD_NUMBER=$(grep -o '"buildNumber": [0-9]*' android/app_version.json | awk '{print $2}')
# 값이 비어있는지 확인
if [ -z "$VERSION_CODE" ]; then VERSION_CODE=1; fi
if [ -z "$VERSION_NAME" ]; then VERSION_NAME="1.0.0"; fi
if [ -z "$BUILD_NUMBER" ]; then BUILD_NUMBER=1; fi
else
VERSION_CODE=1
VERSION_NAME="1.0.0"
BUILD_NUMBER=1
fi
echo "현재 버전 정보:"
echo "버전 코드: $VERSION_CODE"
echo "버전 이름: $VERSION_NAME"
echo "빌드 넘버: $BUILD_NUMBER"
}
# 버전 정보 업데이트
update_version_files() {
# version.properties 파일 업데이트
echo "buildNumber=$BUILD_NUMBER" > android/version.properties
echo "versionCode=$VERSION_CODE" >> android/version.properties
echo "versionName=$VERSION_NAME" >> android/version.properties
# app 디렉토리에도 동일한 파일 복사
cp android/version.properties android/app/version.properties
# app_version.json 파일 업데이트
cat > android/app_version.json << EOF
{
"versionCode": $VERSION_CODE,
"versionName": "$VERSION_NAME",
"buildNumber": $BUILD_NUMBER,
"notes": "자동 업데이트된 버전 정보입니다."
}
EOF
echo "버전 정보가 모든 파일에 저장되었습니다."
}
# 메인 함수
main() {
get_current_version
# 빌드 타입에 따라 버전 증가
case "$1" in
"debug")
BUILD_NUMBER=$((BUILD_NUMBER + 1))
;;
"release")
VERSION_CODE=$((VERSION_CODE + 1))
BUILD_NUMBER=$VERSION_CODE
;;
*)
echo "사용법: $0 [debug|release]"
exit 1
;;
esac
update_version_files
echo "업데이트된 버전 정보:"
echo "버전 코드: $VERSION_CODE"
echo "버전 이름: $VERSION_NAME"
echo "빌드 넘버: $BUILD_NUMBER"
}
main "$@"
```
### 버전 관리 규칙
Zellyy Finance 앱의 버전 관리는 다음 규칙을 따릅니다:
- **versionCode**: 앱스토어에 제출할 때마다 증가하는 정수 값
- **versionName**: 사용자에게 표시되는 버전 (예: "1.0.0")
- **buildNumber**: 내부 빌드 추적을 위한 번호
## 테스트 빌드 배포 및 설치
테스트 빌드가 완료된 후 개발자와 테스터가 앱을 설치하고 테스트할 수 있는 방법을 설명합니다.
### Firebase App Distribution을 통한 배포
Firebase App Distribution은 테스트 버전 앱을 테스터에게 쉽게 배포할 수 있는 서비스입니다.
#### 설정 방법
1. **Firebase 프로젝트 설정**:
- [Firebase 콘솔](https://console.firebase.google.com/)에서 프로젝트 생성
- App Distribution 서비스 활성화
- 테스터 그룹 생성 및 테스터 이메일 추가
2. **GitHub Actions 설정**:
- `FIREBASE_APP_ID``FIREBASE_SERVICE_ACCOUNT` 시크릿 설정
- 워크플로우 파일에 Firebase 배포 단계 추가
#### 테스터 초대 및 앱 설치 방법
##### 안드로이드 테스터
1. **테스터 초대**:
- Firebase 콘솔에서 테스터 이메일 추가
- 테스터에게 초대 이메일 발송
2. **앱 설치 방법**:
- 테스터는 초대 이메일의 링크를 클릭
- Firebase App Tester 앱 설치 (처음 사용 시)
- 테스트 앱 다운로드 및 설치
- 설치 시 "알 수 없는 출처" 앱 설치 허용 필요
```bash
# 안드로이드 테스터를 위한 안내 메시지 예시
안드로이드 테스트 앱 설치 방법:
1. 초대 이메일의 링크를 클릭하세요
2. Firebase App Tester 앱을 설치하세요 (처음 사용 시)
3. 테스트 앱을 다운로드하고 설치하세요
4. 설정 > 보안 > 알 수 없는 출처에서 설치 허용을 활성화하세요
```
##### iOS 테스터
1. **TestFlight 설정**:
- Apple Developer 계정에서 앱 등록
- 내부 테스터 그룹 생성
2. **테스터 초대**:
- App Store Connect에서 테스터 이메일 추가
- 테스터에게 초대 이메일 발송
3. **앱 설치 방법**:
- 테스터는 초대 이메일의 링크를 클릭
- TestFlight 앱 설치 (App Store에서 다운로드)
- TestFlight를 통해 테스트 앱 설치
```bash
# iOS 테스터를 위한 안내 메시지 예시
iOS 테스트 앱 설치 방법:
1. 초대 이메일의 링크를 클릭하세요
2. App Store에서 TestFlight 앱을 설치하세요
3. TestFlight 앱을 열고 테스트 앱을 설치하세요
```
### GitHub Actions Artifacts를 통한 직접 다운로드
Firebase App Distribution 외에도 GitHub Actions의 Artifacts 기능을 사용하여 빌드 결과물을 직접 다운로드할 수 있습니다.
1. **빌드 결과물 확인**:
- GitHub 저장소의 Actions 탭으로 이동
- 해당 워크플로우 실행 결과 페이지 열기
- Artifacts 섹션에서 APK 또는 IPA 파일 다운로드
2. **안드로이드 APK 설치**:
- 다운로드한 APK 파일을 안드로이드 기기로 전송
- 파일 관리자에서 APK 파일 실행
- 알 수 없는 출처 앱 설치 허용
3. **iOS IPA 설치** (개발자만 가능):
- Apple Developer 계정이 있는 개발자만 가능
- Xcode 또는 Apple Configurator를 사용하여 설치
### QR 코드를 통한 간편 설치
테스터의 편의를 위해 QR 코드를 생성하여 배포할 수도 있습니다:
```yaml
- name: QR 코드 생성
if: github.event.inputs.buildType == 'debug'
run: |
# Firebase 배포 URL에 대한 QR 코드 생성
FIREBASE_URL="https://appdistribution.firebase.dev/i/..."
curl -s "https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=$FIREBASE_URL" > qrcode.png
echo "QR 코드가 생성되었습니다. 테스터는 이 코드를 스캔하여 앱을 설치할 수 있습니다."
- name: QR 코드 저장
if: github.event.inputs.buildType == 'debug'
uses: actions/upload-artifact@v3
with:
name: install-qrcode
path: qrcode.png
```
## 앱스토어 자동 배포
### Google Play Store 배포
Google Play Store에 자동으로 앱을 배포하려면 다음 단계가 필요합니다:
1. **Google Play Console 설정**:
- API 액세스 활성화
- 서비스 계정 생성 및 권한 부여
- JSON 키 다운로드
2. **GitHub Actions 설정**:
- `PLAY_STORE_SERVICE_ACCOUNT_JSON` 시크릿 설정
- 워크플로우 파일에 배포 단계 추가
### Apple App Store 배포
Apple App Store에 자동으로 앱을 배포하려면 Fastlane을 사용합니다:
1. **Fastlane 설정**:
- iOS 디렉토리에 Fastfile 생성
```ruby
default_platform(:ios)
platform :ios do
desc "배포용 iOS 앱 빌드 및 TestFlight 업로드"
lane :release do
setup_ci
# 인증서 및 프로비저닝 프로파일 동기화
match(
type: "appstore",
readonly: true
)
# 버전 업데이트
increment_build_number(
build_number: ENV["BUILD_NUMBER"]
)
# 앱 빌드
build_app(
scheme: "App",
workspace: "App.xcworkspace",
export_method: "app-store"
)
# TestFlight 업로드
upload_to_testflight(
skip_waiting_for_build_processing: true
)
end
end
```
2. **GitHub Actions 설정**:
- App Store Connect API 키 생성 및 GitHub Secrets에 저장
- 워크플로우 파일에 iOS 빌드 및 배포 단계 추가
## 비용 분석
### GitHub Actions 비용
GitHub Actions는 다음과 같은 무료 할당량을 제공합니다:
- **퍼블릭 저장소**: 무제한 무료 사용 가능
- **프라이빗 저장소**:
- GitHub Free: 매월 2,000분의 무료 빌드 시간
- GitHub Pro: 매월 3,000분의 무료 빌드 시간
- GitHub Team: 매월 계정당 3,000분의 무료 빌드 시간
- GitHub Enterprise: 매월 계정당 50,000분의 무료 빌드 시간
### Zellyy Finance 앱의 예상 비용
- **빌드 시간 예상**: 한 번의 워크플로우당 약 7-20분
- **월간 빌드 횟수 시나리오**:
- 하루 1회 빌드: 월 30회 × 15분 = 450분
- 하루 3회 빌드: 월 90회 × 15분 = 1,350분
- 하루 5회 빌드: 월 150회 × 15분 = 2,250분
- **비용 계산**:
- GitHub Free 계정 사용 시: 월 2,000분 무료 (하루 4회 빌드까지 무료)
- 초과 사용 시: 분당 $0.008 (Linux 머신 기준)
### 비용 최적화 전략
1. **캐싱 활용**:
```yaml
- uses: actions/cache@v3
with:
path: |
~/.npm
node_modules
android/.gradle
key: ${{ runner.os }}-build-${{ hashFiles('**/package-lock.json') }}
```
2. **빌드 트리거 최적화**:
```yaml
on:
push:
branches: [ main, develop ]
paths-ignore:
- '**.md'
- 'docs/**'
```
3. **조건부 작업 설정**:
```yaml
- name: Google Play 배포
if: github.ref == 'refs/heads/main' && github.event.inputs.buildType == 'release-aab'
# ...
```
## 문제 해결 및 FAQ
### 자주 발생하는 문제
1. **빌드 실패**:
- 종속성 문제: `npm ci` 대신 `npm install`을 사용해 보세요.
- 캐시 문제: 캐시를 삭제하고 다시 시도하세요.
2. **버전 관리 문제**:
- 버전 파일이 비어 있는 경우: 스크립트가 기본값을 설정하도록 합니다.
- 버전 코드 충돌: 수동으로 버전 코드를 설정하여 해결합니다.
3. **배포 실패**:
- 인증 문제: 서비스 계정 권한을 확인하세요.
- 앱 서명 문제: 키스토어 설정을 확인하세요.
### FAQ
**Q: 워크플로우를 수동으로 실행하려면 어떻게 해야 하나요?**
A: GitHub 저장소의 Actions 탭에서 "Zellyy Finance CI/CD" 워크플로우를 선택하고 "Run workflow" 버튼을 클릭합니다.
**Q: 특정 커밋에서 빌드를 실행하려면 어떻게 해야 하나요?**
A: 해당 커밋으로 체크아웃한 후 수동으로 워크플로우를 실행하거나, GitHub API를 사용하여 특정 커밋에서 워크플로우를 트리거할 수 있습니다.
**Q: 빌드 결과물은 어디에서 찾을 수 있나요?**
A: 워크플로우 실행 페이지의 "Artifacts" 섹션에서 다운로드할 수 있습니다.
**Q: 테스터가 테스트 앱을 설치하는 가장 쉬운 방법은 무엇인가요?**
A: Firebase App Distribution을 사용하는 것이 가장 쉽습니다. 테스터는 이메일로 초대를 받고 링크를 통해 앱을 설치할 수 있습니다. QR 코드를 제공하면 더욱 편리하게 설치할 수 있습니다.
**Q: iOS 테스트 앱 설치 시 개발자 계정이 필요한가요?**
A: TestFlight를 통한 배포의 경우 테스터는 개발자 계정이 필요하지 않습니다. 하지만 개발자는 Apple Developer 계정이 필요합니다. GitHub Actions Artifacts를 통한 직접 설치는 개발자만 가능합니다.