Skip to content

Commit 820853f

Browse files
Darren4641darren
andauthored
Feat/#7 (#18)
* feat: User Entity 생성 및 UserPrincipal 세팅 * feat: ExceptionHandler 및 BaseResponse 세팅 * feat: Swagger 403/500 이슈 해결 및 auth 패키지 분리 * fix: spotlessApply * fix: @repository 제거 * fix: security 관련 설정 user 패키지로 이동 * fix: User Entity 및 repository 관련 파일 user 패키지로 이동 * fix: spotless 적용 * feat: Jasypt 설정 추가 * feat: kakao oauth idToken 발급 로직 추가 (테스트용) * fix: UseCase 어노테이션 추가 및 디렉토리 구조 변경 * feat: kakao oauth oidc 추출 * feat: k3s 배포를 위한 Dockerfile 생성 * feat: 카카오 OIDC 회원가입 기능 구현 * feat: 예외 addMessage 메서드 제거 * refactor: signup -> register 네이밍 변경 * fix: transactionRunner 추가 * fix: spotless 적용 * fix: login 기능 구현 1차 * fix: refreshToken 발행 추가 * fix: refreshToken을 통해 accessToken 갱신 API 추가 * fix: JasyptConfig profile 지정 * feat: CustomerUserDetailService 제거 (불필요) * feat: spotless 적용 * feat: converter 적용 * feat: E2E TEST 코드 추가 * feat: E2E TEST 코드 추가 * fix: JasyptTest 테스트코드 yml 의존성 제거 * feat: ci discord 알림 추가 * ci: 빌드 최적화 * ci: k3s 강제 재시작 적용 * fix: kakao oauth nativeID로 변경 * ci: 배포후 downtime 0로 변경 (health check 추가) * fix: app.version 공통 application.yaml로 이동 * fix: JasyptUtil 파일 제거 * fix: RestClientConfig 파일 infra 디렉토리로 이동 * fix: OIDCPublicKeysResponse 변수 var -> val 변경 * fix: KakaoClientResponse 주석 제거 * fix: Valid 어노테이션 @field로 변경 * fix: contract 디렉토리 생성 후 response 이동 * fix: ci yaml staging 브랜치로 변경 * fix: spotlessApply 적용 --------- Co-authored-by: darren <[email protected]>
1 parent cef3d3e commit 820853f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1803
-305
lines changed

.dockerignore

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Git
2+
.git
3+
.gitignore
4+
.gitattributes
5+
.github
6+
7+
# Gradle
8+
.gradle
9+
build/
10+
!build/libs/*.jar
11+
!gradle/wrapper/gradle-wrapper.jar
12+
!gradle/wrapper/gradle-wrapper.properties
13+
14+
# IDE
15+
.idea
16+
*.iml
17+
*.iws
18+
*.ipr
19+
.vscode
20+
*.swp
21+
*.swo
22+
*~
23+
24+
# OS
25+
.DS_Store
26+
Thumbs.db
27+
28+
# Logs
29+
*.log
30+
31+
# Local data
32+
postgres_data/
33+
localstack_data/
34+
35+
# Docker
36+
Dockerfile
37+
.dockerignore
38+
docker-compose.yaml
39+
40+
# Documentation
41+
README.md
42+
*.md
43+
44+
# Kotlin
45+
.kotlin
46+
47+
# Test
48+
src/test/
49+
50+
# Misc
51+
Makefile
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
name: Deploy to Staging (K3s)
2+
3+
on:
4+
push:
5+
branches:
6+
- staging
7+
workflow_dispatch: # 수동 실행 가능
8+
9+
jobs:
10+
build-and-deploy:
11+
name: Build, Test and Deploy to K3s
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- name: Checkout code
16+
uses: actions/checkout@v4
17+
18+
- name: Set up JDK 21
19+
uses: actions/setup-java@v4
20+
with:
21+
java-version: 21
22+
distribution: 'temurin'
23+
cache: 'gradle'
24+
25+
- name: Grant execute permission for gradlew
26+
run: chmod +x gradlew
27+
28+
- name: Run tests
29+
run: ./gradlew test --no-daemon
30+
31+
- name: Build with Gradle
32+
run: ./gradlew bootJar --no-daemon -x test
33+
34+
- name: Set up Docker Buildx
35+
uses: docker/setup-buildx-action@v3
36+
37+
- name: Login to Docker Registry
38+
uses: docker/login-action@v3
39+
with:
40+
username: ${{ secrets.DOCKER_USERNAME }}
41+
password: ${{ secrets.DOCKER_PASSWORD }}
42+
43+
- name: Extract version
44+
id: version
45+
run: |
46+
VERSION=$(./gradlew properties --no-daemon --console=plain -q | grep "^version:" | awk '{print $2}')
47+
echo "version=$VERSION" >> $GITHUB_OUTPUT
48+
echo "short_sha=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT
49+
50+
- name: Build and push Docker image
51+
uses: docker/build-push-action@v5
52+
with:
53+
context: .
54+
push: true
55+
tags: |
56+
${{ secrets.DOCKER_USERNAME }}/yapp-dev:${{ steps.version.outputs.version }}-${{ steps.version.outputs.short_sha }}
57+
${{ secrets.DOCKER_USERNAME }}/yapp-dev:latest
58+
cache-from: type=gha
59+
cache-to: type=gha,mode=max
60+
61+
- name: Discord notification - Deployment started
62+
if: success()
63+
run: |
64+
curl -H "Content-Type: application/json" \
65+
-d '{
66+
"embeds": [{
67+
"title": "🚀 Staging 배포 시작",
68+
"description": "K3s 배포를 시작합니다",
69+
"color": 3447003,
70+
"fields": [
71+
{
72+
"name": "브랜치",
73+
"value": "'"${{ github.ref_name }}"'",
74+
"inline": true
75+
},
76+
{
77+
"name": "커밋",
78+
"value": "'"${{ steps.version.outputs.short_sha }}"'",
79+
"inline": true
80+
},
81+
{
82+
"name": "작성자",
83+
"value": "'"${{ github.actor }}"'",
84+
"inline": true
85+
},
86+
{
87+
"name": "버전",
88+
"value": "'"${{ steps.version.outputs.version }}-${{ steps.version.outputs.short_sha }}"'",
89+
"inline": false
90+
},
91+
{
92+
"name": "커밋 메시지",
93+
"value": "'"$(git log -1 --pretty=%B | head -n 1)"'",
94+
"inline": false
95+
}
96+
],
97+
"timestamp": "'"$(date -u +%Y-%m-%dT%H:%M:%S.000Z)"'"
98+
}]
99+
}' \
100+
${{ secrets.DISCORD_WEBHOOK_URL }}
101+
102+
- name: Deploy to K3s (On-premise) with Zero-Downtime
103+
id: deploy
104+
uses: appleboy/[email protected]
105+
with:
106+
host: ${{ secrets.SSH_HOST }}
107+
username: ${{ secrets.SSH_USER }}
108+
password: ${{ secrets.SSH_PASSWORD }}
109+
port: ${{ secrets.SSH_PORT }}
110+
script: |
111+
echo "🚀 Starting Zero-Downtime deployment to K3s..."
112+
113+
# K3s deployment 디렉토리로 이동
114+
cd /home/yapp/k3s/staging
115+
116+
# 현재 실행 중인 이미지 확인
117+
CURRENT_IMAGE=$(kubectl get deployment yapp-app-staging -n staging -o jsonpath='{.spec.template.spec.containers[0].image}' 2>/dev/null || echo "none")
118+
echo "📌 Current image: $CURRENT_IMAGE"
119+
120+
# 이미지 태그 업데이트
121+
NEW_IMAGE="${{ secrets.DOCKER_USERNAME }}/yapp-dev:${{ steps.version.outputs.version }}-${{ steps.version.outputs.short_sha }}"
122+
echo "📦 New image: $NEW_IMAGE"
123+
sed -i "s|image: .*yapp-dev:.*|image: $NEW_IMAGE|g" deployment.yaml
124+
125+
# K3s에 배포 적용 (Rolling Update 자동 실행)
126+
echo "🔄 Applying deployment... Rolling update will start automatically"
127+
kubectl apply -f deployment.yaml
128+
129+
# 배포 상태 확인 (새 파드가 완전히 준비될 때까지 대기)
130+
echo "⏳ Waiting for new pods to be ready..."
131+
if kubectl rollout status deployment/yapp-app-staging -n staging --timeout=10m; then
132+
echo "✅ Rollout completed successfully!"
133+
134+
# 배포된 파드 정보 확인
135+
echo "📊 Pod status:"
136+
kubectl get pods -n staging -l app=yapp-app-staging
137+
138+
# 최종 이미지 확인
139+
DEPLOYED_IMAGE=$(kubectl get deployment yapp-app-staging -n staging -o jsonpath='{.spec.template.spec.containers[0].image}')
140+
echo "✅ Deployment completed! Deployed image: $DEPLOYED_IMAGE"
141+
else
142+
echo "❌ Rollout failed or timed out!"
143+
kubectl get pods -n staging -l app=yapp-app-staging
144+
exit 1
145+
fi
146+
147+
- name: Discord notification - Deployment success
148+
if: success()
149+
run: |
150+
curl -H "Content-Type: application/json" \
151+
-d '{
152+
"embeds": [{
153+
"title": "✅ Staging 배포 성공",
154+
"description": "K3s 배포가 성공적으로 완료되었습니다",
155+
"color": 5763719,
156+
"fields": [
157+
{
158+
"name": "브랜치",
159+
"value": "'"${{ github.ref_name }}"'",
160+
"inline": true
161+
},
162+
{
163+
"name": "커밋",
164+
"value": "'"${{ steps.version.outputs.short_sha }}"'",
165+
"inline": true
166+
},
167+
{
168+
"name": "작성자",
169+
"value": "'"${{ github.actor }}"'",
170+
"inline": true
171+
},
172+
{
173+
"name": "배포 버전",
174+
"value": "'"${{ steps.version.outputs.version }}-${{ steps.version.outputs.short_sha }}"'",
175+
"inline": false
176+
},
177+
{
178+
"name": "배포 링크",
179+
"value": "[GitHub Actions](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})",
180+
"inline": false
181+
}
182+
],
183+
"timestamp": "'"$(date -u +%Y-%m-%dT%H:%M:%S.000Z)"'"
184+
}]
185+
}' \
186+
${{ secrets.DISCORD_WEBHOOK_URL }}
187+
188+
- name: Discord notification - Deployment failed
189+
if: failure()
190+
run: |
191+
curl -H "Content-Type: application/json" \
192+
-d '{
193+
"embeds": [{
194+
"title": "❌ Staging 배포 실패",
195+
"description": "K3s 배포 중 오류가 발생했습니다",
196+
"color": 15158332,
197+
"fields": [
198+
{
199+
"name": "브랜치",
200+
"value": "'"${{ github.ref_name }}"'",
201+
"inline": true
202+
},
203+
{
204+
"name": "커밋",
205+
"value": "'"${{ steps.version.outputs.short_sha }}"'",
206+
"inline": true
207+
},
208+
{
209+
"name": "작성자",
210+
"value": "'"${{ github.actor }}"'",
211+
"inline": true
212+
},
213+
{
214+
"name": "실패 로그",
215+
"value": "[GitHub Actions 확인](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})",
216+
"inline": false
217+
}
218+
],
219+
"timestamp": "'"$(date -u +%Y-%m-%dT%H:%M:%S.000Z)"'"
220+
}]
221+
}' \
222+
${{ secrets.DISCORD_WEBHOOK_URL }}

Dockerfile

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Layer extraction stage
2+
FROM eclipse-temurin:21-jre-alpine AS builder
3+
4+
WORKDIR /app
5+
6+
# GitHub Actions에서 빌드된 JAR 파일 복사
7+
COPY build/libs/*.jar app.jar
8+
9+
# Spring Boot Layered JAR에서 레이어 추출
10+
RUN java -Djarmode=layertools -jar app.jar extract
11+
12+
# Runtime stage
13+
FROM eclipse-temurin:21-jre-alpine
14+
15+
WORKDIR /app
16+
17+
# 보안을 위해 non-root 사용자 생성
18+
RUN addgroup -S spring && adduser -S spring -G spring
19+
20+
# 레이어별로 복사 (변경 빈도가 낮은 순서대로)
21+
# 1. dependencies: 외부 라이브러리 (거의 변경 안 됨)
22+
COPY --from=builder --chown=spring:spring /app/dependencies/ ./
23+
24+
# 2. spring-boot-loader: Spring Boot 로더
25+
COPY --from=builder --chown=spring:spring /app/spring-boot-loader/ ./
26+
27+
# 3. snapshot-dependencies: SNAPSHOT 의존성
28+
COPY --from=builder --chown=spring:spring /app/snapshot-dependencies/ ./
29+
30+
# 4. application: 애플리케이션 코드 (자주 변경됨)
31+
COPY --from=builder --chown=spring:spring /app/application/ ./
32+
33+
# non-root 사용자로 전환
34+
USER spring:spring
35+
36+
# 환경변수 설정 (기본값, 런타임에 오버라이드 가능)
37+
ENV SPRING_PROFILES_ACTIVE=staging
38+
ENV JASYPT_PASSWORD=""
39+
40+
# 애플리케이션 실행
41+
# Layered JAR는 org.springframework.boot.loader.launch.JarLauncher를 사용
42+
ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]

build.gradle.kts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ dependencies {
4545
// Spring Boot
4646
implementation("org.springframework.boot:spring-boot-starter-web")
4747
implementation("org.springframework.boot:spring-boot-starter-validation")
48+
implementation("org.springframework.boot:spring-boot-starter-actuator")
4849

4950
// Kotlin
5051
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
@@ -137,3 +138,10 @@ tasks.withType<Test> {
137138
tasks.jar {
138139
enabled = false
139140
}
141+
142+
tasks.bootJar {
143+
// Spring Boot Layered JAR 활성화 (Docker 캐싱 최적화)
144+
layered {
145+
enabled = true
146+
}
147+
}

0 commit comments

Comments
 (0)