Compare commits

..

2 Commits

Author SHA1 Message Date
Hyowon Yang 3855e78abf gradlew 실행 권한 설정 가이드 추가
- VM 환경에서 permission denied 오류 해결 방법 추가
- chmod +x gradlew 명령어 및 대체 방법(bash gradlew) 안내
- JAR 빌드 및 재배포 섹션에 권한 설정 단계 추가

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-27 16:43:11 +09:00
Hyowon Yang d223510198 컨테이너배포설정
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-27 16:25:26 +09:00
48 changed files with 1003 additions and 1402 deletions
@@ -1,7 +1,3 @@
---
command: "/deploy-actions-cicd-guide-back"
---
@cicd @cicd
'백엔드GitHubActions파이프라인작성가이드'에 따라 GitHub Actions를 이용한 CI/CD 가이드를 작성해 주세요. '백엔드GitHubActions파이프라인작성가이드'에 따라 GitHub Actions를 이용한 CI/CD 가이드를 작성해 주세요.
프롬프트에 '[실행정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시해 주세요. 프롬프트에 '[실행정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시해 주세요.
@@ -1,7 +1,3 @@
---
command: "/deploy-actions-cicd-guide-front"
---
@cicd @cicd
'프론트엔드GitHubActions파이프라인작성가이드'에 따라 GitHub Actions를 이용한 CI/CD 가이드를 작성해 주세요. '프론트엔드GitHubActions파이프라인작성가이드'에 따라 GitHub Actions를 이용한 CI/CD 가이드를 작성해 주세요.
프롬프트에 '[실행정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시해 주세요. 프롬프트에 '[실행정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시해 주세요.
@@ -1,6 +1,2 @@
---
command: "/deploy-build-image-back"
---
@cicd @cicd
'백엔드컨테이너이미지작성가이드'에 따라 컨테이너 이미지를 작성해 주세요. '백엔드컨테이너이미지작성가이드'에 따라 컨테이너 이미지를 작성해 주세요.
@@ -1,6 +1,2 @@
---
command: "/deploy-build-image-front"
---
@cicd @cicd
'프론트엔드컨테이너이미지작성가이드'에 따라 컨테이너 이미지를 작성해 주세요. '프론트엔드컨테이너이미지작성가이드'에 따라 컨테이너 이미지를 작성해 주세요.
+23 -49
View File
@@ -1,81 +1,55 @@
--- 배포 작업 순서
command: "/deploy-help"
---
# 배포 작업 순서
## 1단계: 컨테이너 이미지 작성 ## 1단계: 컨테이너 이미지 작성
### 백엔드 ### 백엔드
```
/deploy-build-image-back /deploy-build-image-back
``` - 백엔드컨테이너이미지작성가이드에 따라 컨테이너 이미지를 작성합니다
- 백엔드컨테이너이미지작성가이드를 참고하여 컨테이너 이미지를 빌드합니다
### 프론트엔드 ### 프론트엔드
```
/deploy-build-image-front /deploy-build-image-front
``` - 프론트엔드컨테이너이미지작성가이드에 따라 컨테이너 이미지를 작성합니다
- 프론트엔드컨테이너이미지작성가이드를 참고하여 컨테이너 이미지를 빌드합니다
## 2단계: 컨테이너 실행 가이드 작성 ## 2단계: 컨테이너 실행 가이드 작성
### 백엔드 ### 백엔드
```
/deploy-run-container-guide-back /deploy-run-container-guide-back
``` - 백엔드컨테이너실행방법가이드에 따라 실행 가이드를 작성합니다
- 백엔드컨테이너실행방법가이드를 참고하여 컨테이너 실행 방법을 작성합니다 - [실행정보] 섹션에 ACR명, VM 정보를 제공해야 합니다
- 실행정보(ACR명, VM정보)가 필요합니다
### 프론트엔드 ### 프론트엔드
```
/deploy-run-container-guide-front /deploy-run-container-guide-front
``` - 프론트엔드컨테이너실행방법가이드에 따라 실행 가이드를 작성합니다
- 프론트엔드컨테이너실행방법가이드를 참고하여 컨테이너 실행 방법을 작성합니다 - [실행정보] 섹션에 시스템명, ACR명, VM 정보를 제공해야 합니다
- 실행정보(시스템명, ACR명, VM정보)가 필요합니다
## 3단계: Kubernetes 배포 가이드 작성 ## 3단계: 쿠버네티스 배포 가이드 작성
### 백엔드 ### 백엔드
```
/deploy-k8s-guide-back /deploy-k8s-guide-back
``` - 백엔드배포가이드에 따라 K8s 배포 가이드를 작성합니다
- 백엔드배포가이드를 참고하여 쿠버네티스 배포 방법을 작성합니다 - [실행정보] 섹션에 ACR명, k8s명, 네임스페이스, 리소스 정보를 제공해야 합니다
- 실행정보(ACR명, k8s명, 네임스페이스, 리소스 설정)가 필요합니다
### 프론트엔드 ### 프론트엔드
```
/deploy-k8s-guide-front /deploy-k8s-guide-front
``` - 프론트엔드배포가이드에 따라 K8s 배포 가이드를 작성합니다
- 프론트엔드배포가이드를 참고하여 쿠버네티스 배포 방법을 작성합니다 - [실행정보] 섹션에 시스템명, ACR명, k8s명, 네임스페이스, 리소스, Gateway Host 정보를 제공해야 합니다
- 실행정보(시스템명, ACR명, k8s명, 네임스페이스, Gateway Host, 리소스 설정)가 필요합니다
## 4단계: CI/CD 파이프라인 ## 4단계: CI/CD 파이프라인
### Jenkins CI/CD
### Jenkins 사용 시
#### 백엔드 #### 백엔드
```
/deploy-jenkins-cicd-guide-back /deploy-jenkins-cicd-guide-back
``` - 백엔드Jenkins파이프라인작성가이드에 따라 작성합니다
- 백엔드Jenkins파이프라인작성가이드를 참고하여 Jenkins CI/CD 파이프라인을 구성합니다 - [실행정보] 섹션에 ACR_NAME, RESOURCE_GROUP, AKS_CLUSTER, NAMESPACE 정보를 제공해야 합니다
#### 프론트엔드 #### 프론트엔드
```
/deploy-jenkins-cicd-guide-front /deploy-jenkins-cicd-guide-front
``` - 프론트엔드Jenkins파이프라인작성가이드에 따라 작성합니다
- 프론트엔드Jenkins파이프라인작성가이드를 참고하여 Jenkins CI/CD 파이프라인을 구성합니다 - [실행정보] 섹션에 SYSTEM_NAME, ACR_NAME, RESOURCE_GROUP, AKS_CLUSTER, NAMESPACE 정보를 제공해야 합니다
### GitHub Actions 사용 시 ### GitHub Actions CI/CD
#### 백엔드 #### 백엔드
```
/deploy-actions-cicd-guide-back /deploy-actions-cicd-guide-back
``` - 백엔드GitHubActions파이프라인작성가이드에 따라 작성합니다
- 백엔드GitHubActions파이프라인작성가이드를 참고하여 GitHub Actions CI/CD 파이프라인을 구성합니다 - [실행정보] 섹션에 ACR_NAME, RESOURCE_GROUP, AKS_CLUSTER, NAMESPACE 정보를 제공해야 합니다
#### 프론트엔드 #### 프론트엔드
```
/deploy-actions-cicd-guide-front /deploy-actions-cicd-guide-front
``` - 프론트엔드GitHubActions파이프라인작성가이드에 따라 작성합니다
- 프론트엔드GitHubActions파이프라인작성가이드를 참고하여 GitHub Actions CI/CD 파이프라인을 구성합니다 - [실행정보] 섹션에 SYSTEM_NAME, ACR_NAME, RESOURCE_GROUP, AKS_CLUSTER, NAMESPACE 정보를 제공해야 합니다
## 참고사항
- 각 명령 실행 전 필요한 실행정보를 프롬프트에 포함해야 합니다
- 실행정보가 없으면 안내 메시지가 표시되며 작업이 중단됩니다
- CI/CD 도구는 Jenkins 또는 GitHub Actions 중 선택하여 사용합니다
@@ -1,7 +1,3 @@
---
command: "/deploy-jenkins-cicd-guide-back"
---
@cicd @cicd
'백엔드Jenkins파이프라인작성가이드'에 따라 Jenkins를 이용한 CI/CD 가이드를 작성해 주세요. '백엔드Jenkins파이프라인작성가이드'에 따라 Jenkins를 이용한 CI/CD 가이드를 작성해 주세요.
프롬프트에 '[실행정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시해 주세요. 프롬프트에 '[실행정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시해 주세요.
@@ -1,7 +1,3 @@
---
command: "/deploy-jenkins-cicd-guide-front"
---
@cicd @cicd
'프론트엔드Jenkins파이프라인작성가이드'에 따라 Jenkins를 이용한 CI/CD 가이드를 작성해 주세요. '프론트엔드Jenkins파이프라인작성가이드'에 따라 Jenkins를 이용한 CI/CD 가이드를 작성해 주세요.
프롬프트에 '[실행정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시해 주세요. 프롬프트에 '[실행정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시해 주세요.
@@ -1,7 +1,3 @@
---
command: "/deploy-k8s-guide-back"
---
@cicd @cicd
'백엔드배포가이드'에 따라 백엔드 서비스 배포 방법을 작성해 주세요. '백엔드배포가이드'에 따라 백엔드 서비스 배포 방법을 작성해 주세요.
프롬프트에 '[실행정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시해 주세요. 프롬프트에 '[실행정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시해 주세요.
@@ -1,7 +1,3 @@
---
command: "/deploy-k8s-guide-front"
---
@cicd @cicd
'프론트엔드배포가이드'에 따라 프론트엔드 서비스 배포 방법을 작성해 주세요. '프론트엔드배포가이드'에 따라 프론트엔드 서비스 배포 방법을 작성해 주세요.
프롬프트에 '[실행정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시해 주세요. 프롬프트에 '[실행정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시해 주세요.
@@ -1,7 +1,3 @@
---
command: "/deploy-run-container-guide-back"
---
@cicd @cicd
'백엔드컨테이너실행방법가이드'에 따라 컨테이너 실행 가이드를 작성해 주세요. '백엔드컨테이너실행방법가이드'에 따라 컨테이너 실행 가이드를 작성해 주세요.
프롬프트에 '[실행정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시해 주세요. 프롬프트에 '[실행정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시해 주세요.
@@ -10,6 +6,6 @@ command: "/deploy-run-container-guide-back"
[실행정보] [실행정보]
- ACR명: acrdigitalgarage01 - ACR명: acrdigitalgarage01
- VM - VM
- KEY파일: ~/home/bastion-dg0500 - KEY파일: ~/home/bastion-dg0502
- USERID: azureuser - USERID: azureuser
- IP: 4.230.5.6 - IP: 4.218.10.89
@@ -1,7 +1,3 @@
---
command: "/deploy-run-container-guide-front"
---
@cicd @cicd
'프론트엔드컨테이너실행방법가이드'에 따라 컨테이너 실행 가이드를 작성해 주세요. '프론트엔드컨테이너실행방법가이드'에 따라 컨테이너 실행 가이드를 작성해 주세요.
프롬프트에 '[실행정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시해 주세요. 프롬프트에 '[실행정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시해 주세요.
-3
View File
@@ -1,6 +1,3 @@
---
command: "/design-api"
---
@architecture @architecture
API를 설계해 주세요: API를 설계해 주세요:
- '공통설계원칙'과 'API설계가이드'를 준용하여 설계 - '공통설계원칙'과 'API설계가이드'를 준용하여 설계
-3
View File
@@ -1,6 +1,3 @@
---
command: "/design-class"
---
@architecture @architecture
'공통설계원칙'과 '클래스설계가이드'를 준용하여 클래스를 설계해 주세요. '공통설계원칙'과 '클래스설계가이드'를 준용하여 클래스를 설계해 주세요.
프롬프트에 '[클래스설계 정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시합니다. 프롬프트에 '[클래스설계 정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시합니다.
-3
View File
@@ -1,6 +1,3 @@
---
command: "/design-data"
---
@architecture @architecture
데이터 설계를 해주세요: 데이터 설계를 해주세요:
- '공통설계원칙'과 '데이터설계가이드'를 준용하여 설계 - '공통설계원칙'과 '데이터설계가이드'를 준용하여 설계
-3
View File
@@ -1,6 +1,3 @@
---
command: "/design-fix-prototype"
---
@fix as @front @fix as @front
'[오류내용]'섹션에 제공된 오류를 해결해 주세요. '[오류내용]'섹션에 제공된 오류를 해결해 주세요.
프롬프트에 '[오류내용]'섹션이 없으면 수행 중단하고 안내 메시지 표시 프롬프트에 '[오류내용]'섹션이 없으면 수행 중단하고 안내 메시지 표시
-3
View File
@@ -1,6 +1,3 @@
---
command: "/design-front"
---
@plan as @front @plan as @front
'프론트엔드설계가이드'를 준용하여 **프론트엔드설계서**를 작성해 주세요. '프론트엔드설계가이드'를 준용하여 **프론트엔드설계서**를 작성해 주세요.
프롬프트에 '[백엔드시스템]'항목이 없으면 수행을 중단하고 안내 메시지를 표시합니다. 프롬프트에 '[백엔드시스템]'항목이 없으면 수행을 중단하고 안내 메시지를 표시합니다.
-3
View File
@@ -1,6 +1,3 @@
---
command: "/design-high-level"
---
@architecture @architecture
'HighLevel아키텍처정의가이드'를 준용하여 High Level 아키텍처 정의서를 작성해 주세요. 'HighLevel아키텍처정의가이드'를 준용하여 High Level 아키텍처 정의서를 작성해 주세요.
'CLOUD' 정보가 없으면 수행을 중단하고 안내메시지를 표시하세요. 'CLOUD' 정보가 없으면 수행을 중단하고 안내메시지를 표시하세요.
@@ -1,6 +1,3 @@
---
command: "/design-improve-prototype"
---
@improve as @front @improve as @front
'[개선내용]'섹션에 있는 내용을 개선해 주세요. '[개선내용]'섹션에 있는 내용을 개선해 주세요.
프롬프트에 '[개선내용]'항목이 없으면 수행을 중단하고 안내 메시지 표시 프롬프트에 '[개선내용]'항목이 없으면 수행을 중단하고 안내 메시지 표시
@@ -1,5 +1,2 @@
---
command: "/design-improve-userstory"
---
@analyze as @front 프로토타입을 웹브라우저에서 분석한 후, @analyze as @front 프로토타입을 웹브라우저에서 분석한 후,
@document as @scribe 수정된 프로토타입에 따라 유저스토리를 업데이트 해주십시오. @document as @scribe 수정된 프로토타입에 따라 유저스토리를 업데이트 해주십시오.
-3
View File
@@ -1,6 +1,3 @@
---
command: "/design-logical"
---
@architecture @architecture
논리 아키텍처를 설계해 주세요: 논리 아키텍처를 설계해 주세요:
- '공통설계원칙'과 '논리아키텍처 설계 가이드'를 준용하여 설계 - '공통설계원칙'과 '논리아키텍처 설계 가이드'를 준용하여 설계
-3
View File
@@ -1,6 +1,3 @@
---
command: "/design-pattern"
---
@design-pattern @design-pattern
클라우드 아키텍처 패턴 적용 방안을 작성해 주세요: 클라우드 아키텍처 패턴 적용 방안을 작성해 주세요:
- '클라우드아키텍처패턴선정가이드'를 준용하여 작성 - '클라우드아키텍처패턴선정가이드'를 준용하여 작성
-3
View File
@@ -1,6 +1,3 @@
---
command: "/design-physical"
---
@architecture @architecture
'물리아키텍처설계가이드'를 준용하여 물리아키텍처를 설계해 주세요. '물리아키텍처설계가이드'를 준용하여 물리아키텍처를 설계해 주세요.
'CLOUD' 정보가 없으면 수행을 중단하고 안내메시지를 표시하세요. 'CLOUD' 정보가 없으면 수행을 중단하고 안내메시지를 표시하세요.
-3
View File
@@ -1,6 +1,3 @@
---
command: "/design-prototype"
---
@prototype @prototype
프로토타입을 작성해 주세요: 프로토타입을 작성해 주세요:
- '프로토타입작성가이드'를 준용하여 작성 - '프로토타입작성가이드'를 준용하여 작성
-3
View File
@@ -1,6 +1,3 @@
---
command: "/design-seq-inner"
---
@architecture @architecture
내부 시퀀스 설계를 해 주세요: 내부 시퀀스 설계를 해 주세요:
- '공통설계원칙'과 '내부시퀀스설계 가이드'를 준용하여 설계 - '공통설계원칙'과 '내부시퀀스설계 가이드'를 준용하여 설계
-3
View File
@@ -1,6 +1,3 @@
---
command: "/design-seq-outer"
---
@architecture @architecture
외부 시퀀스 설계를 해 주세요: 외부 시퀀스 설계를 해 주세요:
- '공통설계원칙'과 '외부시퀀스설계가이드'를 준용하여 설계 - '공통설계원칙'과 '외부시퀀스설계가이드'를 준용하여 설계
@@ -1,5 +1,2 @@
---
command: "/design-test-prototype"
---
@test-front @test-front
프로토타입을 테스트 해 주세요. 프로토타입을 테스트 해 주세요.
-3
View File
@@ -1,6 +1,3 @@
---
command: "/design-uiux"
---
@uiux @uiux
UI/UX 설계를 해주세요: UI/UX 설계를 해주세요:
- 'UI/UX설계가이드'를 준용하여 작성 - 'UI/UX설계가이드'를 준용하여 작성
-3
View File
@@ -1,5 +1,2 @@
---
command: "/design-update-uiux"
---
@document @front @document @front
현재 프로토타입과 유저스토리를 기준으로 UI/UX설계서와 스타일가이드를 수정해 주세요. 현재 프로토타입과 유저스토리를 기준으로 UI/UX설계서와 스타일가이드를 수정해 주세요.
-3
View File
@@ -1,6 +1,3 @@
---
command: "/think-help"
---
기획 작업 순서 기획 작업 순서
1단계: 서비스 기획 1단계: 서비스 기획
-3
View File
@@ -1,6 +1,3 @@
---
command: "/think-planning"
---
아래 내용을 터미널에 표시만 하고 수행을 하지는 않습니다. 아래 내용을 터미널에 표시만 하고 수행을 하지는 않습니다.
``` ```
아래 가이드를 참고하여 서비스 기획을 수행합니다. 아래 가이드를 참고하여 서비스 기획을 수행합니다.
-6
View File
@@ -1,7 +1,3 @@
---
command: "/think-userstory"
---
```
@document @document
유저스토리를 작성하세요. 유저스토리를 작성하세요.
프롬프트에 '[요구사항]'섹션이 없으면 수행을 중단하고 안내 메시지를 표시합니다. 프롬프트에 '[요구사항]'섹션이 없으면 수행을 중단하고 안내 메시지를 표시합니다.
@@ -20,5 +16,3 @@ Case 2) 다른 방법으로 이벤트스토밍을 한 경우는 요구사항을
2. 유저스토리 작성 2. 유저스토리 작성
- '유저스토리작성방법'과 '유저스토리예제'를 참고하여 유저스토리를 작성 - '유저스토리작성방법'과 '유저스토리예제'를 참고하여 유저스토리를 작성
- 결과파일은 'design/userstory.md'에 생성 - 결과파일은 'design/userstory.md'에 생성
```
+27
View File
@@ -0,0 +1,27 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="EventServiceApplication" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot" folderName="Event Service">
<option name="ACTIVE_PROFILES" />
<option name="ENABLE_LAUNCH_OPTIMIZATION" value="true" />
<envs>
<env name="DB_HOST" value="20.249.177.232" />
<env name="DB_PORT" value="5432" />
<env name="DB_NAME" value="eventdb" />
<env name="DB_USERNAME" value="eventuser" />
<env name="DB_PASSWORD" value="Hi5Jessica!" />
<env name="REDIS_HOST" value="localhost" />
<env name="REDIS_PORT" value="6379" />
<env name="REDIS_PASSWORD" value="" />
<env name="KAFKA_BOOTSTRAP_SERVERS" value="localhost:9092" />
<env name="SERVER_PORT" value="8081" />
<env name="DDL_AUTO" value="update" />
<env name="LOG_LEVEL" value="DEBUG" />
<env name="SQL_LOG_LEVEL" value="DEBUG" />
<env name="DISTRIBUTION_SERVICE_URL" value="http://localhost:8084" />
</envs>
<module name="kt-event-marketing.event-service.main" />
<option name="SPRING_BOOT_MAIN_CLASS" value="com.kt.event.eventservice.EventServiceApplication" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
+89
View File
@@ -0,0 +1,89 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="analytics-service" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="env">
<map>
<!-- Database Settings -->
<entry key="DB_KIND" value="postgresql" />
<entry key="DB_HOST" value="4.230.49.9" />
<entry key="DB_PORT" value="5432" />
<entry key="DB_NAME" value="analyticdb" />
<entry key="DB_USERNAME" value="eventuser" />
<entry key="DB_PASSWORD" value="Hi5Jessica!" />
<!-- Redis Settings -->
<entry key="REDIS_HOST" value="20.214.210.71" />
<entry key="REDIS_PORT" value="6379" />
<entry key="REDIS_PASSWORD" value="Hi5Jessica!" />
<entry key="REDIS_DATABASE" value="5" />
<!-- Kafka Settings -->
<entry key="KAFKA_ENABLED" value="true" />
<entry key="KAFKA_BOOTSTRAP_SERVERS" value="4.230.50.63:9092" />
<entry key="KAFKA_CONSUMER_GROUP_ID" value="analytics-service" />
<!-- Sample Data Settings (MVP Only) -->
<!-- ⚠️ 실제 운영 환경에서는 false로 설정 (다른 서비스들이 이벤트 발행) -->
<entry key="SAMPLE_DATA_ENABLED" value="true" />
<!-- JPA Settings -->
<entry key="SHOW_SQL" value="true" />
<entry key="DDL_AUTO" value="update" />
<!-- Server Settings -->
<entry key="SERVER_PORT" value="8086" />
<!-- JWT Settings -->
<entry key="JWT_SECRET" value="dev-jwt-secret-key-for-development-only-analytics-service-2024" />
<entry key="JWT_ACCESS_TOKEN_VALIDITY" value="1800" />
<entry key="JWT_REFRESH_TOKEN_VALIDITY" value="86400" />
<!-- CORS Settings -->
<entry key="CORS_ALLOWED_ORIGINS" value="http://localhost:*" />
<!-- Logging Settings -->
<entry key="LOG_LEVEL_APP" value="DEBUG" />
<entry key="LOG_LEVEL_WEB" value="INFO" />
<entry key="LOG_LEVEL_SQL" value="DEBUG" />
<entry key="LOG_LEVEL_SQL_TYPE" value="TRACE" />
<entry key="LOG_FILE" value="logs/analytics-service.log" />
<!-- Batch Settings -->
<entry key="BATCH_ENABLED" value="true" />
<entry key="BATCH_REFRESH_INTERVAL" value="300000" />
<entry key="BATCH_INITIAL_DELAY" value="30000" />
</map>
</option>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="analytics-service:bootRun" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<EXTENSION ID="com.intellij.execution.ExternalSystemRunConfigurationJavaExtension">
<extension name="net.ashald.envfile">
<option name="IS_ENABLED" value="false" />
<option name="IS_SUBST" value="false" />
<option name="IS_PATH_MACRO_SUPPORTED" value="false" />
<option name="IS_IGNORE_MISSING_FILES" value="false" />
<option name="IS_ENABLE_EXPERIMENTAL_INTEGRATIONS" value="false" />
<ENTRIES>
<ENTRY IS_ENABLED="true" PARSER="runconfig" IS_EXECUTABLE="false" />
</ENTRIES>
</extension>
</EXTENSION>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>
-82
View File
@@ -1,82 +0,0 @@
# 백엔드 컨테이너이미지 작성가이드
[요청사항]
- 백엔드 각 서비스를의 컨테이너 이미지 생성
- 실제 빌드 수행 및 검증까지 완료
- '[결과파일]'에 수행한 명령어를 포함하여 컨테이너 이미지 작성 과정 생성
[작업순서]
- 서비스명 확인
서비스명은 settings.gradle에서 확인
예시) include 'common'하위의 4개가 서비스명임.
```
rootProject.name = 'tripgen'
include 'common'
include 'user-service'
include 'location-service'
include 'ai-service'
include 'trip-service'
```
- 실행Jar 파일 설정
실행Jar 파일명을 서비스명과 일치하도록 build.gradle에 설정 합니다.
```
bootJar {
archiveFileName = '{서비스명}.jar'
}
```
- Dockerfile 생성
아래 내용으로 deployment/container/Dockerfile-backend 생성
```
# Build stage
FROM openjdk:23-oraclelinux8 AS builder
ARG BUILD_LIB_DIR
ARG ARTIFACTORY_FILE
COPY ${BUILD_LIB_DIR}/${ARTIFACTORY_FILE} app.jar
# Run stage
FROM openjdk:23-slim
ENV USERNAME=k8s
ENV ARTIFACTORY_HOME=/home/${USERNAME}
ENV JAVA_OPTS=""
# Add a non-root user
RUN adduser --system --group ${USERNAME} && \
mkdir -p ${ARTIFACTORY_HOME} && \
chown ${USERNAME}:${USERNAME} ${ARTIFACTORY_HOME}
WORKDIR ${ARTIFACTORY_HOME}
COPY --from=builder app.jar app.jar
RUN chown ${USERNAME}:${USERNAME} app.jar
USER ${USERNAME}
ENTRYPOINT [ "sh", "-c" ]
CMD ["java ${JAVA_OPTS} -jar app.jar"]
```
- 컨테이너 이미지 생성
아래 명령으로 각 서비스 빌드. shell 파일을 생성하지 말고 command로 수행.
서브에이젼트를 생성하여 병렬로 수행.
```
DOCKER_FILE=deployment/container/Dockerfile-backend
service={서비스명}
docker build \
--platform linux/amd64 \
--build-arg BUILD_LIB_DIR="${서비스명}/build/libs" \
--build-arg ARTIFACTORY_FILE="${서비스명}.jar" \
-f ${DOCKER_FILE} \
-t ${서비스명}:latest .
```
- 생성된 이미지 확인
아래 명령으로 모든 서비스의 이미지가 빌드되었는지 확인
```
docker images | grep {서비스명}
```
[결과파일]
deployment/container/build-image.md
-220
View File
@@ -1,220 +0,0 @@
# 설계 프롬프트
아래 순서대로 설계합니다.
## UI/UX 설계
command: "/design-uiux"
prompt:
```
@uiux
UI/UX 설계를 해주세요:
- 'UI/UX설계가이드'를 준용하여 작성
```
---
# 프로토타입 작성
command: "/design-prototype"
prompt:
**1.작성**
```
@prototype
프로토타입을 작성해 주세요:
- '프로토타입작성가이드'를 준용하여 작성
```
---
**2.검증**
command: "/design-test-prototype"
prompt:
```
@test-front
프로토타입을 테스트 해 주세요.
```
---
**3.오류수정**
command: "/design-fix-prototype"
prompt:
```
@fix as @front
'[오류내용]'섹션에 제공된 오류를 해결해 주세요.
프롬프트에 '[오류내용]'섹션이 없으면 수행 중단하고 안내 메시지 표시
{안내메시지}
'[오류내용]'섹션 하위에 오류 내용을 제공
```
---
**4.개선**
command: "/design-improve-prototype"
prompt:
```
@improve as @front
'[개선내용]'섹션에 있는 내용을 개선해 주세요.
프롬프트에 '[개선내용]'항목이 없으면 수행을 중단하고 안내 메시지 표시
{안내메시지}
'[개선내용]'섹션 하위에 개선할 내용을 제공
```
---
**5.유저스토리 품질 높이기**
command: "/design-improve-userstory"
prompt:
```
@analyze as @front 프로토타입을 웹브라우저에서 분석한 후,
@document as @scribe 수정된 프로토타입에 따라 유저스토리를 업데이트 해주십시오.
```
---
**6.설계서 다시 업데이트**
command: "/design-update-uiux"
prompt:
```
@document @front
현재 프로토타입과 유저스토리를 기준으로 UI/UX설계서와 스타일가이드를 수정해 주세요.
```
---
## 클라우드 아키텍처 패턴 선정
command: "/design-pattern"
prompt:
```
@design-pattern
클라우드 아키텍처 패턴 적용 방안을 작성해 주세요:
- '클라우드아키텍처패턴선정가이드'를 준용하여 작성
```
---
## 논리아키텍처 설계
command: "/design-logical"
prompt:
```
@architecture
논리 아키텍처를 설계해 주세요:
- '공통설계원칙'과 '논리아키텍처 설계 가이드'를 준용하여 설계
```
---
## 외부 시퀀스 설계
command: "/design-seq-outer"
prompt:
```
@architecture
외부 시퀀스 설계를 해 주세요:
- '공통설계원칙'과 '외부시퀀스설계가이드'를 준용하여 설계
```
---
## 내부 시퀀스 설계
command: "/design-seq-inner"
prompt:
```
@architecture
내부 시퀀스 설계를 해 주세요:
- '공통설계원칙'과 '내부시퀀스설계 가이드'를 준용하여 설계
```
---
## API 설계
command: "/design-api"
prompt:
```
@architecture
API를 설계해 주세요:
- '공통설계원칙'과 'API설계가이드'를 준용하여 설계
```
---
## 클래스 설계
command: "/design-class"
prompt:
```
@architecture
'공통설계원칙'과 '클래스설계가이드'를 준용하여 클래스를 설계해 주세요.
프롬프트에 '[클래스설계 정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시합니다.
{안내메시지}
'[클래스설계 정보]' 섹션에 아래 예와 같은 정보를 제공해 주십시오.
[클래스설계 정보]
- 패키지 그룹: com.unicorn.tripgen
- 설계 아키텍처 패턴
- User: Layered
- Trip: Clean
- Location: Layered
- AI: Layered
```
---
## 데이터 설계
command: "/design-data"
prompt:
```
@architecture
데이터 설계를 해주세요:
- '공통설계원칙'과 '데이터설계가이드'를 준용하여 설계
```
---
## High Level 아키텍처 정의서 작성
command: "/design-high-level"
prompt:
```
@architecture
'HighLevel아키텍처정의가이드'를 준용하여 High Level 아키텍처 정의서를 작성해 주세요.
'CLOUD' 정보가 없으면 수행을 중단하고 안내메시지를 표시하세요.
{안내메시지}
아래 예와 같이 CLOUD 제공자를 Azure, AWS, Google과 같이 제공하세요.
- CLOUD: Azure
```
---
## 물리 아키텍처 설계
command: "/design-physical"
prompt:
```
@architecture
'물리아키텍처설계가이드'를 준용하여 물리아키텍처를 설계해 주세요.
'CLOUD' 정보가 없으면 수행을 중단하고 안내메시지를 표시하세요.
{안내메시지}
아래 예와 같이 CLOUD 제공자를 Azure, AWS, Google과 같이 제공하세요.
- CLOUD: Azure
```
## 프론트엔드 설계
command: "/design-front"
prompt:
```
@plan as @front
'프론트엔드설계가이드'를 준용하여 **프론트엔드설계서**를 작성해 주세요.
프롬프트에 '[백엔드시스템]'항목이 없으면 수행을 중단하고 안내 메시지를 표시합니다.
{안내메시지}
'[백엔드시스템]' 섹션에 아래 예와 같은 정보를 제공해 주십시오.
[백엔드시스템]
- 시스템: tripgen
- 마이크로서비스: user-service, location-service, trip-service, ai-service
- API문서
- user service: http://localhost:8081/v3/api-docs
- location service: http://localhost:8082/v3/api-docs
- trip service: http://localhost:8083/v3/api-docs
- ai service: http://localhost:8084/v3/api-docs
[요구사항]
- 각 화면에 Back 아이콘 버튼과 화면 타이틀 표시
- 하단 네비게이션 바 아이콘화: 홈, 새여행, 주변장소검색, 여행보기
```
-180
View File
@@ -1,180 +0,0 @@
# 개발 프롬프트
## 데이터베이스 설치계획서 작성 요청
command: "/develop-db-guide"
prompt:
```
@backing-service
"데이터베이스설치계획서가이드"에 따라 데이터베이스 설치계획서를 작성해 주십시오.
```
---
## 데이터베이스 설치 수행 요청
command: "/develop-db-install"
prompt:
```
@backing-service
[요구사항]
'데이터베이스설치가이드'에 따라 설치해 주세요.
'[설치정보]'섹션이 없으면 수행을 중단하고 안내 메시지를 표시하세요.
{안내메시지}
'[설치정보]'섹션 하위에 아래 예와 같이 설치에 필요한 정보를 추가해 주세요.
- 설치대상환경: 개발환경
- AKS Resource Group: rg-digitalgarage-01
- AKS Name: aks-digitalgarage-01
- Namespace: tripgen-dev
```
---
## 데이터베이스 설치 제거 요청 (필요시)
command: "/develop-db-remove"
prompt:
```
@backing-service
[요구사항]
- "데이터베이스설치결과서"를 보고 관련된 모든 리소스를 삭제
- "캐시설치결과서"를 보고 관련된 모든 리소스를 삭제
- 현재 OS에 맞게 수행
- 서브 에이젼트를 병렬로 수행하여 삭제
- 결과파일은 생성할 필요 없고 화면에만 결과 표시
[참고자료]
- 데이터베이스설치결과서
- 캐시설치결과서
```
---
## Message Queue 설치 계획서 작성 요청
command: "/develop-mq-guide"
prompt:
```
@backing-service
"MQ설치게획서가이드"에 따라 Message Queue 설치계획서를 작성해 주세요.
```
---
## Message Queue 설치 수행 요청(필요시)
command: "/develop-mq-install"
prompt:
```
@backing-service
[요구사항]
'MQ설치가이드'에 따라 설치해 주세요.
'[설치정보]'섹션이 없으면 수행을 중단하고 안내 메시지를 표시하세요.
{안내메시지}
'[설치정보]'섹션 하위에 아래 예와 같이 설치에 필요한 정보를 추가해 주세요.
- 설치대상환경: 개발환경
- Resource Group: rg-digitalgarage-01
- Namespace: tripgen-dev
```
---
## Message Queue 설치 제거 요청
command: "/develop-mq-remove"
prompt:
```
@backing-service
[요구사항]
- "MQ설치결과서"를 보고 관련된 모든 리소스를 삭제
- 현재 OS에 맞게 수행
- 서브 에이젼트를 병렬로 수행하여 삭제
- 결과파일은 생성할 필요 없고 화면에만 결과 표시
[참고자료]
- MQ설치결과서
```
---
## 백엔드 개발 요청
command: "/develop-dev-backend"
prompt:
```
@dev-backend
"백엔드개발가이드"에 따라 개발해 주세요.
프롬프트에 '[개발정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시해 주세요.
{안내메시지}
[개발정보]
- 개발 아키텍처패턴
- auth: Layered
- bill-inquiry: Clean
- product-change: Layered
- kos-mock: Layered
```
---
## 백엔드 오류 해결 요청
command: "/develop-fix-backend"
prompt:
```
@fix as @back
개발된 각 서비스와 common 모듈을 컴파일하고 에러를 해결해 주세요.
- common 모듈 우선 수행
- 각 서비스별로 서브 에이젠트를 병렬로 수행
- 컴파일이 모두 성공할때까지 계속 수행
```
---
## 서비스 실행파일 작성 요청
command: "/develop-make-run-profile"
prompt:
```
@test-backend
'서비스실행파일작성가이드'에 따라 테스트를 해 주세요.
프롬프트에 '[작성정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시해 주세요.
DB나 Redis의 접근 정보는 지정할 필요 없습니다. 특별히 없으면 '[작성정보]'섹션에 '없음'이라고 하세요.
{안내메시지}
[작성정보]
- API Key
- Claude: sk-ant-ap...
- OpenAI: sk-proj-An4Q...
- Open Weather Map: 1aa5b...
- Kakao API Key: 5cdc24....
```
---
## 백엔드 테스트 요청
command: "/develop-test-backend"
prompt:
```
@test-backend
'백엔드테스트가이드'에 따라 테스트를 해 주세요.
프롬프트에 '[테스트정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시해 주세요.
테스트 대상 서비스를 지정안하면 모든 서비스를 테스트 합니다.
{안내메시지}
'[테스트정보]'섹션 하위에 아래 예와 같이 테스트에 필요한 정보를 제시해 주세요.
테스트 대상 서비스를 콤마로 구분하여 입력할 수 있으며 전체를 테스트 할 때는 '전체'라고 입력하세요.
- 서비스: user-service
- API Key
- Claude: sk-ant-ap...
- OpenAI: sk-proj-An4Q...
- Open Weather Map: 1aa5b...
- Kakao API Key: 5cdc24....
```
---
## 프론트엔드 개발 요청
command: "/develop-dev-front"
prompt:
```
@dev-front
"프론트엔드개발가이드"에 따라 개발해 주세요.
프롬프트에 '[개발정보]'항목이 없으면 수행을 중단하고 안내 메시지를 표시해 주세요.
{안내메시지}
'[개발정보]'섹션 하위에 아래 예와 같이 개발에 필요한 정보를 제시해 주세요.
[개발정보]
- 개발프레임워크: Typescript + React 18
- UI프레임워크: MUI v5
- 상태관리: Redux Toolkit
- 라우팅: React Router v6
- API통신: Axios
- 스타일링: MUI + styled-components
- 빌드도구: Vite
```
-41
View File
@@ -1,41 +0,0 @@
# 서비스 기획 프롬프트
## 서비스 기획
command: "/think-planning"
prompt:
아래 내용을 터미널에 표시만 하고 수행을 하지는 않습니다.
```
아래 가이드를 참고하여 서비스 기획을 수행합니다.
https://github.com/cna-bootcamp/aiguide/blob/main/AI%ED%99%9C%EC%9A%A9%20%EC%84%9C%EB%B9%84%EC%8A%A4%20%EA%B8%B0%ED%9A%8D%20%EA%B0%80%EC%9D%B4%EB%93%9C.md
```
---
## 유저스토리 작성
command: "/think-userstory"
prompt:
```
@document
유저스토리를 작성하세요.
프롬프트에 '[요구사항]'섹션이 없으면 수행을 중단하고 안내 메시지를 표시합니다.
{안내메시지}
'[요구사항]' 섹션에 아래 예와 같은 정보를 제공해 주십시오.
[요구사항]
Case 1) 이벤트스토밍을 피그마로 수행한 경우는 피그마 채널ID를 제공
예) 피그마 채널ID 'abcde'에 접속하여 분석
Case 2) 다른 방법으로 이벤트스토밍을 한 경우는 요구사항을 정리한 파일 경로를 제공
예) 요구사항문서 'design/requirement.md'를 읽어 분석
프롬프트에 '[요구사항]'섹션이 있으면 아래와 같이 수행합니다.
1. 요구사항 분석
- 피그마 채널ID가 제공된 경우 figma MCP를 이용하여 해당 채널에 접속하여 분석
- 요구사항문서 경로가 제공된 경우 해당 문서를 읽어 요구사항을 분석
2. 유저스토리 작성
- '유저스토리작성방법'과 '유저스토리예제'를 참고하여 유저스토리를 작성
- 결과파일은 'design/userstory.md'에 생성
```
@@ -56,14 +56,13 @@ public class JwtTokenProvider {
* @param roles 역할 목록 * @param roles 역할 목록
* @return Access Token * @return Access Token
*/ */
public String createAccessToken(UUID userId, UUID storeId, String email, String name, List<String> roles) {
public String createAccessToken(Long userId, Long storeId, String email, String name, List<String> roles) {
Date now = new Date(); Date now = new Date();
Date expiryDate = new Date(now.getTime() + accessTokenValidityMs); Date expiryDate = new Date(now.getTime() + accessTokenValidityMs);
return Jwts.builder() return Jwts.builder()
.subject(userId.toString()) .subject(userId.toString())
.claim("storeId", storeId != null ? storeId.toString() : null) .claim("storeId", storeId.toString())
.claim("email", email) .claim("email", email)
.claim("name", name) .claim("name", name)
.claim("roles", roles) .claim("roles", roles)
@@ -113,9 +112,8 @@ public class JwtTokenProvider {
public UserPrincipal getUserPrincipalFromToken(String token) { public UserPrincipal getUserPrincipalFromToken(String token) {
Claims claims = parseToken(token); Claims claims = parseToken(token);
Long userId = Long.parseLong(claims.getSubject()); UUID userId = UUID.fromString(claims.getSubject());
String storeIdStr = claims.get("storeId", String.class); UUID storeId = UUID.fromString(claims.get("storeId", String.class));
Long storeId = storeIdStr != null ? Long.parseLong(storeIdStr) : null;
String email = claims.get("email", String.class); String email = claims.get("email", String.class);
String name = claims.get("name", String.class); String name = claims.get("name", String.class);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -31,11 +31,6 @@ public class UserPrincipal implements UserDetails {
*/ */
private final UUID storeId; private final UUID storeId;
/**
* 매장 ID
*/
private final Long storeId;
/** /**
* 사용자 이메일 * 사용자 이메일
*/ */
+297 -148
View File
@@ -1,40 +1,118 @@
# 백엔드 컨테이너 이미지 빌드 결과 # 백엔드 컨테이너 이미지 작성 결과
## 프로젝트 정보 작성일: 2025-10-27
- **프로젝트명**: kt-event-marketing 작성자: DevOps Engineer
- **빌드 일시**: 2025-10-27
- **빌드 대상**: 3개 마이크로서비스 (content-service, participation-service, user-service)
## 1. 사전 준비 ## 1. 개요
### 1.1 서비스 확인 KT 이벤트 마케팅 플랫폼의 백엔드 마이크로서비스들을 컨테이너 이미지로 빌드하는 과정을 문서화합니다.
settings.gradle에서 확인된 구현 완료 서비스:
- ✅ content-service ## 2. 서비스 현황
- ✅ participation-service
- ✅ user-service ### 2.1 전체 서비스 목록 (settings.gradle 기준)
- ⏳ ai-service (미구현)
- ⏳ analytics-service (미구현) ```
- ⏳ distribution-service (미구현) rootProject.name = 'kt-event-marketing'
- ⏳ event-service (미구현)
// Common module
include 'common'
// Microservices
include 'user-service'
include 'event-service'
include 'ai-service'
include 'content-service'
include 'distribution-service'
include 'participation-service'
include 'analytics-service'
```
### 2.2 구현 상태
| 서비스명 | 구현 상태 | JAR 빌드 | 컨테이너 이미지 | 비고 |
|---------|----------|---------|---------------|------|
| common | ✅ | N/A | N/A | 공통 라이브러리 |
| user-service | ⚠️ | ❌ | ⏸️ | 컴파일 에러 (타입 불일치) |
| event-service | ✅ | ✅ | ⏸️ | Docker Desktop 필요 |
| ai-service | ❌ | ❌ | ❌ | 미구현 |
| content-service | ✅ | ✅ | ⏸️ | Docker Desktop 필요 |
| distribution-service | ❌ | ❌ | ❌ | 미구현 |
| participation-service | ✅ | ✅ | ⏸️ | Docker Desktop 필요 |
| analytics-service | ✅ | ✅ | ⏸️ | Docker Desktop 필요 |
**빌드 가능 서비스**: 4개 (event-service, content-service, participation-service, analytics-service)
## 3. JAR 파일 빌드
### 3.1 bootJar 설정 확인
root `build.gradle`에 이미 설정되어 있음:
### 1.2 bootJar 설정 확인
build.gradle에 이미 설정되어 있음 (line 101-103):
```gradle ```gradle
// Configure bootJar task for each service
bootJar { bootJar {
archiveFileName = "${project.name}.jar" archiveFileName = "${project.name}.jar"
} }
``` ```
## 2. Dockerfile 생성 ### 3.2 JAR 빌드 실행
#### gradlew 실행 권한 설정 (최초 1회)
VM 환경에서 실행 시 권한 오류가 발생할 수 있으므로 먼저 실행 권한을 부여합니다:
### 2.1 디렉토리 생성
```bash ```bash
mkdir -p deployment/container chmod +x gradlew
``` ```
### 2.2 Dockerfile-backend 작성 #### 빌드 명령어 실행
파일 위치: `deployment/container/Dockerfile-backend`
**명령어**:
```bash
./gradlew :analytics-service:bootJar :content-service:bootJar :event-service:bootJar :participation-service:bootJar :user-service:bootJar --no-daemon
```
**권한 오류 발생 시 대체 방법**:
```bash
# gradlew에 실행 권한이 없는 경우
bash gradlew :analytics-service:bootJar :content-service:bootJar :event-service:bootJar :participation-service:bootJar :user-service:bootJar --no-daemon
```
**빌드 결과**:
**성공한 서비스 (4개)**:
- `analytics-service/build/libs/analytics-service.jar`
- `content-service/build/libs/content-service.jar`
- `event-service/build/libs/event-service.jar`
- `participation-service/build/libs/participation-service.jar`
**실패한 서비스 (1개)**:
- `user-service`: 컴파일 에러 발생
**user-service 컴파일 에러 상세**:
```
UserController.java:93: error: incompatible types: UUID cannot be converted to Long
Long userId = principal.getUserId();
^
UserController.java:109: error: incompatible types: UUID cannot be converted to Long
Long userId = principal.getUserId();
^
UserController.java:126: error: incompatible types: UUID cannot be converted to Long
Long userId = principal.getUserId();
^
AuthenticationServiceImpl.java:72: error: method createAccessToken in class JwtTokenProvider cannot be applied to given types;
required: UUID,UUID,String,String,List<String>
found: Long,String,String,List<String>
reason: actual and formal argument lists differ in length
```
**조치 필요**: user-service의 User ID 타입을 Long에서 UUID로 변경 필요
## 4. Dockerfile 작성
**파일 위치**: `deployment/container/Dockerfile-backend`
**내용**:
```dockerfile ```dockerfile
# Build stage # Build stage
FROM openjdk:23-oraclelinux8 AS builder FROM openjdk:23-oraclelinux8 AS builder
@@ -63,170 +141,241 @@ ENTRYPOINT [ "sh", "-c" ]
CMD ["java ${JAVA_OPTS} -jar app.jar"] CMD ["java ${JAVA_OPTS} -jar app.jar"]
``` ```
**주요 특징**: **특징**:
- Multi-stage build로 이미지 크기 최적화 - Multi-stage build (빌드 단계와 실행 단계 분리)
- Non-root user(k8s) 생성으로 보안 강화 - OpenJDK 23 사용
- JAVA_OPTS 환경 변수로 JVM 옵션 설정 가능 - 비root 사용자(k8s)로 실행하여 보안 강화
- JAVA_OPTS 환경변수로 JVM 옵션 커스터마이징 가능
- linux/amd64 플랫폼 지원
## 3. JAR 파일 빌드 ## 5. 컨테이너 이미지 빌드
### 3.1 빌드 명령어 ### 5.1 사전 조건
⚠️ **Docker Desktop 실행 필요**
이미지 빌드 전에 Docker Desktop이 실행되어 있어야 합니다:
1. Windows에서 Docker Desktop 실행
2. 시스템 트레이에서 "Docker Desktop is running" 확인
3. 확인 명령어: `docker ps`
### 5.2 빌드 명령어
#### analytics-service
```bash ```bash
./gradlew :content-service:bootJar :participation-service:bootJar :user-service:bootJar docker build \
--platform linux/amd64 \
--build-arg BUILD_LIB_DIR="analytics-service/build/libs" \
--build-arg ARTIFACTORY_FILE="analytics-service.jar" \
-f deployment/container/Dockerfile-backend \
-t analytics-service:latest .
``` ```
### 3.2 빌드 결과 #### content-service
```
BUILD SUCCESSFUL in 15s
18 actionable tasks: 5 executed, 13 up-to-date
```
### 3.3 생성된 JAR 파일
```bash ```bash
$ ls -lh */build/libs/*.jar docker build \
--platform linux/amd64 \
-rw-r--r-- 1 KTDS 197121 78M content-service/build/libs/content-service.jar --build-arg BUILD_LIB_DIR="content-service/build/libs" \
-rw-r--r-- 1 KTDS 197121 85M participation-service/build/libs/participation-service.jar --build-arg ARTIFACTORY_FILE="content-service.jar" \
-rw-r--r-- 1 KTDS 197121 96M user-service/build/libs/user-service.jar -f deployment/container/Dockerfile-backend \
-t content-service:latest .
``` ```
## 4. Docker 이미지 빌드 #### event-service
### 4.1 content-service 이미지 빌드
```bash ```bash
DOCKER_FILE=deployment/container/Dockerfile-backend docker build \
service=content-service --platform linux/amd64 \
--build-arg BUILD_LIB_DIR="event-service/build/libs" \
--build-arg ARTIFACTORY_FILE="event-service.jar" \
-f deployment/container/Dockerfile-backend \
-t event-service:latest .
```
#### participation-service
```bash
docker build \
--platform linux/amd64 \
--build-arg BUILD_LIB_DIR="participation-service/build/libs" \
--build-arg ARTIFACTORY_FILE="participation-service.jar" \
-f deployment/container/Dockerfile-backend \
-t participation-service:latest .
```
### 5.3 일괄 빌드 스크립트
모든 서비스를 한 번에 빌드하려면 다음 스크립트를 사용하세요:
**Windows (PowerShell)**:
```powershell
# 빌드 가능한 서비스 목록
$services = @(
"analytics-service",
"content-service",
"event-service",
"participation-service"
)
# 각 서비스 빌드
foreach ($service in $services) {
Write-Host "Building $service..." -ForegroundColor Green
docker build `
--platform linux/amd64 `
--build-arg BUILD_LIB_DIR="$service/build/libs" `
--build-arg ARTIFACTORY_FILE="$service.jar" `
-f deployment/container/Dockerfile-backend `
-t ${service}:latest .
if ($LASTEXITCODE -eq 0) {
Write-Host "$service build completed" -ForegroundColor Green
} else {
Write-Host "$service build failed" -ForegroundColor Red
}
}
```
**Linux/Mac (Bash)**:
```bash
#!/bin/bash
# 빌드 가능한 서비스 목록
services=(
"analytics-service"
"content-service"
"event-service"
"participation-service"
)
# 각 서비스 빌드
for service in "${services[@]}"; do
echo "Building $service..."
docker build \ docker build \
--platform linux/amd64 \ --platform linux/amd64 \
--build-arg BUILD_LIB_DIR="${service}/build/libs" \ --build-arg BUILD_LIB_DIR="${service}/build/libs" \
--build-arg ARTIFACTORY_FILE="${service}.jar" \ --build-arg ARTIFACTORY_FILE="${service}.jar" \
-f ${DOCKER_FILE} \ -f deployment/container/Dockerfile-backend \
-t ${service}:latest . -t ${service}:latest .
if [ $? -eq 0 ]; then
echo "$service build completed"
else
echo "$service build failed"
fi
done
``` ```
**빌드 결과**: ## 6. 이미지 확인
- Image ID: 06af046cbebe
- Size: 1.01GB ### 6.1 빌드된 이미지 목록 확인
- Platform: linux/amd64
- Status: ✅ SUCCESS
### 4.2 participation-service 이미지 빌드
```bash ```bash
DOCKER_FILE=deployment/container/Dockerfile-backend docker images | grep -E "analytics-service|content-service|event-service|participation-service"
service=participation-service
docker build \
--platform linux/amd64 \
--build-arg BUILD_LIB_DIR="${service}/build/libs" \
--build-arg ARTIFACTORY_FILE="${service}.jar" \
-f ${DOCKER_FILE} \
-t ${service}:latest .
``` ```
**빌드 결과**: **예상 출력**:
- Image ID: 486f2c00811e ```
- Size: 1.04GB analytics-service latest <IMAGE_ID> <TIME> <SIZE>
- Platform: linux/amd64 content-service latest <IMAGE_ID> <TIME> <SIZE>
- Status: ✅ SUCCESS event-service latest <IMAGE_ID> <TIME> <SIZE>
participation-service latest <IMAGE_ID> <TIME> <SIZE>
```
### 6.2 개별 서비스 이미지 확인
### 4.3 user-service 이미지 빌드
```bash ```bash
DOCKER_FILE=deployment/container/Dockerfile-backend # analytics-service
service=user-service docker images analytics-service:latest
docker build \ # content-service
--platform linux/amd64 \ docker images content-service:latest
--build-arg BUILD_LIB_DIR="${service}/build/libs" \
--build-arg ARTIFACTORY_FILE="${service}.jar" \ # event-service
-f ${DOCKER_FILE} \ docker images event-service:latest
-t ${service}:latest .
# participation-service
docker images participation-service:latest
``` ```
**빌드 결과**: ### 6.3 이미지 상세 정보 확인
- Image ID: 7ef657c343dd
- Size: 1.09GB
- Platform: linux/amd64
- Status: ✅ SUCCESS
## 5. 빌드 결과 확인
### 5.1 이미지 목록 조회
```bash ```bash
$ docker images | grep -E "(content-service|participation-service|user-service)" # 이미지 레이어 확인
docker history <service-name>:latest
participation-service latest 486f2c00811e 48 seconds ago 1.04GB # 이미지 메타데이터 확인
user-service latest 7ef657c343dd 48 seconds ago 1.09GB docker inspect <service-name>:latest
content-service latest 06af046cbebe 48 seconds ago 1.01GB
``` ```
### 5.2 빌드 요약 ## 7. 테스트 실행
| 서비스명 | Image ID | 크기 | 상태 |
|---------|----------|------|------|
| content-service | 06af046cbebe | 1.01GB | ✅ |
| participation-service | 486f2c00811e | 1.04GB | ✅ |
| user-service | 7ef657c343dd | 1.09GB | ✅ |
## 6. 다음 단계 ### 7.1 로컬에서 컨테이너 실행 테스트
### 6.1 컨테이너 실행 테스트
각 서비스의 Docker 이미지를 컨테이너로 실행하여 동작 확인:
```bash ```bash
docker run -d -p 8080:8080 --name content-service content-service:latest # analytics-service 실행 예시
docker run -d -p 8081:8081 --name participation-service participation-service:latest docker run -d \
docker run -d -p 8082:8082 --name user-service user-service:latest --name analytics-service-test \
-p 8080:8080 \
-e JAVA_OPTS="-Xms256m -Xmx512m" \
-e SPRING_PROFILES_ACTIVE=dev \
analytics-service:latest
# 로그 확인
docker logs -f analytics-service-test
# 헬스체크
curl http://localhost:8080/actuator/health
# 컨테이너 정리
docker stop analytics-service-test
docker rm analytics-service-test
``` ```
### 6.2 컨테이너 레지스트리 푸시
이미지를 Docker Hub 또는 프라이빗 레지스트리에 푸시:
```bash
# 이미지 태깅
docker tag content-service:latest [registry]/content-service:1.0.0
docker tag participation-service:latest [registry]/participation-service:1.0.0
docker tag user-service:latest [registry]/user-service:1.0.0
# 레지스트리 푸시
docker push [registry]/content-service:1.0.0
docker push [registry]/participation-service:1.0.0
docker push [registry]/user-service:1.0.0
```
### 6.3 Kubernetes 배포
Kubernetes 클러스터에 배포하기 위한 매니페스트 작성 및 적용
## 7. 참고 사항
### 7.1 보안 고려사항
- ✅ Non-root user(k8s) 사용으로 보안 강화
- ✅ Multi-stage build로 빌드 도구 제외
- ⚠️ 프로덕션 환경에서는 이미지 스캔 권장
### 7.2 이미지 최적화
- 현재 이미지 크기: ~1GB
- JVM 튜닝 옵션 활용 가능: `JAVA_OPTS` 환경 변수
- 추후 경량화 검토: Alpine 기반 이미지, jlink 활용
### 7.3 빌드 자동화
향후 CI/CD 파이프라인에서 자동 빌드 통합 가능:
- GitHub Actions
- Jenkins
- GitLab CI/CD
- ArgoCD
## 8. 문제 해결 ## 8. 문제 해결
### 8.1 빌드 실패 시 ### 8.1 user-service 컴파일 에러
- Gradle clean 실행 후 재빌드
- Docker daemon 상태 확인
- 디스크 공간 확인
### 8.2 이미지 크기 문제 **문제**: UUID와 Long 타입 불일치
- Multi-stage build 활용 (현재 적용됨)
- .dockerignore 파일 활용
- 불필요한 의존성 제거
--- **해결 방법**:
1. `UserController.java`에서 `Long userId``UUID userId` 변경
2. `AuthenticationServiceImpl.java``UserServiceImpl.java`에서 `createAccessToken` 메서드 호출 시 첫 번째 파라미터로 `sessionId` 추가
3. 변경 후 재빌드:
```bash
./gradlew :user-service:bootJar --no-daemon
```
**작성자**: DevOps Engineer (송근정) ### 8.2 ai-service 및 distribution-service
**작성일**: 2025-10-27
**버전**: 1.0.0 **문제**: 소스 코드 미구현
**조치**: 해당 서비스의 구현이 완료된 후 컨테이너 이미지 빌드 진행
### 8.3 Docker Desktop 연결 실패
**에러 메시지**:
```
error during connect: open //./pipe/dockerDesktopLinuxEngine: The system cannot find the file specified.
```
**해결 방법**:
1. Docker Desktop 실행
2. 완전히 시작될 때까지 대기 (트레이 아이콘 확인)
3. `docker ps` 명령으로 정상 동작 확인
4. 빌드 명령 재실행
## 9. 다음 단계
1. ✅ **완료**: Dockerfile 작성 및 JAR 빌드
2. ⏸️ **대기 중**: Docker Desktop 실행 후 이미지 빌드
3. 📋 **예정**:
- user-service 컴파일 에러 수정
- ai-service 및 distribution-service 구현 완료 후 빌드
- 이미지 레지스트리에 푸시 (ACR 등)
- Kubernetes 배포 매니페스트 작성
## 10. 참고 자료
- Dockerfile: `deployment/container/Dockerfile-backend`
- JAR 위치: `<service-name>/build/libs/<service-name>.jar`
- 빌드 스크립트: 본 문서의 5.3 섹션 참조
- OpenJDK 23 Documentation: https://openjdk.org/projects/jdk/23/
@@ -1,502 +0,0 @@
# 백엔드 컨테이너 실행 가이드
백엔드 서비스를 Azure VM에서 Docker 컨테이너로 실행하는 가이드를 제공합니다.
## 📋 목차
1. [사전 준비](#사전-준비)
2. [컨테이너 이미지 확인](#컨테이너-이미지-확인)
3. [컨테이너 실행](#컨테이너-실행)
4. [컨테이너 관리](#컨테이너-관리)
5. [문제 해결](#문제-해결)
---
## 사전 준비
### 1. VM 접속 정보
```yaml
ACR: acrdigitalgarage01
VM:
KEY파일: ~/home/bastion-dg0505
사용자: azureuser
IP: 20.196.65.160
```
### 2. VM 접속
```bash
# SSH 접속
ssh -i ~/home/bastion-dg0505 azureuser@20.196.65.160
```
### 3. Docker 및 ACR 로그인 확인
```bash
# Docker 실행 확인
docker --version
# ACR 로그인 (필요시)
az acr login --name acrdigitalgarage01
```
---
## 컨테이너 이미지 확인
### 1. ACR에서 이미지 목록 조회
```bash
# 이미지 목록 확인
az acr repository list --name acrdigitalgarage01 --output table
# 특정 이미지의 태그 확인
az acr repository show-tags --name acrdigitalgarage01 \
--repository {service-name} --output table
```
### 2. 실행할 이미지 Pull
```bash
# 이미지 다운로드
docker pull acrdigitalgarage01.azurecr.io/{service-name}:{tag}
# 예: participation-service
docker pull acrdigitalgarage01.azurecr.io/participation-service:latest
```
---
## 컨테이너 실행
### 1. 환경 변수 준비
각 서비스별 환경 변수를 확인하고 준비합니다.
```bash
# .env 파일 생성 (예시)
cat > ~/event-marketing.env << EOF
# Database
DB_HOST=your-db-host
DB_PORT=5432
DB_NAME=event_marketing
DB_USERNAME=your-username
DB_PASSWORD=your-password
# Redis
REDIS_HOST=your-redis-host
REDIS_PORT=6379
# Kafka
KAFKA_BOOTSTRAP_SERVERS=your-kafka:9092
# Application
SERVER_PORT=8080
SPRING_PROFILES_ACTIVE=prod
EOF
```
### 2. 네트워크 생성 (선택사항)
여러 컨테이너를 함께 실행할 경우 네트워크를 생성합니다.
```bash
# Docker 네트워크 생성
docker network create event-marketing-network
```
### 3. 컨테이너 실행
#### 기본 실행
```bash
docker run -d \
--name {service-name} \
--env-file ~/event-marketing.env \
-p 8080:8080 \
acrdigitalgarage01.azurecr.io/{service-name}:latest
```
#### 네트워크 포함 실행
```bash
docker run -d \
--name {service-name} \
--network event-marketing-network \
--env-file ~/event-marketing.env \
-p 8080:8080 \
acrdigitalgarage01.azurecr.io/{service-name}:latest
```
#### 볼륨 마운트 포함 실행
```bash
docker run -d \
--name {service-name} \
--network event-marketing-network \
--env-file ~/event-marketing.env \
-p 8080:8080 \
-v ~/logs/{service-name}:/app/logs \
acrdigitalgarage01.azurecr.io/{service-name}:latest
```
### 4. 여러 서비스 실행 (docker-compose 사용)
`docker-compose.yml` 파일 생성:
```yaml
version: '3.8'
services:
participation-service:
image: acrdigitalgarage01.azurecr.io/participation-service:latest
container_name: participation-service
env_file:
- ./event-marketing.env
ports:
- "8080:8080"
networks:
- event-marketing-network
volumes:
- ./logs/participation:/app/logs
restart: unless-stopped
# 다른 서비스 추가...
networks:
event-marketing-network:
driver: bridge
volumes:
logs:
```
실행:
```bash
# docker-compose로 모든 서비스 시작
docker-compose up -d
# 특정 서비스만 시작
docker-compose up -d participation-service
```
---
## 컨테이너 관리
### 1. 컨테이너 상태 확인
```bash
# 실행 중인 컨테이너 확인
docker ps
# 모든 컨테이너 확인 (중지된 것 포함)
docker ps -a
# 특정 컨테이너 상세 정보
docker inspect {container-name}
```
### 2. 로그 확인
```bash
# 실시간 로그 확인
docker logs -f {container-name}
# 최근 100줄 로그 확인
docker logs --tail 100 {container-name}
# 타임스탬프 포함 로그 확인
docker logs -t {container-name}
```
### 3. 컨테이너 중지/시작/재시작
```bash
# 중지
docker stop {container-name}
# 시작
docker start {container-name}
# 재시작
docker restart {container-name}
# 강제 중지
docker kill {container-name}
```
### 4. 컨테이너 삭제
```bash
# 중지된 컨테이너 삭제
docker rm {container-name}
# 실행 중인 컨테이너 강제 삭제
docker rm -f {container-name}
# 중지된 모든 컨테이너 삭제
docker container prune
```
### 5. 컨테이너 내부 접속
```bash
# bash 쉘로 접속
docker exec -it {container-name} bash
# 특정 명령 실행
docker exec {container-name} ls -la /app
```
### 6. 리소스 사용량 확인
```bash
# 실시간 리소스 사용량
docker stats
# 특정 컨테이너의 리소스 사용량
docker stats {container-name}
```
---
## 문제 해결
### 1. 컨테이너가 시작되지 않는 경우
```bash
# 로그 확인
docker logs {container-name}
# 컨테이너 상태 확인
docker inspect {container-name}
# 환경 변수 확인
docker exec {container-name} env
```
### 2. 포트 충돌
```bash
# 포트 사용 확인
netstat -tuln | grep {port}
# 다른 포트로 매핑
docker run -d -p 8081:8080 ...
```
### 3. 네트워크 연결 문제
```bash
# 네트워크 목록 확인
docker network ls
# 네트워크 상세 정보
docker network inspect {network-name}
# 컨테이너를 네트워크에 연결
docker network connect {network-name} {container-name}
```
### 4. 이미지 Pull 실패
```bash
# ACR 로그인 재시도
az acr login --name acrdigitalgarage01
# 수동으로 Pull
docker pull acrdigitalgarage01.azurecr.io/{service-name}:{tag}
```
### 5. 디스크 공간 부족
```bash
# 사용하지 않는 이미지 삭제
docker image prune -a
# 사용하지 않는 볼륨 삭제
docker volume prune
# 전체 정리 (주의!)
docker system prune -a
```
---
## 헬스체크 및 모니터링
### 1. 헬스체크 엔드포인트 확인
```bash
# Spring Boot Actuator health endpoint
curl http://localhost:8080/actuator/health
# 상세 헬스 정보
curl http://localhost:8080/actuator/health/readiness
curl http://localhost:8080/actuator/health/liveness
```
### 2. 메트릭 확인
```bash
# 메트릭 엔드포인트
curl http://localhost:8080/actuator/metrics
# 특정 메트릭 확인
curl http://localhost:8080/actuator/metrics/jvm.memory.used
```
### 3. 로그 모니터링 스크립트
```bash
#!/bin/bash
# monitor-logs.sh
SERVICE_NAME=$1
if [ -z "$SERVICE_NAME" ]; then
echo "Usage: ./monitor-logs.sh {service-name}"
exit 1
fi
# 에러 로그 모니터링
docker logs -f $SERVICE_NAME 2>&1 | grep -i error
```
---
## 자동화 스크립트
### 1. 서비스 재배포 스크립트
```bash
#!/bin/bash
# redeploy.sh
SERVICE_NAME=$1
IMAGE_TAG=${2:-latest}
if [ -z "$SERVICE_NAME" ]; then
echo "Usage: ./redeploy.sh {service-name} [tag]"
exit 1
fi
echo "📦 Pulling latest image..."
docker pull acrdigitalgarage01.azurecr.io/$SERVICE_NAME:$IMAGE_TAG
echo "🛑 Stopping old container..."
docker stop $SERVICE_NAME
docker rm $SERVICE_NAME
echo "🚀 Starting new container..."
docker run -d \
--name $SERVICE_NAME \
--env-file ~/event-marketing.env \
-p 8080:8080 \
acrdigitalgarage01.azurecr.io/$SERVICE_NAME:$IMAGE_TAG
echo "✅ Deployment complete!"
docker logs -f $SERVICE_NAME
```
### 2. 헬스체크 스크립트
```bash
#!/bin/bash
# healthcheck.sh
SERVICE_NAME=$1
MAX_RETRIES=30
RETRY_INTERVAL=2
if [ -z "$SERVICE_NAME" ]; then
echo "Usage: ./healthcheck.sh {service-name}"
exit 1
fi
echo "⏳ Waiting for $SERVICE_NAME to be healthy..."
for i in $(seq 1 $MAX_RETRIES); do
if curl -f http://localhost:8080/actuator/health > /dev/null 2>&1; then
echo "$SERVICE_NAME is healthy!"
exit 0
fi
echo "Attempt $i/$MAX_RETRIES failed. Retrying in ${RETRY_INTERVAL}s..."
sleep $RETRY_INTERVAL
done
echo "$SERVICE_NAME failed to become healthy"
exit 1
```
---
## 보안 고려사항
### 1. 환경 변수 보호
```bash
# .env 파일 권한 설정
chmod 600 ~/event-marketing.env
# 민감 정보는 Azure Key Vault 사용 권장
```
### 2. 컨테이너 보안
```bash
# 읽기 전용 파일시스템으로 실행
docker run -d --read-only ...
# 리소스 제한
docker run -d \
--memory="512m" \
--cpus="0.5" \
...
```
### 3. 네트워크 보안
```bash
# 필요한 포트만 노출
# 내부 통신은 Docker 네트워크 사용
```
---
## 서비스별 실행 예시
### Participation Service
```bash
docker run -d \
--name participation-service \
--network event-marketing-network \
--env-file ~/event-marketing.env \
-e SERVER_PORT=8080 \
-e SPRING_PROFILES_ACTIVE=prod \
-p 8080:8080 \
-v ~/logs/participation:/app/logs \
acrdigitalgarage01.azurecr.io/participation-service:latest
```
### Event Service
```bash
docker run -d \
--name event-service \
--network event-marketing-network \
--env-file ~/event-marketing.env \
-e SERVER_PORT=8081 \
-e SPRING_PROFILES_ACTIVE=prod \
-p 8081:8081 \
-v ~/logs/event:/app/logs \
acrdigitalgarage01.azurecr.io/event-service:latest
```
### User Service
```bash
docker run -d \
--name user-service \
--network event-marketing-network \
--env-file ~/event-marketing.env \
-e SERVER_PORT=8082 \
-e SPRING_PROFILES_ACTIVE=prod \
-p 8082:8082 \
-v ~/logs/user:/app/logs \
acrdigitalgarage01.azurecr.io/user-service:latest
```
### Analytics Service
```bash
docker run -d \
--name analytics-service \
--network event-marketing-network \
--env-file ~/event-marketing.env \
-e SERVER_PORT=8083 \
-e SPRING_PROFILES_ACTIVE=prod \
-p 8083:8083 \
-v ~/logs/analytics:/app/logs \
acrdigitalgarage01.azurecr.io/analytics-service:latest
```
---
이 가이드를 통해 백엔드 서비스를 안전하고 효율적으로 컨테이너로 실행할 수 있습니다. 추가 질문이나 문제가 있으면 언제든지 문의해 주세요! 🚀
+526
View File
@@ -0,0 +1,526 @@
# 백엔드 컨테이너 실행 가이드
작성일: 2025-10-27
작성자: DevOps Engineer
## 1. 개요
KT 이벤트 마케팅 플랫폼의 백엔드 마이크로서비스들을 Docker 컨테이너로 실행하는 방법을 안내합니다.
## 2. 실행 환경 정보
| 항목 | 값 |
|------|-----|
| **Azure Container Registry** | acrdigitalgarage01 |
| **VM IP** | 4.218.10.89 |
| **VM User ID** | azureuser |
| **SSH Private Key** | ~/home/bastion-dg0502 |
| **시스템명** | kt-event-marketing |
## 3. 빌드 가능한 서비스 목록
| 서비스명 | 포트 | 상태 | 비고 |
|---------|------|------|------|
| analytics-service | 8086 | ✅ 빌드 완료 | 컨테이너 이미지 생성됨 |
| participation-service | 8084 | ⏸️ JAR 빌드 완료 | 컨테이너 이미지 생성 필요 |
| event-service | 8080 | ⏸️ JAR 빌드 완료 | 컨테이너 이미지 생성 필요 |
| content-service | 8083 | ⏸️ JAR 빌드 완료 | 컨테이너 이미지 생성 필요 |
## 4. VM 접속 방법
### 4.1 터미널 실행
- **Linux/Mac**: 기본 터미널 실행
- **Windows**: Windows Terminal 실행
### 4.2 SSH Private Key 권한 설정 (최초 1회)
```bash
chmod 400 ~/home/bastion-dg0502
```
### 4.3 VM 접속
```bash
ssh -i ~/home/bastion-dg0502 azureuser@4.218.10.89
```
## 5. 작업 환경 준비
### 5.1 Workspace 디렉토리 생성
```bash
mkdir -p ~/home/workspace
cd ~/home/workspace
```
### 5.2 Git Repository 클론
```bash
git clone https://github.com/ktds-dg0501/kt-event-marketing.git
```
**참고**: 실제 Git Repository 주소로 변경해 주세요.
### 5.3 프로젝트 디렉토리 이동
```bash
cd kt-event-marketing
```
## 6. 애플리케이션 빌드 및 컨테이너 이미지 생성
### 6.1 gradlew 실행 권한 설정 (최초 1회)
VM 환경에서는 gradlew 파일에 실행 권한이 없을 수 있습니다:
```bash
chmod +x gradlew
```
### 6.2 JAR 파일 빌드
```bash
./gradlew :analytics-service:bootJar :content-service:bootJar :event-service:bootJar :participation-service:bootJar --no-daemon
```
**권한 오류 발생 시**:
```bash
bash gradlew :analytics-service:bootJar :content-service:bootJar :event-service:bootJar :participation-service:bootJar --no-daemon
```
### 6.3 Docker 이미지 생성
상세한 가이드는 `deployment/container/build-image.md` 파일을 참조하세요.
## 7. Azure Container Registry (ACR) 작업
### 7.1 ACR 인증 정보 확인
```bash
az acr credential show --name acrdigitalgarage01
```
**출력 예시**:
```json
{
"passwords": [
{
"name": "password",
"value": "<PASSWORD>"
},
{
"name": "password2",
"value": "<PASSWORD2>"
}
],
"username": "acrdigitalgarage01"
}
```
### 7.2 ACR 로그인
위에서 확인한 `username``passwords[0].value`를 사용하여 로그인합니다:
```bash
docker login acrdigitalgarage01.azurecr.io -u acrdigitalgarage01 -p <PASSWORD>
```
## 8. 컨테이너 이미지 푸시
### 8.1 analytics-service
```bash
# 이미지 태그
docker tag analytics-service:latest acrdigitalgarage01.azurecr.io/kt-event-marketing/analytics-service:latest
# ACR로 푸시
docker push acrdigitalgarage01.azurecr.io/kt-event-marketing/analytics-service:latest
```
### 8.2 participation-service
```bash
# 이미지 태그
docker tag participation-service:latest acrdigitalgarage01.azurecr.io/kt-event-marketing/participation-service:latest
# ACR로 푸시
docker push acrdigitalgarage01.azurecr.io/kt-event-marketing/participation-service:latest
```
### 8.3 event-service
```bash
# 이미지 태그
docker tag event-service:latest acrdigitalgarage01.azurecr.io/kt-event-marketing/event-service:latest
# ACR로 푸시
docker push acrdigitalgarage01.azurecr.io/kt-event-marketing/event-service:latest
```
### 8.4 content-service
```bash
# 이미지 태그
docker tag content-service:latest acrdigitalgarage01.azurecr.io/kt-event-marketing/content-service:latest
# ACR로 푸시
docker push acrdigitalgarage01.azurecr.io/kt-event-marketing/content-service:latest
```
## 9. 컨테이너 실행
### 9.1 analytics-service
```bash
SERVER_PORT=8086
docker run -d --name analytics-service --rm -p ${SERVER_PORT}:${SERVER_PORT} \
-e DB_KIND=postgresql \
-e DB_HOST=4.230.49.9 \
-e DB_PORT=5432 \
-e DB_NAME=analyticdb \
-e DB_USERNAME=eventuser \
-e DB_PASSWORD=Hi5Jessica! \
-e DDL_AUTO=update \
-e SHOW_SQL=true \
-e REDIS_HOST=20.214.210.71 \
-e REDIS_PORT=6379 \
-e REDIS_PASSWORD=Hi5Jessica! \
-e REDIS_DATABASE=5 \
-e KAFKA_ENABLED=true \
-e KAFKA_BOOTSTRAP_SERVERS=20.249.182.13:9095,4.217.131.59:9095 \
-e KAFKA_CONSUMER_GROUP_ID=analytics-service-consumers \
-e SAMPLE_DATA_ENABLED=true \
-e SERVER_PORT=8086 \
-e JWT_SECRET=dev-jwt-secret-key-for-development-only-kt-event-marketing \
-e JWT_ACCESS_TOKEN_VALIDITY=1800 \
-e JWT_REFRESH_TOKEN_VALIDITY=86400 \
-e CORS_ALLOWED_ORIGINS="http://localhost:*,http://4.218.10.89:3000" \
-e LOG_FILE=logs/analytics-service.log \
-e LOG_LEVEL_APP=DEBUG \
-e LOG_LEVEL_WEB=INFO \
-e LOG_LEVEL_SQL=DEBUG \
-e LOG_LEVEL_SQL_TYPE=TRACE \
acrdigitalgarage01.azurecr.io/kt-event-marketing/analytics-service:latest
```
### 9.2 participation-service
```bash
SERVER_PORT=8084
docker run -d --name participation-service --rm -p ${SERVER_PORT}:${SERVER_PORT} \
-e DB_HOST=4.230.72.147 \
-e DB_NAME=participationdb \
-e DB_PASSWORD=Hi5Jessica! \
-e DB_PORT=5432 \
-e DB_USERNAME=eventuser \
-e DDL_AUTO=validate \
-e JWT_EXPIRATION=86400000 \
-e JWT_SECRET=kt-event-marketing-secret-key-for-development-only-change-in-production \
-e KAFKA_BOOTSTRAP_SERVERS=20.249.182.13:9095,4.217.131.59:9095 \
-e LOG_FILE=logs/participation-service.log \
-e LOG_LEVEL=INFO \
-e REDIS_HOST=20.214.210.71 \
-e REDIS_PASSWORD=Hi5Jessica! \
-e REDIS_PORT=6379 \
-e SERVER_PORT=8084 \
-e SHOW_SQL=true \
acrdigitalgarage01.azurecr.io/kt-event-marketing/participation-service:latest
```
### 9.3 event-service
**참고**: event-service는 `.run.xml` 파일이 없어 환경변수 설정이 필요합니다.
아래는 `application.yml`을 기반으로 추정한 환경변수입니다.
```bash
SERVER_PORT=8080
docker run -d --name event-service --rm -p ${SERVER_PORT}:${SERVER_PORT} \
-e DB_HOST=<DB_HOST> \
-e DB_PORT=5432 \
-e DB_NAME=eventdb \
-e DB_USERNAME=eventuser \
-e DB_PASSWORD=<DB_PASSWORD> \
-e DDL_AUTO=update \
-e REDIS_HOST=20.214.210.71 \
-e REDIS_PORT=6379 \
-e REDIS_PASSWORD=Hi5Jessica! \
-e KAFKA_BOOTSTRAP_SERVERS=20.249.182.13:9095,4.217.131.59:9095 \
-e SERVER_PORT=8080 \
-e LOG_LEVEL=DEBUG \
-e SQL_LOG_LEVEL=DEBUG \
acrdigitalgarage01.azurecr.io/kt-event-marketing/event-service:latest
```
⚠️ **필수**: `<DB_HOST>``<DB_PASSWORD>`를 실제 값으로 변경해 주세요.
### 9.4 content-service
**참고**: content-service는 `.run.xml` 파일이 없어 환경변수 설정이 필요합니다.
아래는 `application.yml`을 기반으로 추정한 환경변수입니다.
```bash
SERVER_PORT=8083
docker run -d --name content-service --rm -p ${SERVER_PORT}:${SERVER_PORT} \
-e REDIS_HOST=20.214.210.71 \
-e REDIS_PORT=6379 \
-e REDIS_PASSWORD=Hi5Jessica! \
-e SERVER_PORT=8083 \
-e JWT_SECRET=dev-jwt-secret-key \
-e JWT_ACCESS_TOKEN_VALIDITY=3600000 \
-e JWT_REFRESH_TOKEN_VALIDITY=604800000 \
-e AZURE_STORAGE_CONNECTION_STRING=<AZURE_STORAGE_CONNECTION_STRING> \
-e AZURE_CONTAINER_NAME=event-images \
-e LOG_LEVEL_APP=DEBUG \
-e LOG_LEVEL_ROOT=INFO \
-e LOG_FILE=logs/content-service.log \
acrdigitalgarage01.azurecr.io/kt-event-marketing/content-service:latest
```
⚠️ **필수**: `<AZURE_STORAGE_CONNECTION_STRING>`을 실제 값으로 변경해 주세요.
## 10. 실행 확인
### 10.1 컨테이너 실행 상태 확인
```bash
# 전체 컨테이너 확인
docker ps
# 특정 서비스 확인
docker ps | grep analytics-service
docker ps | grep participation-service
docker ps | grep event-service
docker ps | grep content-service
```
### 10.2 컨테이너 로그 확인
```bash
# 실시간 로그 확인
docker logs -f analytics-service
docker logs -f participation-service
docker logs -f event-service
docker logs -f content-service
# 최근 100줄 로그 확인
docker logs --tail 100 analytics-service
```
### 10.3 헬스체크
```bash
# analytics-service
curl http://4.218.10.89:8086/actuator/health
# participation-service
curl http://4.218.10.89:8084/actuator/health
# event-service
curl http://4.218.10.89:8080/actuator/health
# content-service
curl http://4.218.10.89:8083/actuator/health
```
## 11. 재배포 방법
### 11.1 로컬에서 수정된 소스 푸시
로컬 개발 환경에서 코드 수정 후:
```bash
git add .
git commit -m "변경 사항"
git push
```
### 11.2 VM 접속
```bash
ssh -i ~/home/bastion-dg0502 azureuser@4.218.10.89
```
### 11.3 디렉토리 이동 및 소스 내려받기
```bash
cd ~/home/workspace/kt-event-marketing
git pull
```
### 11.4 컨테이너 이미지 재생성
**JAR 파일 빌드**:
```bash
./gradlew :analytics-service:bootJar :content-service:bootJar :event-service:bootJar :participation-service:bootJar --no-daemon
```
**Docker 이미지 빌드** (예: analytics-service):
```bash
docker build \
--platform linux/amd64 \
--build-arg BUILD_LIB_DIR="analytics-service/build/libs" \
--build-arg ARTIFACTORY_FILE="analytics-service.jar" \
-f deployment/container/Dockerfile-backend \
-t analytics-service:latest .
```
상세한 가이드는 `deployment/container/build-image.md` 파일을 참조하세요.
### 11.5 컨테이너 이미지 푸시
**analytics-service 예시**:
```bash
docker tag analytics-service:latest acrdigitalgarage01.azurecr.io/kt-event-marketing/analytics-service:latest
docker push acrdigitalgarage01.azurecr.io/kt-event-marketing/analytics-service:latest
```
### 11.6 컨테이너 중지
```bash
docker stop analytics-service
docker stop participation-service
docker stop event-service
docker stop content-service
```
### 11.7 컨테이너 이미지 삭제 (선택사항)
```bash
docker rmi acrdigitalgarage01.azurecr.io/kt-event-marketing/analytics-service:latest
docker rmi acrdigitalgarage01.azurecr.io/kt-event-marketing/participation-service:latest
docker rmi acrdigitalgarage01.azurecr.io/kt-event-marketing/event-service:latest
docker rmi acrdigitalgarage01.azurecr.io/kt-event-marketing/content-service:latest
```
### 11.8 컨테이너 재실행
위의 [9. 컨테이너 실행](#9-컨테이너-실행) 섹션의 명령어를 다시 실행합니다.
## 12. 일괄 실행 스크립트
### 12.1 전체 서비스 중지
```bash
docker stop analytics-service participation-service event-service content-service
```
### 12.2 전체 서비스 시작 (Bash 스크립트)
**실행 전 주의사항**:
- event-service와 content-service의 환경변수 값을 실제 값으로 변경해야 합니다.
```bash
#!/bin/bash
# analytics-service 실행
SERVER_PORT=8086
docker run -d --name analytics-service --rm -p ${SERVER_PORT}:${SERVER_PORT} \
-e DB_KIND=postgresql \
-e DB_HOST=4.230.49.9 \
-e DB_PORT=5432 \
-e DB_NAME=analyticdb \
-e DB_USERNAME=eventuser \
-e DB_PASSWORD=Hi5Jessica! \
-e DDL_AUTO=update \
-e SHOW_SQL=true \
-e REDIS_HOST=20.214.210.71 \
-e REDIS_PORT=6379 \
-e REDIS_PASSWORD=Hi5Jessica! \
-e REDIS_DATABASE=5 \
-e KAFKA_ENABLED=true \
-e KAFKA_BOOTSTRAP_SERVERS=20.249.182.13:9095,4.217.131.59:9095 \
-e KAFKA_CONSUMER_GROUP_ID=analytics-service-consumers \
-e SAMPLE_DATA_ENABLED=true \
-e SERVER_PORT=8086 \
-e JWT_SECRET=dev-jwt-secret-key-for-development-only-kt-event-marketing \
-e JWT_ACCESS_TOKEN_VALIDITY=1800 \
-e JWT_REFRESH_TOKEN_VALIDITY=86400 \
-e CORS_ALLOWED_ORIGINS="http://localhost:*,http://4.218.10.89:3000" \
-e LOG_FILE=logs/analytics-service.log \
-e LOG_LEVEL_APP=DEBUG \
-e LOG_LEVEL_WEB=INFO \
-e LOG_LEVEL_SQL=DEBUG \
-e LOG_LEVEL_SQL_TYPE=TRACE \
acrdigitalgarage01.azurecr.io/kt-event-marketing/analytics-service:latest
echo "✅ analytics-service started on port 8086"
# participation-service 실행
SERVER_PORT=8084
docker run -d --name participation-service --rm -p ${SERVER_PORT}:${SERVER_PORT} \
-e DB_HOST=4.230.72.147 \
-e DB_NAME=participationdb \
-e DB_PASSWORD=Hi5Jessica! \
-e DB_PORT=5432 \
-e DB_USERNAME=eventuser \
-e DDL_AUTO=validate \
-e JWT_EXPIRATION=86400000 \
-e JWT_SECRET=kt-event-marketing-secret-key-for-development-only-change-in-production \
-e KAFKA_BOOTSTRAP_SERVERS=20.249.182.13:9095,4.217.131.59:9095 \
-e LOG_FILE=logs/participation-service.log \
-e LOG_LEVEL=INFO \
-e REDIS_HOST=20.214.210.71 \
-e REDIS_PASSWORD=Hi5Jessica! \
-e REDIS_PORT=6379 \
-e SERVER_PORT=8084 \
-e SHOW_SQL=true \
acrdigitalgarage01.azurecr.io/kt-event-marketing/participation-service:latest
echo "✅ participation-service started on port 8084"
# 실행 확인
echo ""
echo "🔍 Running containers:"
docker ps | grep -E "analytics-service|participation-service"
```
## 13. 문제 해결
### 13.1 컨테이너가 즉시 종료되는 경우
**로그 확인**:
```bash
docker logs <container-name>
```
**일반적인 원인**:
- 환경변수 누락 또는 잘못된 값
- 데이터베이스/Redis/Kafka 연결 실패
- 포트 충돌
### 13.2 ACR 로그인 실패
**인증 정보 재확인**:
```bash
az acr credential show --name acrdigitalgarage01
```
**다시 로그인**:
```bash
docker logout acrdigitalgarage01.azurecr.io
docker login acrdigitalgarage01.azurecr.io -u <username> -p <password>
```
### 13.3 포트 충돌
**포트 사용 확인**:
```bash
netstat -tuln | grep <PORT>
```
**다른 포트로 변경**:
```bash
SERVER_PORT=<NEW_PORT>
docker run -d -p ${SERVER_PORT}:${SERVER_PORT} ...
```
## 14. 참고 자료
- 컨테이너 이미지 빌드 가이드: `deployment/container/build-image.md`
- Docker 공식 문서: https://docs.docker.com/
- Azure Container Registry 문서: https://docs.microsoft.com/azure/container-registry/
@@ -14,7 +14,7 @@ import lombok.*;
@Entity @Entity
@Table(name = "draw_logs", @Table(name = "draw_logs",
indexes = { indexes = {
@Index(name = "idx_draw_log_event_id", columnList = "event_id") @Index(name = "idx_event_id", columnList = "event_id")
} }
) )
@Getter @Getter
@@ -13,7 +13,7 @@ import lombok.*;
@Entity @Entity
@Table(name = "participants", @Table(name = "participants",
indexes = { indexes = {
@Index(name = "idx_participant_event_id", columnList = "event_id"), @Index(name = "idx_event_id", columnList = "event_id"),
@Index(name = "idx_event_phone", columnList = "event_id, phone_number") @Index(name = "idx_event_phone", columnList = "event_id, phone_number")
}, },
uniqueConstraints = { uniqueConstraints = {
@@ -24,8 +24,6 @@ public class SecurityConfig {
.csrf(csrf -> csrf.disable()) .csrf(csrf -> csrf.disable())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth .authorizeHttpRequests(auth -> auth
// Actuator endpoints
.requestMatchers("/actuator/**").permitAll()
.anyRequest().permitAll() .anyRequest().permitAll()
); );
@@ -73,19 +73,3 @@ logging:
max-file-size: 10MB max-file-size: 10MB
max-history: 7 max-history: 7
total-size-cap: 100MB total-size-cap: 100MB
# Actuator
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
base-path: /actuator
endpoint:
health:
show-details: always
show-components: always
health:
livenessState:
enabled: true
readinessState:
enabled: true
@@ -5,10 +5,8 @@ import com.kt.event.common.security.JwtTokenProvider;
import com.kt.event.user.dto.request.LoginRequest; import com.kt.event.user.dto.request.LoginRequest;
import com.kt.event.user.dto.response.LoginResponse; import com.kt.event.user.dto.response.LoginResponse;
import com.kt.event.user.dto.response.LogoutResponse; import com.kt.event.user.dto.response.LogoutResponse;
import com.kt.event.user.entity.Store;
import com.kt.event.user.entity.User; import com.kt.event.user.entity.User;
import com.kt.event.user.exception.UserErrorCode; import com.kt.event.user.exception.UserErrorCode;
import com.kt.event.user.repository.StoreRepository;
import com.kt.event.user.repository.UserRepository; import com.kt.event.user.repository.UserRepository;
import com.kt.event.user.service.AuthenticationService; import com.kt.event.user.service.AuthenticationService;
import com.kt.event.user.service.UserService; import com.kt.event.user.service.UserService;
@@ -36,7 +34,6 @@ import java.util.concurrent.TimeUnit;
public class AuthenticationServiceImpl implements AuthenticationService { public class AuthenticationServiceImpl implements AuthenticationService {
private final UserRepository userRepository; private final UserRepository userRepository;
private final StoreRepository storeRepository;
private final PasswordEncoder passwordEncoder; private final PasswordEncoder passwordEncoder;
private final JwtTokenProvider jwtTokenProvider; private final JwtTokenProvider jwtTokenProvider;
private final UserService userService; private final UserService userService;
@@ -45,12 +42,10 @@ public class AuthenticationServiceImpl implements AuthenticationService {
private RedisTemplate<String, Object> redisTemplate; private RedisTemplate<String, Object> redisTemplate;
public AuthenticationServiceImpl(UserRepository userRepository, public AuthenticationServiceImpl(UserRepository userRepository,
StoreRepository storeRepository,
PasswordEncoder passwordEncoder, PasswordEncoder passwordEncoder,
JwtTokenProvider jwtTokenProvider, JwtTokenProvider jwtTokenProvider,
UserService userService) { UserService userService) {
this.userRepository = userRepository; this.userRepository = userRepository;
this.storeRepository = storeRepository;
this.passwordEncoder = passwordEncoder; this.passwordEncoder = passwordEncoder;
this.jwtTokenProvider = jwtTokenProvider; this.jwtTokenProvider = jwtTokenProvider;
this.userService = userService; this.userService = userService;
@@ -73,26 +68,21 @@ public class AuthenticationServiceImpl implements AuthenticationService {
throw new BusinessException(UserErrorCode.AUTH_FAILED.getErrorCode()); throw new BusinessException(UserErrorCode.AUTH_FAILED.getErrorCode());
} }
// 3. 매장 정보 조회 // 3. JWT 토큰 생성
Store store = storeRepository.findByUserId(user.getId()).orElse(null);
Long storeId = store != null ? store.getId() : null;
// 4. JWT 토큰 생성
String token = jwtTokenProvider.createAccessToken( String token = jwtTokenProvider.createAccessToken(
user.getId(), user.getId(),
storeId,
user.getEmail(), user.getEmail(),
user.getName(), user.getName(),
List.of(user.getRole().name()) List.of(user.getRole().name())
); );
// 5. Redis 세션 저장 (TTL 7일) // 4. Redis 세션 저장 (TTL 7일)
saveSession(token, user.getId(), user.getRole().name()); saveSession(token, user.getId(), user.getRole().name());
// 6. 최종 로그인 시각 업데이트 (비동기) // 5. 최종 로그인 시각 업데이트 (비동기)
userService.updateLastLoginAt(user.getId()); userService.updateLastLoginAt(user.getId());
// 7. 응답 반환 // 6. 응답 반환
return LoginResponse.builder() return LoginResponse.builder()
.token(token) .token(token)
.userId(user.getId()) .userId(user.getId())
@@ -103,7 +103,6 @@ public class UserServiceImpl implements UserService {
// 6. JWT 토큰 생성 // 6. JWT 토큰 생성
String token = jwtTokenProvider.createAccessToken( String token = jwtTokenProvider.createAccessToken(
savedUser.getId(), savedUser.getId(),
savedStore.getId(),
savedUser.getEmail(), savedUser.getEmail(),
savedUser.getName(), savedUser.getName(),
List.of(savedUser.getRole().name()) List.of(savedUser.getRole().name())