Event Service 컨테이너 이미지 빌드 및 타입 시스템 통일

- UserPrincipal userId/storeId 타입을 Long에서 UUID로 변경
- JwtTokenProvider UUID 파싱 로직 수정
- event-service build.gradle에 bootJar 설정 추가
- Docker 이미지 빌드 성공 (event-service:latest, 1.08GB)
- 컨테이너 이미지 빌드 가이드 문서 작성

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
merrycoral 2025-10-28 14:41:48 +09:00
parent f07002ac33
commit 89a86c1301
4 changed files with 239 additions and 243 deletions

View File

@ -113,9 +113,9 @@ 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); String storeIdStr = claims.get("storeId", String.class);
Long storeId = storeIdStr != null ? Long.parseLong(storeIdStr) : null; UUID storeId = storeIdStr != null ? UUID.fromString(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")

View File

@ -24,12 +24,12 @@ public class UserPrincipal implements UserDetails {
/** /**
* 사용자 ID * 사용자 ID
*/ */
private final Long userId; private final UUID userId;
/** /**
* 매장 ID * 매장 ID
*/ */
private final Long storeId; private final UUID storeId;
/** /**
* 사용자 이메일 * 사용자 이메일

View File

@ -1,187 +1,195 @@
# Content Service 컨테이너 이미지 빌드 및 배포 가이드 # Event Service 컨테이너 이미지 빌드 가이드
## 1. 사전 준비사항 ## 1. 빌드 일시
- **빌드 날짜**: 2025-10-28
- **빌드 시간**: 14:35 KST
### 필수 소프트웨어 ## 2. 수정 사항
- **Docker Desktop**: Docker 컨테이너 실행 환경
- **JDK 23**: Java 애플리케이션 빌드
- **Gradle**: 프로젝트 빌드 도구
### 외부 서비스 ### 2.1 타입 불일치 수정
- **Redis 서버**: 20.214.210.71:6379 Event Service 컴파일 오류 해결을 위해 다음 파일들을 수정했습니다:
- **Kafka 서버**: 4.230.50.63:9092
- **Replicate API**: Stable Diffusion 이미지 생성
- **Azure Blob Storage**: 이미지 CDN
## 2. 빌드 설정 #### UserPrincipal.java (common 모듈)
- **파일 경로**: `common/src/main/java/com/kt/event/common/security/UserPrincipal.java`
- **수정 내용**: userId와 storeId 타입을 Long에서 UUID로 변경
- **변경 이유**: EventService의 메서드 시그니처가 UUID를 기대하므로 일관성 유지
```java
// Before
private final Long userId;
private final Long storeId;
// After
private final UUID userId;
private final UUID storeId;
```
#### JwtTokenProvider.java (common 모듈)
- **파일 경로**: `common/src/main/java/com/kt/event/common/security/JwtTokenProvider.java`
- **수정 내용**: JWT 토큰 파싱 시 Long.parseLong()을 UUID.fromString()으로 변경
- **변경 이유**: UserPrincipal의 타입 변경에 따른 파싱 로직 수정
```java
// Before
Long userId = Long.parseLong(claims.getSubject());
Long storeId = storeIdStr != null ? Long.parseLong(storeIdStr) : null;
// After
UUID userId = UUID.fromString(claims.getSubject());
UUID storeId = storeIdStr != null ? UUID.fromString(storeIdStr) : null;
```
#### event-service/build.gradle
- **수정 내용**: bootJar 설정 추가
- **변경 이유**: 컨테이너 이미지 빌드를 위한 JAR 파일명 명시
### build.gradle 설정 (content-service/build.gradle)
```gradle ```gradle
// 실행 JAR 파일명 설정
bootJar { bootJar {
archiveFileName = 'content-service.jar' archiveFileName = 'event-service.jar'
} }
``` ```
## 3. 배포 파일 구조 ## 3. 빌드 명령어
``` ### 3.1 Common 모듈 컴파일
deployment/
└── container/
├── Dockerfile-backend # 백엔드 서비스용 Dockerfile
├── docker-compose.yml # Docker Compose 설정
└── build-and-run.sh # 자동화 배포 스크립트
```
## 4. 수동 빌드 및 배포
### 4.1 Gradle 빌드
```bash ```bash
# 프로젝트 루트에서 실행 ./gradlew common:compileJava
./gradlew clean content-service:bootJar
``` ```
### 4.2 Docker 이미지 빌드 **결과**: BUILD SUCCESSFUL in 6s
```bash
DOCKER_FILE=deployment/container/Dockerfile-backend
### 3.2 Event Service 컴파일
```bash
./gradlew event-service:compileJava
```
**결과**: BUILD SUCCESSFUL in 6s
### 3.3 Event Service JAR 빌드
```bash
./gradlew event-service:bootJar
```
**결과**:
- BUILD SUCCESSFUL in 5s
- JAR 파일 생성: `event-service/build/libs/event-service.jar` (94MB)
### 3.4 Docker 이미지 빌드
```bash
docker build \ docker build \
--platform linux/amd64 \ --platform linux/amd64 \
--build-arg BUILD_LIB_DIR="content-service/build/libs" \ --build-arg BUILD_LIB_DIR="event-service/build/libs" \
--build-arg ARTIFACTORY_FILE="content-service.jar" \ --build-arg ARTIFACTORY_FILE="event-service.jar" \
-f ${DOCKER_FILE} \
-t content-service:latest .
```
### 4.3 빌드된 이미지 확인
```bash
docker images | grep content-service
```
예상 출력:
```
content-service latest abc123def456 2 minutes ago 450MB
```
### 4.4 Docker Compose로 컨테이너 실행
```bash
docker-compose -f deployment/container/docker-compose.yml up -d
```
### 4.5 컨테이너 상태 확인
```bash
# 실행 중인 컨테이너 확인
docker ps
# 로그 확인
docker logs -f content-service
# 헬스체크
curl http://localhost:8084/actuator/health
```
## 5. 자동화 배포 스크립트 사용 (권장)
### 5.1 스크립트 실행
```bash
# 프로젝트 루트에서 실행
./deployment/container/build-and-run.sh
```
### 5.2 스크립트 수행 단계
1. Gradle 빌드
2. Docker 이미지 빌드
3. 이미지 확인
4. 기존 컨테이너 정리
5. 새 컨테이너 실행
## 6. 환경변수 설정
`docker-compose.yml`에 다음 환경변수가 설정되어 있습니다:
### 필수 환경변수
- `SPRING_PROFILES_ACTIVE`: Spring Profile (prod)
- `SERVER_PORT`: 서버 포트 (8084)
- `REDIS_HOST`: Redis 호스트
- `REDIS_PORT`: Redis 포트
- `REDIS_PASSWORD`: Redis 비밀번호
- `JWT_SECRET`: JWT 서명 키 (최소 32자)
- `REPLICATE_API_TOKEN`: Replicate API 토큰
- `AZURE_STORAGE_CONNECTION_STRING`: Azure Storage 연결 문자열
- `AZURE_CONTAINER_NAME`: Azure Storage 컨테이너 이름
### JWT_SECRET 요구사항
- **최소 길이**: 32자 이상 (256비트)
- **형식**: 영문자, 숫자 조합
- **예시**: `kt-event-marketing-jwt-secret-key-for-authentication-and-authorization-2025`
## 7. VM 배포
### 7.1 VM에 파일 전송
```bash
# VM으로 파일 복사 (예시)
scp -r deployment/ user@vm-host:/path/to/project/
scp docker-compose.yml user@vm-host:/path/to/project/deployment/container/
scp content-service/build/libs/content-service.jar user@vm-host:/path/to/project/content-service/build/libs/
```
### 7.2 VM에서 이미지 빌드
```bash
# VM에 SSH 접속 후
cd /path/to/project
# 이미지 빌드
docker build \
--platform linux/amd64 \
--build-arg BUILD_LIB_DIR="content-service/build/libs" \
--build-arg ARTIFACTORY_FILE="content-service.jar" \
-f deployment/container/Dockerfile-backend \ -f deployment/container/Dockerfile-backend \
-t content-service:latest . -t event-service:latest .
``` ```
### 7.3 VM에서 컨테이너 실행 **결과**: 이미지 빌드 성공
```bash - Image ID: bbeecf2ccaf2
# Docker Compose로 실행 - Size: 1.08GB
docker-compose -f deployment/container/docker-compose.yml up -d - Created: 19 seconds ago
# 또는 직접 실행 ## 4. 빌드 검증
### 4.1 JAR 파일 확인
```bash
ls -lh event-service/build/libs/
```
**출력**:
```
-rw-r--r-- 1 KTDS 197121 94M 10월 28 14:35 event-service.jar
```
### 4.2 Docker 이미지 확인
```bash
docker images | grep event-service
```
**출력**:
```
event-service latest bbeecf2ccaf2 19 seconds ago 1.08GB
```
## 5. Dockerfile 구조
**파일 위치**: `deployment/container/Dockerfile-backend`
### 빌드 스테이지 (Build Stage)
- **Base Image**: openjdk:23-oraclelinux8
- **작업**: JAR 파일 복사
### 실행 스테이지 (Run Stage)
- **Base Image**: openjdk:23-slim
- **사용자**: k8s (non-root user)
- **작업 디렉토리**: /home/k8s
- **진입점**: `java ${JAVA_OPTS} -jar app.jar`
## 6. 컨테이너 실행 가이드
### 6.1 기본 실행
```bash
docker run -d \ docker run -d \
--name content-service \ --name event-service \
-p 8084:8084 \ -p 8082:8082 \
-e SPRING_PROFILES_ACTIVE=prod \ -e SPRING_PROFILES_ACTIVE=dev \
-e SERVER_PORT=8084 \ -e SERVER_PORT=8082 \
-e REDIS_HOST=20.214.210.71 \ event-service:latest
-e REDIS_PORT=6379 \
-e REDIS_PASSWORD=Hi5Jessica! \
-e JWT_SECRET=kt-event-marketing-jwt-secret-key-for-authentication-and-authorization-2025 \
-e REPLICATE_API_TOKEN=r8_Q33U00fSnpjYlHNIRglwurV446h7g8V2wkFFa \
-e AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=https;AccountName=blobkteventstorage;AccountKey=tcBN7mAfojbl0uGsOpU7RNuKNhHnzmwDiWjN31liSMVSrWaEK+HHnYKZrjBXXAC6ZPsuxUDlsf8x+AStd++QYg==;EndpointSuffix=core.windows.net" \
-e AZURE_CONTAINER_NAME=content-images \
content-service:latest
``` ```
## 8. 모니터링 및 로그 ### 6.2 환경변수 설정
Event Service 실행을 위한 주요 환경변수:
### 8.1 컨테이너 상태 확인 #### 필수 환경변수
- `SERVER_PORT`: 서버 포트 (기본값: 8082)
- `DB_HOST`: PostgreSQL 호스트
- `DB_PORT`: PostgreSQL 포트 (기본값: 5432)
- `DB_NAME`: 데이터베이스 이름
- `DB_USERNAME`: 데이터베이스 사용자명
- `DB_PASSWORD`: 데이터베이스 비밀번호
- `REDIS_HOST`: Redis 호스트
- `REDIS_PORT`: Redis 포트 (기본값: 6379)
- `REDIS_PASSWORD`: Redis 비밀번호
- `KAFKA_BOOTSTRAP_SERVERS`: Kafka 브로커 주소
- `JWT_SECRET`: JWT 서명 키 (최소 32자)
#### 선택 환경변수
- `DISTRIBUTION_SERVICE_URL`: Distribution Service URL
- `JAVA_OPTS`: JVM 옵션
### 6.3 Docker Compose 실행 예시
```yaml
services:
event-service:
image: event-service:latest
container_name: event-service
ports:
- "8082:8082"
environment:
- SPRING_PROFILES_ACTIVE=prod
- SERVER_PORT=8082
- DB_HOST=your-db-host
- DB_PORT=5432
- DB_NAME=event_db
- DB_USERNAME=event_user
- DB_PASSWORD=your-password
- REDIS_HOST=your-redis-host
- REDIS_PORT=6379
- REDIS_PASSWORD=your-redis-password
- KAFKA_BOOTSTRAP_SERVERS=your-kafka:9092
- JWT_SECRET=your-jwt-secret-key-minimum-32-characters
- DISTRIBUTION_SERVICE_URL=http://distribution-service:8086
restart: unless-stopped
```
## 7. 헬스체크
### 7.1 Spring Boot Actuator
```bash ```bash
docker ps curl http://localhost:8082/actuator/health
``` ```
### 8.2 로그 확인 **예상 응답**:
```bash
# 실시간 로그
docker logs -f content-service
# 최근 100줄
docker logs --tail 100 content-service
```
### 8.3 헬스체크
```bash
curl http://localhost:8084/actuator/health
```
예상 응답:
```json ```json
{ {
"status": "UP", "status": "UP",
@ -189,6 +197,9 @@ curl http://localhost:8084/actuator/health
"ping": { "ping": {
"status": "UP" "status": "UP"
}, },
"db": {
"status": "UP"
},
"redis": { "redis": {
"status": "UP" "status": "UP"
} }
@ -196,92 +207,70 @@ curl http://localhost:8084/actuator/health
} }
``` ```
## 9. Swagger UI 접근 ### 7.2 Swagger UI
배포 후 Swagger UI로 API 테스트 가능:
``` ```
http://localhost:8084/swagger-ui/index.html http://localhost:8082/swagger-ui/index.html
``` ```
## 10. 이미지 생성 API 테스트 ## 8. 빌드 결과 요약
### 10.1 이미지 생성 요청 ### 서비스 정보
```bash - **서비스명**: event-service
curl -X POST "http://localhost:8084/api/v1/content/images/generate" \ - **포트**: 8082
-H "Content-Type: application/json" \ - **JAR 크기**: 94MB
-d '{ - **이미지 크기**: 1.08GB
"eventDraftId": 1001,
"industry": "고깃집",
"location": "강남",
"trends": ["가을", "단풍", "BBQ"],
"styles": ["FANCY"],
"platforms": ["INSTAGRAM"]
}'
```
### 10.2 Job 상태 확인
```bash
curl http://localhost:8084/api/v1/content/jobs/{jobId}
```
## 11. 컨테이너 관리 명령어
### 11.1 컨테이너 중지
```bash
docker-compose -f deployment/container/docker-compose.yml down
```
### 11.2 컨테이너 재시작
```bash
docker-compose -f deployment/container/docker-compose.yml restart
```
### 11.3 컨테이너 삭제
```bash
# 컨테이너만 삭제
docker rm -f content-service
# 이미지도 삭제
docker rmi content-service:latest
```
## 12. 트러블슈팅
### 12.1 JWT 토큰 오류
**증상**: `Error creating bean with name 'jwtTokenProvider'`
**해결방법**:
- `JWT_SECRET` 환경변수가 32자 이상인지 확인
- docker-compose.yml에 올바르게 설정되어 있는지 확인
### 12.2 Redis 연결 오류
**증상**: `Unable to connect to Redis`
**해결방법**:
- Redis 서버(20.214.210.71:6379)가 실행 중인지 확인
- 방화벽 설정 확인
- 비밀번호 확인
### 12.3 Azure Storage 오류
**증상**: `Azure storage connection failed`
**해결방법**:
- `AZURE_STORAGE_CONNECTION_STRING`이 올바른지 확인
- Storage Account가 활성화되어 있는지 확인
- 컨테이너 이름(`content-images`)이 존재하는지 확인
## 13. 빌드 결과
### 빌드 정보
- **서비스명**: content-service
- **JAR 파일**: content-service.jar
- **Docker 이미지**: content-service:latest
- **노출 포트**: 8084
### 빌드 일시
- **빌드 날짜**: 2025-10-27
### 환경
- **Base Image**: openjdk:23-slim - **Base Image**: openjdk:23-slim
- **Platform**: linux/amd64 - **Platform**: linux/amd64
- **User**: k8s (non-root)
### 빌드 통계
- **Common 컴파일**: 6초
- **Event Service 컴파일**: 6초
- **JAR 빌드**: 5초
- **Docker 이미지 빌드**: 약 120초
### 주요 의존성
- Spring Boot Actuator
- Spring Kafka
- Spring Data Redis
- Spring Cloud OpenFeign
- PostgreSQL Driver
- Jackson
## 9. 트러블슈팅
### 9.1 컴파일 오류 해결
**증상**: userId/storeId 타입 불일치 오류
**해결**:
- UserPrincipal의 userId, storeId를 UUID로 변경
- JwtTokenProvider의 파싱 로직을 UUID.fromString()으로 수정
### 9.2 Gradle Clean 오류
**증상**: `Unable to delete directory 'common\build'`
**해결**: clean 없이 빌드 수행
```bash
./gradlew event-service:bootJar
```
### 9.3 Docker 빌드 컨텍스트 오류
**증상**: JAR 파일을 찾을 수 없음
**해결**:
- JAR 파일이 실제로 빌드되었는지 확인
- 빌드 아규먼트 경로가 올바른지 확인
## 10. 다음 단계
1. **컨테이너 테스트**: 로컬 환경에서 컨테이너 실행 및 API 테스트
2. **환경변수 설정**: 운영 환경에 맞는 환경변수 구성
3. **통합 테스트**: 다른 마이크로서비스들과의 통합 테스트
4. **이미지 레지스트리 푸시**: Docker Hub 또는 사설 레지스트리에 이미지 업로드
5. **Kubernetes 배포**: K8s 클러스터에 배포
## 11. 참고사항
- **개발 환경 인증**: DevAuthenticationFilter가 자동으로 테스트용 UserPrincipal 생성
- **프로덕션 배포**: DevAuthenticationFilter 비활성화 및 실제 JWT 인증 필터 활성화 필요
- **보안**: JWT_SECRET은 안전하게 관리하고 최소 32자 이상 사용
- **성능**: JAVA_OPTS를 통해 JVM 메모리 설정 최적화 권장

View File

@ -1,4 +1,11 @@
bootJar {
archiveFileName = 'event-service.jar'
}
dependencies { dependencies {
// Actuator for health checks and monitoring
implementation 'org.springframework.boot:spring-boot-starter-actuator'
// Kafka for job publishing // Kafka for job publishing
implementation 'org.springframework.kafka:spring-kafka' implementation 'org.springframework.kafka:spring-kafka'