Skip to content

Commit d4c1705

Browse files
authored
chore: CI/CD 세팅 진행중 (테스트 PR) (#17)
* feat: 멀티모듈 지원을 위한 PR용 Gradle 검증 워크플로우 추가 * [BOOK-50] chore: secret properties git 추적에서 제거 * [BOOK-50] chore: gradle/actions/setup-gradle 버전 업그레이드(v3 -> v4) * [BOOK-50] refactor: yml 파일 환경 분리 * [BOOK-50] refactor: secret을 주입한 후 CI를 돌리도록 리팩토링 * [BOOK-50] feat: release-drafter를 이용해 버저닝 태그로 버전관리 할 수 있는 기능 추가 * [BOOK-50] chore: buildSrc, apis - 테스트 컨테이너 관련 의존성 추가 * [BOOK-50] chore: apis - 테스트 환경 YML 파일 생성 * [BOOK-50] test: apis - 테스트 실행 시 실행될 테이블 초기화 스크립트 작성 * [BOOK-50] test: apis - 테스트 컨테이너 관련 어노테이션 명시 * [BOOK-50] chore: batch, gateway - 의존성 방향에 맞게 수정 * [BOOK-50] test: apis - 사용하지 않는 테스트 클래스 삭제 * [BOOK-50] refactor: 멀티라인 배열로 변경 * [BOOK-50] fix: refactor - 중복 설정 값 주입 수정 - jwtTokenProvider에서 알고 있기에 해당 객체에서 get * [BOOK-50] delete: apis, domain, global-utils, infra - 사용하지 않는 파일 삭제 * [BOOK-50] test: admin, batch - 테스트 컨테이너 어노테이션 명시 * [BOOK-50] chore: admin, batch, infra, buildSrc - 의존성 업데이트 및 Flyway 의존성 infra 모듈에 추가 * [BOOK-50] feat: infra, gateway - 각 모듈별로 환경변수를 관리하는 yml 구현 * [BOOK-50] chore: .gitignore에 시크릿 명시 * [BOOK-50] feat: admin, apis, batch - 설정 관리 구조 리팩토링 애플리케이션의 설정 관리 방식을 보다 명확하고 확장성 있게 개선했습니다. 주요 변경 사항: 1. **프로파일 그룹 도입 (`spring.profiles.group`)** - `dev`, `prod`, `test` 등 각 환경에서 필요한 기능별 설정(persistence, jwt, redis 등)을 그룹으로 묶어 관리합니다. - 이를 통해 환경별 구성 요소를 한눈에 파악하고 쉽게 조합할 수 있습니다. 2. **민감 정보 외부 분리** - 데이터베이스 접속 정보, JWT 키 등 민감 정보를 프로젝트 루트의 `secret` 디렉토리로 분리했습니다. - `spring.config.import`와 `file:` 경로를 사용하여 각 환경에 맞는 시크릿 파일을 안전하게 로드합니다. - 이 구조는 `.gitignore`를 통해 Git에 민감 정보가 커밋되는 것을 방지하고, CI/CD 환경에서 외부 주입을 용이하게 합니다. * [BOOK-50] refactor: CI 스크립트 리팩토링 * [BOOK-50] refactor: infra - redis password 설정 추가 * [BOOK-50] chore: .gitignore에 secret 폴더 표시 * [BOOK-50] test: admin, batch, apis - Testcontainers 어노테이션은 컨테이너를 직접 관리하는 클래스에서 명시하도록 변경 * [BOOK-50] chore: redis 컨테이너 의존성 추가 * [BOOK-50] chore: apis, infra - 테스트 컨테이너 의존성 추가 * [BOOK-50] chore: admin, apis, batch, infra - test 프로필에서 redis 설정 제거 - 테스트 실행 시 실제 Redis 설정 파일이나 환경변수에 의존하지 않고, Testcontainers로 실행되는 Redis 컨테이너를 사용하기 위해 test 프로필에서 redis 설정을 제외했습니다. * [BOOK-50] test: infra - Redis 테스트 설정 클래스 도입 - JUnit 5 + Testcontainers 기반의 Redis 테스트 설정 클래스를 추가했습니다. - 테스트 클래스에서 이 클래스를 상속하면 Redis 컨테이너가 자동으로 실행되며, 컨테이너의 host/port가 Spring 프로퍼티에 동적으로 주입됩니다. - 추후, 모듈 간 테스트 코드 접근 문제로 인해, 추후 Gradle Test Fixture 도입이 필요합니다. * [BOOK-50] chore: build continue 옵션 ci에서 제거 * [BOOK-50] feat: dev/prod 환경 CI/CD 스크립트 작성 * [BOOK-50] refactor: 코드리뷰 반영 * [BOOK-50] refactor: 도커 관련 정보도 넘기도록 변경 * [BOOK-50] chore: 사용하지 않는 커맨드 제거 * [BOOK-50] chore: infra - dev환경에서 flyway를 이용하지 않도록 변경 * [BOOK-50] chore: 스크립트 위치에 맞게 변경
1 parent e45c994 commit d4c1705

File tree

28 files changed

+645
-73
lines changed

28 files changed

+645
-73
lines changed

.github/release-drafter-config.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name-template: 'v$RESOLVED_VERSION'
2+
tag-template: 'v$RESOLVED_VERSION'
3+
4+
categories:
5+
- title: '✨ 새로운 기능이 추가되었어요'
6+
labels: ['✨ feat']
7+
8+
- title: '🐞 버그가 수정되었어요'
9+
labels: ['🐞 fix']
10+
11+
- title: '🔨 코드 리팩터링이 있었어요'
12+
labels: ['🔨 refactor']
13+
14+
- title: '📃 문서가 변경되었어요'
15+
labels: ['📃 docs']
16+
17+
- title: '⚙️ 설정이나 기타 사소한 작업이 있었어요'
18+
labels: ['⚙️ chore']
19+
20+
- title: '✅ 테스트가 추가되었어요'
21+
labels: ['✅ test']
22+
23+
- title: '🎨 스타일 관련 수정이 있었어요'
24+
labels: ['🎨 style']
25+
26+
change-template: '- $TITLE (#$NUMBER) @$AUTHOR'
27+
template: |
28+
## 🚀 이번 버전의 변경사항
29+
---
30+
$CHANGES
31+
32+
no-changes-template: '변경사항이 없어요 🎉'
33+
34+
version-resolver:
35+
major:
36+
labels: ['1️⃣ major']
37+
minor:
38+
labels: ['2️⃣ minor']
39+
patch:
40+
labels: ['3️⃣ patch']
41+
default: patch

.github/workflows/ci-pr.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: CI - Pull Request
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- develop
7+
- main
8+
types:
9+
- opened
10+
- synchronize
11+
- reopened
12+
13+
concurrency:
14+
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
15+
cancel-in-progress: true
16+
17+
jobs:
18+
build-validation:
19+
runs-on: ubuntu-24.04
20+
timeout-minutes: 10
21+
22+
steps:
23+
- name: Checkout code
24+
uses: actions/checkout@v4
25+
with:
26+
fetch-depth: 0 # SonarCloud를 위한 전체 히스토리 가져오기
27+
28+
- name: Create secret properties files from GitHub Secrets
29+
run: |
30+
mkdir ./secret
31+
echo "${{ secrets.DEV_SECRET_PROPERTIES }}" > ./secret/application-dev-secret.properties
32+
echo "${{ secrets.PROD_SECRET_PROPERTIES }}" > ./secret/application-prod-secret.properties
33+
echo "${{ secrets.TEST_SECRET_PROPERTIES }}" > ./secret/application-test-secret.properties
34+
chmod 600 ./secret/*
35+
36+
- name: Set up JDK 21
37+
uses: actions/setup-java@v4
38+
with:
39+
java-version: '21'
40+
distribution: 'temurin'
41+
42+
- name: Cache Gradle packages
43+
uses: gradle/actions/setup-gradle@v4
44+
with:
45+
gradle-home-cache-cleanup: true
46+
47+
- name: Grant execute permission for gradlew
48+
run: chmod +x gradlew
49+
50+
- name: Run Gradle check (fast validation)
51+
run: ./gradlew check --parallel --build-cache

.github/workflows/dev-ci-cd.yml

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
name: Dev CI/CD - Build and Deploy
2+
3+
on:
4+
push:
5+
branches:
6+
- develop
7+
8+
concurrency:
9+
group: ${{ github.workflow }}-${{ github.ref }}
10+
cancel-in-progress: false
11+
12+
env:
13+
REGISTRY: docker.io
14+
IMAGE_NAME: ninecraft0523/ninecraft-server
15+
16+
jobs:
17+
build-and-push:
18+
runs-on: ubuntu-24.04
19+
timeout-minutes: 20
20+
outputs:
21+
tags: ${{ steps.meta.outputs.tags }}
22+
23+
steps:
24+
- name: Checkout code
25+
uses: actions/checkout@v4
26+
27+
- name: Inject application-secret.properties from Secrets
28+
run: |
29+
mkdir ./secret
30+
echo "${{ secrets.DEV_SECRET_PROPERTIES }}" > ./secret/application-dev-secret.properties
31+
echo "${{ secrets.PROD_SECRET_PROPERTIES }}" > ./secret/application-prod-secret.properties
32+
echo "${{ secrets.TEST_SECRET_PROPERTIES }}" > ./secret/application-test-secret.properties
33+
chmod 600 ./secret/*
34+
35+
- name: Set up JDK 21
36+
uses: actions/setup-java@v4
37+
with:
38+
java-version: '21'
39+
distribution: 'temurin'
40+
cache: gradle
41+
42+
- name: Setup Gradle
43+
uses: gradle/actions/setup-gradle@v4
44+
with:
45+
gradle-home-cache-cleanup: true
46+
47+
- name: Grant execute permission for gradlew
48+
run: chmod +x gradlew
49+
50+
- name: Run full Gradle build
51+
run: ./gradlew build --parallel --build-cache
52+
53+
- name: Extract metadata for Docker
54+
id: meta
55+
uses: docker/metadata-action@v5
56+
with:
57+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
58+
tags: |
59+
type=raw,value=development-latest
60+
61+
- name: Set up Docker Buildx
62+
uses: docker/setup-buildx-action@v3
63+
64+
- name: Log in to Docker Hub
65+
uses: docker/login-action@v3
66+
with:
67+
username: ${{ secrets.DOCKERHUB_USERNAME }}
68+
password: ${{ secrets.DOCKERHUB_TOKEN }}
69+
70+
- name: Build and push Docker image
71+
uses: docker/build-push-action@v6
72+
with:
73+
context: .
74+
platforms: linux/amd64,linux/arm64
75+
push: true
76+
tags: ${{ steps.meta.outputs.tags }}
77+
cache-from: type=gha
78+
cache-to: type=gha,mode=max
79+
80+
deploy-dev:
81+
needs: build-and-push
82+
runs-on: ubuntu-24.04
83+
timeout-minutes: 10
84+
environment: development
85+
86+
steps:
87+
- name: Deploy to Development Server
88+
uses: appleboy/[email protected]
89+
with:
90+
host: ${{ secrets.DEV_HOST }}
91+
username: ${{ secrets.DEV_USERNAME }}
92+
key: ${{ secrets.DEV_SSH_KEY }}
93+
port: ${{ secrets.DEV_PORT }}
94+
script: |
95+
cd /opt/app
96+
export DOCKERHUB_USERNAME="${{ secrets.DOCKERHUB_USERNAME }}"
97+
export DOCKERHUB_TOKEN="${{ secrets.DOCKERHUB_TOKEN }}"
98+
export IMAGE_TAG="${{ needs.build-and-push.outputs.tags }}"
99+
cd ~/deploy
100+
chmod +x ./deploy.sh
101+
./deploy.sh
102+

.github/workflows/prod-ci-cd.yml

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
name: Prod CI/CD - Build and Deploy
2+
3+
on:
4+
release:
5+
types:
6+
- published # Release가 published 될 때만 실행
7+
8+
concurrency:
9+
group: ${{ github.workflow }}-${{ github.ref }}
10+
cancel-in-progress: false
11+
12+
env:
13+
REGISTRY: docker.io
14+
IMAGE_NAME: ninecraft0523/ninecraft-server
15+
16+
jobs:
17+
build-and-push:
18+
runs-on: ubuntu-24.04
19+
timeout-minutes: 25
20+
outputs:
21+
image-digest: ${{ steps.build.outputs.digest }}
22+
version: ${{ steps.meta.outputs.version }}
23+
tags: ${{ steps.meta.outputs.tags }}
24+
25+
steps:
26+
- name: Checkout code
27+
uses: actions/checkout@v4
28+
29+
- name: Inject application-secret.properties from Secrets
30+
run: |
31+
mkdir ./secret
32+
echo "${{ secrets.DEV_SECRET_PROPERTIES }}" > ./secret/application-dev-secret.properties
33+
echo "${{ secrets.PROD_SECRET_PROPERTIES }}" > ./secret/application-prod-secret.properties
34+
echo "${{ secrets.TEST_SECRET_PROPERTIES }}" > ./secret/application-test-secret.properties
35+
chmod 600 ./secret/*
36+
37+
- name: Set up JDK 21
38+
uses: actions/setup-java@v4
39+
with:
40+
java-version: '21'
41+
distribution: 'temurin'
42+
cache: gradle
43+
44+
- name: Setup Gradle
45+
uses: gradle/actions/setup-gradle@v4
46+
with:
47+
gradle-home-cache-cleanup: true
48+
49+
- name: Grant execute permission for gradlew
50+
run: chmod +x gradlew
51+
52+
- name: Run full Gradle build with strict validation
53+
run: ./gradlew build --parallel --build-cache --warning-mode all
54+
55+
- name: Extract metadata for Docker
56+
id: meta
57+
uses: docker/metadata-action@v5
58+
with:
59+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
60+
tags: |
61+
type=semver,pattern={{version}}
62+
type=raw,value=production-latest
63+
64+
- name: Set up Docker Buildx
65+
uses: docker/setup-buildx-action@v3
66+
67+
- name: Log in to Docker Hub
68+
uses: docker/login-action@v3
69+
with:
70+
username: ${{ secrets.DOCKERHUB_USERNAME }}
71+
password: ${{ secrets.DOCKERHUB_TOKEN }}
72+
73+
- name: Build and push Docker image
74+
id: build
75+
uses: docker/build-push-action@v6
76+
with:
77+
context: .
78+
platforms: linux/amd64,linux/arm64
79+
push: true
80+
tags: ${{ steps.meta.outputs.tags }}
81+
cache-from: type=gha
82+
cache-to: type=gha,mode=max
83+
84+
deploy-prod:
85+
needs: build-and-push
86+
runs-on: ubuntu-24.04
87+
timeout-minutes: 20
88+
environment: production
89+
90+
steps:
91+
- name: Deploy to Production Server
92+
uses: appleboy/[email protected]
93+
with:
94+
host: ${{ secrets.PROD_HOST }}
95+
username: ${{ secrets.PROD_USERNAME }}
96+
key: ${{ secrets.PROD_SSH_KEY }}
97+
port: ${{ secrets.PROD_PORT }}
98+
script: |
99+
cd /opt/app
100+
export DOCKERHUB_USERNAME="${{ secrets.DOCKERHUB_USERNAME }}"
101+
export DOCKERHUB_TOKEN="${{ secrets.DOCKERHUB_TOKEN }}"
102+
export IMAGE_TAG="$(echo "${{ needs.build-and-push.outputs.tags }}" | head -n1)"
103+
export VERSION_TAG="${{ needs.build-and-push.outputs.version }}"
104+
export RELEASE_VERSION="${{ github.event.release.tag_name }}"
105+
cd ~/deploy
106+
chmod +x ./deploy.sh
107+
./deploy.sh
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: Release Drafter
2+
on:
3+
push:
4+
branches:
5+
- main
6+
jobs:
7+
update_release_draft:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: release-drafter/release-drafter@v6
11+
with:
12+
config-name: release-drafter-config.yml
13+
env:
14+
GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }}

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,12 @@ gradle-app.setting
168168
# Java heap dump
169169
*.hprof
170170

171+
### User Customization ###
172+
# node_modules
171173
node_modules/
172174

175+
# secret
176+
application-*-secret.properties
177+
secret/
178+
173179
# End of https://www.toptal.com/developers/gitignore/api/intellij,kotlin,gradle

admin/build.gradle.kts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@ dependencies {
66
implementation(project(Dependencies.Projects.GLOBAL_UTILS))
77

88
implementation(Dependencies.Spring.BOOT_STARTER_WEB)
9-
implementation(Dependencies.Spring.BOOT_STARTER_DATA_JPA)
109
implementation(Dependencies.Spring.BOOT_STARTER_SECURITY)
1110
implementation(Dependencies.Spring.BOOT_STARTER_VALIDATION)
1211
implementation(Dependencies.Spring.BOOT_STARTER_ACTUATOR)
12+
testImplementation(Dependencies.Spring.BOOT_STARTER_TEST)
13+
1314
implementation(Dependencies.Database.MYSQL_CONNECTOR)
1415

15-
testImplementation(Dependencies.Spring.BOOT_STARTER_TEST)
16+
implementation(Dependencies.Swagger.SPRINGDOC_OPENAPI_STARTER_WEBMVC_UI)
17+
18+
testImplementation(Dependencies.TestContainers.MYSQL)
19+
testImplementation(Dependencies.TestContainers.JUNIT_JUPITER)
1620
}
1721

1822
tasks {

0 commit comments

Comments
 (0)