백엔드 서비스 설정 및 배포 구성 개선
- CORS 설정 업데이트 (모든 서비스) - Swagger UI 경로 및 설정 수정 - Kubernetes 배포 설정 개선 (Ingress, Deployment) - distribution-service SecurityConfig 및 Controller 개선 - IntelliJ 실행 프로파일 업데이트 - 컨테이너 이미지 빌드 문서화 (deployment/container/build-image.md) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
3075a5d49f
commit
3da9303091
@ -41,21 +41,21 @@ spec:
|
|||||||
memory: "1024Mi"
|
memory: "1024Mi"
|
||||||
startupProbe:
|
startupProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: /actuator/health
|
path: /api/v1/distribution/actuator/health
|
||||||
port: 8085
|
port: 8085
|
||||||
initialDelaySeconds: 30
|
initialDelaySeconds: 30
|
||||||
periodSeconds: 10
|
periodSeconds: 10
|
||||||
failureThreshold: 30
|
failureThreshold: 30
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: /actuator/health/readiness
|
path: /api/v1/distribution/actuator/health/readiness
|
||||||
port: 8085
|
port: 8085
|
||||||
initialDelaySeconds: 10
|
initialDelaySeconds: 10
|
||||||
periodSeconds: 5
|
periodSeconds: 5
|
||||||
failureThreshold: 3
|
failureThreshold: 3
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: /actuator/health/liveness
|
path: /api/v1/distribution/actuator/health/liveness
|
||||||
port: 8085
|
port: 8085
|
||||||
initialDelaySeconds: 30
|
initialDelaySeconds: 30
|
||||||
periodSeconds: 10
|
periodSeconds: 10
|
||||||
|
|||||||
@ -39,7 +39,7 @@
|
|||||||
<entry key="JWT_REFRESH_TOKEN_VALIDITY" value="86400" />
|
<entry key="JWT_REFRESH_TOKEN_VALIDITY" value="86400" />
|
||||||
|
|
||||||
<!-- CORS Configuration -->
|
<!-- CORS Configuration -->
|
||||||
<entry key="CORS_ALLOWED_ORIGINS" value="http://localhost:*" />
|
<entry key="CORS_ALLOWED_ORIGINS" value="http://localhost:*,http://*.nip.io:*" />
|
||||||
|
|
||||||
<!-- Logging Configuration -->
|
<!-- Logging Configuration -->
|
||||||
<entry key="LOG_FILE" value="logs/analytics-service.log" />
|
<entry key="LOG_FILE" value="logs/analytics-service.log" />
|
||||||
|
|||||||
@ -84,7 +84,11 @@ jwt:
|
|||||||
|
|
||||||
# CORS Configuration
|
# CORS Configuration
|
||||||
cors:
|
cors:
|
||||||
allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost:*}
|
allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost:8081,http://localhost:8082,http://localhost:8083,http://localhost:8084,http://kt-event-marketing.20.214.196.128.nip.io}
|
||||||
|
allowed-methods: ${CORS_ALLOWED_METHODS:GET,POST,PUT,DELETE,OPTIONS,PATCH}
|
||||||
|
allowed-headers: ${CORS_ALLOWED_HEADERS:*}
|
||||||
|
allow-credentials: ${CORS_ALLOW_CREDENTIALS:true}
|
||||||
|
max-age: ${CORS_MAX_AGE:3600}
|
||||||
|
|
||||||
# Actuator
|
# Actuator
|
||||||
management:
|
management:
|
||||||
|
|||||||
@ -40,7 +40,11 @@ replicate:
|
|||||||
|
|
||||||
# CORS Configuration
|
# CORS Configuration
|
||||||
cors:
|
cors:
|
||||||
allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost:*}
|
allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost:8081,http://localhost:8082,http://localhost:8083,http://localhost:8084,http://kt-event-marketing.20.214.196.128.nip.io}
|
||||||
|
allowed-methods: ${CORS_ALLOWED_METHODS:GET,POST,PUT,DELETE,OPTIONS,PATCH}
|
||||||
|
allowed-headers: ${CORS_ALLOWED_HEADERS:*}
|
||||||
|
allow-credentials: ${CORS_ALLOW_CREDENTIALS:true}
|
||||||
|
max-age: ${CORS_MAX_AGE:3600}
|
||||||
|
|
||||||
# Actuator
|
# Actuator
|
||||||
management:
|
management:
|
||||||
|
|||||||
@ -1,68 +1,57 @@
|
|||||||
# 백엔드 컨테이너 이미지 작성 결과
|
# 백엔드 컨테이너 이미지 빌드 결과
|
||||||
|
|
||||||
## 작업 개요
|
## 개요
|
||||||
- **작업일시**: 2025-10-29
|
KT 이벤트 마케팅 서비스의 백엔드 마이크로서비스들에 대한 컨테이너 이미지를 생성하였습니다.
|
||||||
- **작성자**: DevOps Engineer (송근정 "데브옵스 마스터")
|
|
||||||
- **대상 서비스**: 6개 백엔드 마이크로서비스
|
|
||||||
|
|
||||||
## 1. 서비스 확인
|
## 작업 일시
|
||||||
|
- 날짜: 2025-10-29
|
||||||
|
- 빌드 환경: Windows (MINGW64_NT-10.0-19045)
|
||||||
|
|
||||||
### settings.gradle 분석
|
## 서비스 목록 확인
|
||||||
```gradle
|
|
||||||
|
settings.gradle에서 확인한 서비스 목록:
|
||||||
|
```
|
||||||
rootProject.name = 'kt-event-marketing'
|
rootProject.name = 'kt-event-marketing'
|
||||||
|
|
||||||
// Common module
|
|
||||||
include 'common'
|
include 'common'
|
||||||
|
|
||||||
// Microservices
|
|
||||||
include 'user-service'
|
include 'user-service'
|
||||||
include 'event-service'
|
include 'event-service'
|
||||||
include 'ai-service'
|
include 'ai-service'
|
||||||
include 'content-service'
|
|
||||||
include 'distribution-service'
|
include 'distribution-service'
|
||||||
include 'participation-service'
|
include 'participation-service'
|
||||||
include 'analytics-service'
|
include 'analytics-service'
|
||||||
```
|
```
|
||||||
|
|
||||||
### 빌드 가능한 서비스 (6개)
|
**빌드 대상 서비스 (6개):**
|
||||||
Main Application 클래스가 존재하는 서비스:
|
- user-service (Java/Spring Boot)
|
||||||
1. **user-service** - `UserServiceApplication.java`
|
- event-service (Java/Spring Boot)
|
||||||
2. **event-service** - `EventServiceApplication.java`
|
- ai-service (Java/Spring Boot)
|
||||||
3. **ai-service** - `AiServiceApplication.java`
|
- distribution-service (Java/Spring Boot)
|
||||||
4. **content-service** - `ContentApplication.java`
|
- participation-service (Java/Spring Boot)
|
||||||
5. **participation-service** - `ParticipationServiceApplication.java`
|
- analytics-service (Java/Spring Boot)
|
||||||
6. **analytics-service** - `AnalyticsServiceApplication.java`
|
|
||||||
|
|
||||||
### 제외된 서비스
|
**제외 대상:**
|
||||||
- **distribution-service**: 소스 코드 미구현 상태 (src/main/java 디렉토리 없음)
|
- common: 공통 라이브러리 모듈 (독립 실행 서비스 아님)
|
||||||
|
- content-service: Python 기반 서비스 (별도 빌드 필요)
|
||||||
|
|
||||||
## 2. bootJar 설정
|
## bootJar 설정 확인
|
||||||
|
|
||||||
각 서비스의 `build.gradle`에 bootJar 설정 추가/수정:
|
모든 Java 서비스의 build.gradle에 bootJar 설정이 올바르게 구성되어 있음을 확인:
|
||||||
|
|
||||||
### 설정 추가된 서비스 (5개)
|
| 서비스명 | JAR 파일명 | 경로 |
|
||||||
```gradle
|
|---------|-----------|------|
|
||||||
bootJar {
|
| user-service | user-service.jar | user-service/build/libs/user-service.jar |
|
||||||
archiveFileName = '{service-name}.jar'
|
| event-service | event-service.jar | event-service/build/libs/event-service.jar |
|
||||||
}
|
| ai-service | ai-service.jar | ai-service/build/libs/ai-service.jar |
|
||||||
```
|
| distribution-service | distribution-service.jar | distribution-service/build/libs/distribution-service.jar |
|
||||||
|
| participation-service | participation-service.jar | participation-service/build/libs/participation-service.jar |
|
||||||
|
| analytics-service | analytics-service.jar | analytics-service/build/libs/analytics-service.jar |
|
||||||
|
|
||||||
- user-service/build.gradle
|
## Dockerfile 생성
|
||||||
- ai-service/build.gradle
|
|
||||||
- distribution-service/build.gradle (향후 구현 대비)
|
|
||||||
- participation-service/build.gradle
|
|
||||||
- analytics-service/build.gradle
|
|
||||||
|
|
||||||
### 기존 설정 확인된 서비스 (2개)
|
**파일 위치:** `deployment/container/Dockerfile-backend`
|
||||||
- event-service/build.gradle ✅
|
|
||||||
- content-service/build.gradle ✅
|
|
||||||
|
|
||||||
## 3. Dockerfile 생성
|
**Dockerfile 구성:**
|
||||||
|
|
||||||
### 파일 경로
|
|
||||||
`deployment/container/Dockerfile-backend`
|
|
||||||
|
|
||||||
### Dockerfile 내용
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
# Build stage
|
# Build stage
|
||||||
FROM openjdk:23-oraclelinux8 AS builder
|
FROM openjdk:23-oraclelinux8 AS builder
|
||||||
@ -91,58 +80,34 @@ ENTRYPOINT [ "sh", "-c" ]
|
|||||||
CMD ["java ${JAVA_OPTS} -jar app.jar"]
|
CMD ["java ${JAVA_OPTS} -jar app.jar"]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Dockerfile 특징
|
**주요 특징:**
|
||||||
- **Multi-stage build**: 빌드와 실행 스테이지 분리
|
- Multi-stage 빌드: 빌드 이미지와 런타임 이미지 분리
|
||||||
- **Non-root user**: 보안을 위한 k8s 사용자 실행
|
- Base Image: openjdk:23-slim (경량화)
|
||||||
- **플랫폼**: linux/amd64 (K8s 클러스터 호환)
|
- 보안: 비root 사용자(k8s)로 실행
|
||||||
- **Java 버전**: OpenJDK 23
|
- 플랫폼: linux/amd64
|
||||||
|
|
||||||
## 4. JAR 파일 빌드
|
## Gradle 빌드 실행
|
||||||
|
|
||||||
### 빌드 명령어
|
**실행 명령:**
|
||||||
```bash
|
```bash
|
||||||
./gradlew user-service:bootJar ai-service:bootJar event-service:bootJar \
|
./gradlew clean build -x test
|
||||||
content-service:bootJar participation-service:bootJar analytics-service:bootJar
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 빌드 결과
|
**빌드 결과:**
|
||||||
```
|
- 상태: ✅ BUILD SUCCESSFUL
|
||||||
BUILD SUCCESSFUL in 27s
|
- 소요 시간: 33초
|
||||||
33 actionable tasks: 15 executed, 18 up-to-date
|
- 실행된 태스크: 56개
|
||||||
```
|
|
||||||
|
|
||||||
### 생성된 JAR 파일
|
## 컨테이너 이미지 빌드
|
||||||
```bash
|
|
||||||
$ ls -lh */build/libs/*.jar
|
|
||||||
|
|
||||||
-rw-r--r-- 1 KTDS 197121 94M 10월 29 09:49 ai-service/build/libs/ai-service.jar
|
### 병렬 빌드 전략
|
||||||
-rw-r--r-- 1 KTDS 197121 95M 10월 29 09:48 analytics-service/build/libs/analytics-service.jar
|
서브 에이전트를 활용하여 6개 서비스를 동시에 빌드하여 시간 단축
|
||||||
-rw-r--r-- 1 KTDS 197121 78M 10월 29 09:49 content-service/build/libs/content-service.jar
|
|
||||||
-rw-r--r-- 1 KTDS 197121 94M 10월 29 09:49 event-service/build/libs/event-service.jar
|
|
||||||
-rw-r--r-- 1 KTDS 197121 85M 10월 29 09:49 participation-service/build/libs/participation-service.jar
|
|
||||||
-rw-r--r-- 1 KTDS 197121 96M 10월 29 09:49 user-service/build/libs/user-service.jar
|
|
||||||
```
|
|
||||||
|
|
||||||
## 5. Docker 이미지 빌드
|
### 1. user-service
|
||||||
|
|
||||||
### 사전 준비사항
|
**빌드 명령:**
|
||||||
⚠️ **Docker Desktop이 실행 중이어야 합니다**
|
|
||||||
|
|
||||||
Docker Desktop 시작 확인:
|
|
||||||
```bash
|
|
||||||
# Docker 상태 확인
|
|
||||||
docker version
|
|
||||||
docker ps
|
|
||||||
|
|
||||||
# Docker Desktop이 정상 실행되면 위 명령들이 정상 동작합니다
|
|
||||||
```
|
|
||||||
|
|
||||||
### 빌드 명령어
|
|
||||||
|
|
||||||
#### 5.1 user-service
|
|
||||||
```bash
|
```bash
|
||||||
DOCKER_FILE=deployment/container/Dockerfile-backend
|
DOCKER_FILE=deployment/container/Dockerfile-backend
|
||||||
|
|
||||||
docker build \
|
docker build \
|
||||||
--platform linux/amd64 \
|
--platform linux/amd64 \
|
||||||
--build-arg BUILD_LIB_DIR="user-service/build/libs" \
|
--build-arg BUILD_LIB_DIR="user-service/build/libs" \
|
||||||
@ -151,22 +116,17 @@ docker build \
|
|||||||
-t user-service:latest .
|
-t user-service:latest .
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 5.2 ai-service
|
**결과:**
|
||||||
|
- 상태: ✅ SUCCESS
|
||||||
|
- 이미지 ID: fb07547604be
|
||||||
|
- 이미지 크기: 1.09GB
|
||||||
|
- Image SHA: sha256:fb07547604bee7e8ff69e56e8423299b7dec277e80d865ee5013ddd876a0b4c6
|
||||||
|
|
||||||
|
### 2. event-service
|
||||||
|
|
||||||
|
**빌드 명령:**
|
||||||
```bash
|
```bash
|
||||||
DOCKER_FILE=deployment/container/Dockerfile-backend
|
DOCKER_FILE=deployment/container/Dockerfile-backend
|
||||||
|
|
||||||
docker build \
|
|
||||||
--platform linux/amd64 \
|
|
||||||
--build-arg BUILD_LIB_DIR="ai-service/build/libs" \
|
|
||||||
--build-arg ARTIFACTORY_FILE="ai-service.jar" \
|
|
||||||
-f ${DOCKER_FILE} \
|
|
||||||
-t ai-service:latest .
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 5.3 event-service
|
|
||||||
```bash
|
|
||||||
DOCKER_FILE=deployment/container/Dockerfile-backend
|
|
||||||
|
|
||||||
docker build \
|
docker build \
|
||||||
--platform linux/amd64 \
|
--platform linux/amd64 \
|
||||||
--build-arg BUILD_LIB_DIR="event-service/build/libs" \
|
--build-arg BUILD_LIB_DIR="event-service/build/libs" \
|
||||||
@ -175,22 +135,56 @@ docker build \
|
|||||||
-t event-service:latest .
|
-t event-service:latest .
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 5.4 content-service
|
**결과:**
|
||||||
|
- 상태: ✅ SUCCESS
|
||||||
|
- 이미지 ID: 191a9882a628
|
||||||
|
- 이미지 크기: 1.08GB
|
||||||
|
- 빌드 시간: ~20초
|
||||||
|
|
||||||
|
### 3. ai-service
|
||||||
|
|
||||||
|
**빌드 명령:**
|
||||||
```bash
|
```bash
|
||||||
DOCKER_FILE=deployment/container/Dockerfile-backend
|
DOCKER_FILE=deployment/container/Dockerfile-backend
|
||||||
|
|
||||||
docker build \
|
docker build \
|
||||||
--platform linux/amd64 \
|
--platform linux/amd64 \
|
||||||
--build-arg BUILD_LIB_DIR="content-service/build/libs" \
|
--build-arg BUILD_LIB_DIR="ai-service/build/libs" \
|
||||||
--build-arg ARTIFACTORY_FILE="content-service.jar" \
|
--build-arg ARTIFACTORY_FILE="ai-service.jar" \
|
||||||
-f ${DOCKER_FILE} \
|
-f ${DOCKER_FILE} \
|
||||||
-t content-service:latest .
|
-t ai-service:latest .
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 5.5 participation-service
|
**결과:**
|
||||||
|
- 상태: ✅ SUCCESS
|
||||||
|
- 이미지 ID: 498feb888dc5
|
||||||
|
- 이미지 크기: 1.08GB
|
||||||
|
- Image SHA: sha256:498feb888dc58a98715841c4e50f191bc8434eccd12baefa79e82b0e44a5bc40
|
||||||
|
|
||||||
|
### 4. distribution-service
|
||||||
|
|
||||||
|
**빌드 명령:**
|
||||||
```bash
|
```bash
|
||||||
DOCKER_FILE=deployment/container/Dockerfile-backend
|
DOCKER_FILE=deployment/container/Dockerfile-backend
|
||||||
|
docker build \
|
||||||
|
--platform linux/amd64 \
|
||||||
|
--build-arg BUILD_LIB_DIR="distribution-service/build/libs" \
|
||||||
|
--build-arg ARTIFACTORY_FILE="distribution-service.jar" \
|
||||||
|
-f ${DOCKER_FILE} \
|
||||||
|
-t distribution-service:latest .
|
||||||
|
```
|
||||||
|
|
||||||
|
**결과:**
|
||||||
|
- 상태: ✅ SUCCESS
|
||||||
|
- 이미지 ID: e0ad31c51b63
|
||||||
|
- 이미지 크기: 1.08GB
|
||||||
|
- Image SHA: sha256:e0ad31c51b63b44d67f017cca8a729ae9cbb5e9e9503feddb308c09f19b70fba
|
||||||
|
- 빌드 시간: ~60초
|
||||||
|
|
||||||
|
### 5. participation-service
|
||||||
|
|
||||||
|
**빌드 명령:**
|
||||||
|
```bash
|
||||||
|
DOCKER_FILE=deployment/container/Dockerfile-backend
|
||||||
docker build \
|
docker build \
|
||||||
--platform linux/amd64 \
|
--platform linux/amd64 \
|
||||||
--build-arg BUILD_LIB_DIR="participation-service/build/libs" \
|
--build-arg BUILD_LIB_DIR="participation-service/build/libs" \
|
||||||
@ -199,10 +193,18 @@ docker build \
|
|||||||
-t participation-service:latest .
|
-t participation-service:latest .
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 5.6 analytics-service
|
**결과:**
|
||||||
|
- 상태: ✅ SUCCESS
|
||||||
|
- 이미지 ID: 9bd60358659b
|
||||||
|
- 이미지 크기: 1.04GB
|
||||||
|
- Image SHA: sha256:9bd60358659b528190edcab699152b5126dc906070e05d355310303ac292f02b
|
||||||
|
- 빌드 시간: ~37초
|
||||||
|
|
||||||
|
### 6. analytics-service
|
||||||
|
|
||||||
|
**빌드 명령:**
|
||||||
```bash
|
```bash
|
||||||
DOCKER_FILE=deployment/container/Dockerfile-backend
|
DOCKER_FILE=deployment/container/Dockerfile-backend
|
||||||
|
|
||||||
docker build \
|
docker build \
|
||||||
--platform linux/amd64 \
|
--platform linux/amd64 \
|
||||||
--build-arg BUILD_LIB_DIR="analytics-service/build/libs" \
|
--build-arg BUILD_LIB_DIR="analytics-service/build/libs" \
|
||||||
@ -211,186 +213,55 @@ docker build \
|
|||||||
-t analytics-service:latest .
|
-t analytics-service:latest .
|
||||||
```
|
```
|
||||||
|
|
||||||
### 빌드 스크립트 (일괄 실행)
|
**결과:**
|
||||||
|
- 상태: ✅ SUCCESS
|
||||||
|
- 이미지 ID: 33b53299ec16
|
||||||
|
- 이미지 크기: 1.08GB
|
||||||
|
- Image SHA: sha256:33b53299ec16e0021a9adca4fb32535708021073df03c30b8a0ea335348547de
|
||||||
|
|
||||||
|
## 생성된 이미지 확인
|
||||||
|
|
||||||
|
**확인 명령:**
|
||||||
```bash
|
```bash
|
||||||
#!/bin/bash
|
docker images | grep -E "(user-service|event-service|ai-service|distribution-service|participation-service|analytics-service)" | grep latest
|
||||||
# build-all-images.sh
|
|
||||||
|
|
||||||
DOCKER_FILE=deployment/container/Dockerfile-backend
|
|
||||||
|
|
||||||
services=(
|
|
||||||
"user-service"
|
|
||||||
"ai-service"
|
|
||||||
"event-service"
|
|
||||||
"content-service"
|
|
||||||
"participation-service"
|
|
||||||
"analytics-service"
|
|
||||||
)
|
|
||||||
|
|
||||||
for service in "${services[@]}"; do
|
|
||||||
echo "Building ${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 .
|
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
echo "✅ ${service} build successful"
|
|
||||||
else
|
|
||||||
echo "❌ ${service} build failed"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "🎉 All images built successfully!"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 6. 이미지 확인
|
**확인 결과:**
|
||||||
|
```
|
||||||
### 생성된 이미지 확인 명령어
|
event-service latest 191a9882a628 39 seconds ago 1.08GB
|
||||||
```bash
|
ai-service latest 498feb888dc5 46 seconds ago 1.08GB
|
||||||
# 모든 서비스 이미지 확인
|
analytics-service latest 33b53299ec16 46 seconds ago 1.08GB
|
||||||
docker images | grep -E "(user-service|ai-service|event-service|content-service|participation-service|analytics-service)"
|
user-service latest fb07547604be 47 seconds ago 1.09GB
|
||||||
|
participation-service latest 9bd60358659b 48 seconds ago 1.04GB
|
||||||
# 개별 서비스 확인
|
distribution-service latest e0ad31c51b63 48 seconds ago 1.08GB
|
||||||
docker images user-service:latest
|
|
||||||
docker images ai-service:latest
|
|
||||||
docker images event-service:latest
|
|
||||||
docker images content-service:latest
|
|
||||||
docker images participation-service:latest
|
|
||||||
docker images analytics-service:latest
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 빌드 결과 ✅
|
## 빌드 결과 요약
|
||||||
```
|
|
||||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
|
||||||
user-service latest 91c511ef86bd About a minute ago 1.09GB
|
|
||||||
ai-service latest 9477022fa493 About a minute ago 1.08GB
|
|
||||||
event-service latest add81de69536 About a minute ago 1.08GB
|
|
||||||
content-service latest aa9cc16ad041 About a minute ago 1.01GB
|
|
||||||
participation-service latest 9b044a3854dd About a minute ago 1.04GB
|
|
||||||
analytics-service latest ac569de42545 About a minute ago 1.08GB
|
|
||||||
```
|
|
||||||
|
|
||||||
**빌드 일시**: 2025-10-29 09:50 KST
|
| 서비스명 | 이미지 태그 | 이미지 ID | 크기 | 상태 |
|
||||||
**빌드 소요 시간**: 약 13초 (병렬 빌드)
|
|---------|-----------|----------|------|------|
|
||||||
**총 이미지 크기**: 6.48GB
|
| user-service | user-service:latest | fb07547604be | 1.09GB | ✅ |
|
||||||
|
| event-service | event-service:latest | 191a9882a628 | 1.08GB | ✅ |
|
||||||
|
| ai-service | ai-service:latest | 498feb888dc5 | 1.08GB | ✅ |
|
||||||
|
| distribution-service | distribution-service:latest | e0ad31c51b63 | 1.08GB | ✅ |
|
||||||
|
| participation-service | participation-service:latest | 9bd60358659b | 1.04GB | ✅ |
|
||||||
|
| analytics-service | analytics-service:latest | 33b53299ec16 | 1.08GB | ✅ |
|
||||||
|
|
||||||
## 7. 이미지 테스트
|
**총 6개 서비스 이미지 빌드 성공**
|
||||||
|
|
||||||
### 로컬 실행 테스트 (예시: user-service)
|
## 다음 단계
|
||||||
```bash
|
|
||||||
# 컨테이너 실행
|
|
||||||
docker run -d \
|
|
||||||
--name user-service-test \
|
|
||||||
-p 8080:8080 \
|
|
||||||
-e SPRING_PROFILES_ACTIVE=dev \
|
|
||||||
user-service:latest
|
|
||||||
|
|
||||||
# 로그 확인
|
생성된 이미지를 사용하여 다음 작업을 진행할 수 있습니다:
|
||||||
docker logs -f user-service-test
|
|
||||||
|
|
||||||
# 헬스체크
|
1. **로컬 테스트:** Docker Compose 또는 개별 컨테이너 실행
|
||||||
curl http://localhost:8080/actuator/health
|
2. **ACR 푸시:** Azure Container Registry에 이미지 업로드
|
||||||
|
3. **AKS 배포:** Kubernetes 클러스터에 배포
|
||||||
|
4. **CI/CD 통합:** GitHub Actions 또는 Jenkins 파이프라인 연동
|
||||||
|
|
||||||
# 정리
|
## 참고사항
|
||||||
docker stop user-service-test
|
|
||||||
docker rm user-service-test
|
|
||||||
```
|
|
||||||
|
|
||||||
## 8. 다음 단계
|
- 모든 이미지는 linux/amd64 플랫폼용으로 빌드됨
|
||||||
|
- 보안을 위해 비root 사용자(k8s)로 실행 구성
|
||||||
### 8.1 컨테이너 레지스트리 푸시
|
- Multi-stage 빌드로 이미지 크기 최적화
|
||||||
```bash
|
- Java 23 (OpenJDK) 기반 런타임 사용
|
||||||
# Docker Hub 예시
|
- content-service(Python)는 별도의 Dockerfile로 빌드 필요
|
||||||
docker tag user-service:latest <your-registry>/user-service:latest
|
|
||||||
docker push <your-registry>/user-service:latest
|
|
||||||
|
|
||||||
# Azure Container Registry 예시
|
|
||||||
docker tag user-service:latest <acr-name>.azurecr.io/user-service:latest
|
|
||||||
docker push <acr-name>.azurecr.io/user-service:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
### 8.2 Kubernetes 배포
|
|
||||||
- Kubernetes Deployment 매니페스트 작성
|
|
||||||
- Service 리소스 정의
|
|
||||||
- ConfigMap/Secret 설정
|
|
||||||
- Ingress 구성
|
|
||||||
|
|
||||||
### 8.3 CI/CD 파이프라인 구성
|
|
||||||
- GitHub Actions 또는 Jenkins 파이프라인 작성
|
|
||||||
- 자동 빌드 및 배포 설정
|
|
||||||
- 이미지 태깅 전략 수립 (semantic versioning)
|
|
||||||
|
|
||||||
## 9. 트러블슈팅
|
|
||||||
|
|
||||||
### Issue 1: Docker Desktop 미실행
|
|
||||||
**증상**:
|
|
||||||
```
|
|
||||||
ERROR: error during connect: open //./pipe/dockerDesktopLinuxEngine:
|
|
||||||
The system cannot find the file specified.
|
|
||||||
```
|
|
||||||
|
|
||||||
**해결**:
|
|
||||||
1. Docker Desktop 애플리케이션 시작
|
|
||||||
2. 시스템 트레이의 Docker 아이콘이 안정화될 때까지 대기
|
|
||||||
3. `docker ps` 명령으로 정상 동작 확인
|
|
||||||
|
|
||||||
### Issue 2: JAR 파일 없음
|
|
||||||
**증상**:
|
|
||||||
```
|
|
||||||
COPY failed: file not found in build context
|
|
||||||
```
|
|
||||||
|
|
||||||
**해결**:
|
|
||||||
```bash
|
|
||||||
# JAR 파일 재빌드
|
|
||||||
./gradlew {service-name}:clean {service-name}:bootJar
|
|
||||||
|
|
||||||
# 생성 확인
|
|
||||||
ls -l {service-name}/build/libs/{service-name}.jar
|
|
||||||
```
|
|
||||||
|
|
||||||
### Issue 3: 플랫폼 불일치
|
|
||||||
**증상**: K8s 클러스터에서 실행 안됨
|
|
||||||
|
|
||||||
**해결**: `--platform linux/amd64` 옵션 사용 (이미 적용됨)
|
|
||||||
|
|
||||||
## 10. 요약
|
|
||||||
|
|
||||||
### ✅ 완료된 작업
|
|
||||||
1. ✅ 6개 서비스의 bootJar 설정 완료
|
|
||||||
2. ✅ Dockerfile-backend 생성 완료
|
|
||||||
3. ✅ 6개 서비스 JAR 파일 빌드 완료 (총 542MB)
|
|
||||||
4. ✅ 6개 서비스 Docker 이미지 빌드 완료 (총 6.48GB)
|
|
||||||
|
|
||||||
### 📊 최종 서비스 현황
|
|
||||||
| 서비스 | JAR 빌드 | Docker 이미지 | 이미지 크기 | Image ID | 상태 |
|
|
||||||
|--------|---------|--------------|-----------|----------|------|
|
|
||||||
| user-service | ✅ 96MB | ✅ | 1.09GB | 91c511ef86bd | ✅ Ready |
|
|
||||||
| ai-service | ✅ 94MB | ✅ | 1.08GB | 9477022fa493 | ✅ Ready |
|
|
||||||
| event-service | ✅ 94MB | ✅ | 1.08GB | add81de69536 | ✅ Ready |
|
|
||||||
| content-service | ✅ 78MB | ✅ | 1.01GB | aa9cc16ad041 | ✅ Ready |
|
|
||||||
| participation-service | ✅ 85MB | ✅ | 1.04GB | 9b044a3854dd | ✅ Ready |
|
|
||||||
| analytics-service | ✅ 95MB | ✅ | 1.08GB | ac569de42545 | ✅ Ready |
|
|
||||||
| distribution-service | ❌ | ❌ | - | - | 소스 미구현 |
|
|
||||||
|
|
||||||
### 🎯 빌드 성능 메트릭
|
|
||||||
- **JAR 빌드 시간**: 27초
|
|
||||||
- **Docker 이미지 빌드**: 병렬 실행으로 약 13초
|
|
||||||
- **총 소요 시간**: 약 40초
|
|
||||||
- **빌드 성공률**: 100% (6/6 서비스)
|
|
||||||
|
|
||||||
### 🚀 다음 단계 권장사항
|
|
||||||
1. **컨테이너 레지스트리 푸시** (예: Azure ACR, Docker Hub)
|
|
||||||
2. **Kubernetes 배포 매니페스트 작성**
|
|
||||||
3. **CI/CD 파이프라인 구성** (GitHub Actions 또는 Jenkins)
|
|
||||||
4. **모니터링 및 로깅 설정**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**작성일**: 2025-10-29 09:50 KST
|
|
||||||
**작성자**: DevOps Engineer (송근정 "데브옵스 마스터")
|
|
||||||
**빌드 완료**: ✅ 모든 서비스 이미지 빌드 성공
|
|
||||||
|
|||||||
@ -99,7 +99,7 @@ spec:
|
|||||||
number: 80
|
number: 80
|
||||||
|
|
||||||
# Distribution Service
|
# Distribution Service
|
||||||
- path: /distribution
|
- path: /api/v1/distribution
|
||||||
pathType: Prefix
|
pathType: Prefix
|
||||||
backend:
|
backend:
|
||||||
service:
|
service:
|
||||||
|
|||||||
@ -42,21 +42,21 @@ spec:
|
|||||||
memory: "1024Mi"
|
memory: "1024Mi"
|
||||||
startupProbe:
|
startupProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: /distribution/actuator/health
|
path: /api/v1/distribution/actuator/health
|
||||||
port: 8085
|
port: 8085
|
||||||
initialDelaySeconds: 30
|
initialDelaySeconds: 30
|
||||||
periodSeconds: 10
|
periodSeconds: 10
|
||||||
failureThreshold: 30
|
failureThreshold: 30
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: /distribution/actuator/health/readiness
|
path: /api/v1/distribution/actuator/health/readiness
|
||||||
port: 8085
|
port: 8085
|
||||||
initialDelaySeconds: 10
|
initialDelaySeconds: 10
|
||||||
periodSeconds: 5
|
periodSeconds: 5
|
||||||
failureThreshold: 3
|
failureThreshold: 3
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: /distribution/actuator/health/liveness
|
path: /api/v1/distribution/actuator/health/liveness
|
||||||
port: 8085
|
port: 8085
|
||||||
initialDelaySeconds: 30
|
initialDelaySeconds: 30
|
||||||
periodSeconds: 10
|
periodSeconds: 10
|
||||||
|
|||||||
@ -26,7 +26,7 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/distribution")
|
@RequestMapping
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Tag(name = "Distribution", description = "다중 채널 배포 관리 API")
|
@Tag(name = "Distribution", description = "다중 채널 배포 관리 API")
|
||||||
public class DistributionController {
|
public class DistributionController {
|
||||||
|
|||||||
@ -68,7 +68,7 @@ kafka:
|
|||||||
server:
|
server:
|
||||||
port: ${SERVER_PORT:8085}
|
port: ${SERVER_PORT:8085}
|
||||||
servlet:
|
servlet:
|
||||||
context-path: /distribution
|
context-path: /api/v1/distribution
|
||||||
|
|
||||||
# Resilience4j Configuration
|
# Resilience4j Configuration
|
||||||
resilience4j:
|
resilience4j:
|
||||||
@ -136,6 +136,14 @@ springdoc:
|
|||||||
display-request-duration: true
|
display-request-duration: true
|
||||||
show-actuator: true
|
show-actuator: true
|
||||||
|
|
||||||
|
# CORS Configuration
|
||||||
|
cors:
|
||||||
|
allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost:8081,http://localhost:8082,http://localhost:8083,http://localhost:8084,http://kt-event-marketing.20.214.196.128.nip.io}
|
||||||
|
allowed-methods: ${CORS_ALLOWED_METHODS:GET,POST,PUT,DELETE,OPTIONS,PATCH}
|
||||||
|
allowed-headers: ${CORS_ALLOWED_HEADERS:*}
|
||||||
|
allow-credentials: ${CORS_ALLOW_CREDENTIALS:true}
|
||||||
|
max-age: ${CORS_MAX_AGE:3600}
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
logging:
|
logging:
|
||||||
file:
|
file:
|
||||||
|
|||||||
@ -31,6 +31,9 @@
|
|||||||
<!-- JWT Configuration -->
|
<!-- JWT Configuration -->
|
||||||
<entry key="JWT_SECRET" value="kt-event-marketing-secret-key-for-development-only-please-change-in-production" />
|
<entry key="JWT_SECRET" value="kt-event-marketing-secret-key-for-development-only-please-change-in-production" />
|
||||||
|
|
||||||
|
<!-- CORS Configuration -->
|
||||||
|
<entry key="CORS_ALLOWED_ORIGINS" value="http://localhost:*,http://*.nip.io:*" />
|
||||||
|
|
||||||
<!-- Logging Configuration -->
|
<!-- Logging Configuration -->
|
||||||
<entry key="LOG_LEVEL" value="DEBUG" />
|
<entry key="LOG_LEVEL" value="DEBUG" />
|
||||||
<entry key="SQL_LOG_LEVEL" value="DEBUG" />
|
<entry key="SQL_LOG_LEVEL" value="DEBUG" />
|
||||||
|
|||||||
@ -167,3 +167,11 @@ app:
|
|||||||
jwt:
|
jwt:
|
||||||
secret: ${JWT_SECRET:default-jwt-secret-key-for-development-minimum-32-bytes-required}
|
secret: ${JWT_SECRET:default-jwt-secret-key-for-development-minimum-32-bytes-required}
|
||||||
expiration: 86400000 # 24시간 (밀리초 단위)
|
expiration: 86400000 # 24시간 (밀리초 단위)
|
||||||
|
|
||||||
|
# CORS Configuration
|
||||||
|
cors:
|
||||||
|
allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost:8081,http://localhost:8082,http://localhost:8083,http://localhost:8084,http://kt-event-marketing.20.214.196.128.nip.io}
|
||||||
|
allowed-methods: ${CORS_ALLOWED_METHODS:GET,POST,PUT,DELETE,OPTIONS,PATCH}
|
||||||
|
allowed-headers: ${CORS_ALLOWED_HEADERS:*}
|
||||||
|
allow-credentials: ${CORS_ALLOW_CREDENTIALS:true}
|
||||||
|
max-age: ${CORS_MAX_AGE:3600}
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
<entry key="JWT_EXPIRATION" value="86400000" />
|
<entry key="JWT_EXPIRATION" value="86400000" />
|
||||||
<entry key="JWT_SECRET" value="kt-event-marketing-secret-key-for-development-only-change-in-production" />
|
<entry key="JWT_SECRET" value="kt-event-marketing-secret-key-for-development-only-change-in-production" />
|
||||||
<entry key="KAFKA_BOOTSTRAP_SERVERS" value="20.249.182.13:9095,4.217.131.59:9095" />
|
<entry key="KAFKA_BOOTSTRAP_SERVERS" value="20.249.182.13:9095,4.217.131.59:9095" />
|
||||||
|
<entry key="CORS_ALLOWED_ORIGINS" value="http://localhost:*,http://*.nip.io:*" />
|
||||||
<entry key="LOG_FILE" value="logs/participation-service.log" />
|
<entry key="LOG_FILE" value="logs/participation-service.log" />
|
||||||
<entry key="LOG_LEVEL" value="INFO" />
|
<entry key="LOG_LEVEL" value="INFO" />
|
||||||
<entry key="REDIS_HOST" value="20.214.210.71" />
|
<entry key="REDIS_HOST" value="20.214.210.71" />
|
||||||
|
|||||||
@ -1,11 +1,17 @@
|
|||||||
package com.kt.event.participation.infrastructure.config;
|
package com.kt.event.participation.infrastructure.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
|
import org.springframework.web.cors.CorsConfigurationSource;
|
||||||
|
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Security Configuration for Participation Service
|
* Security Configuration for Participation Service
|
||||||
@ -18,10 +24,14 @@ import org.springframework.security.web.SecurityFilterChain;
|
|||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
public class SecurityConfig {
|
public class SecurityConfig {
|
||||||
|
|
||||||
|
@Value("${cors.allowed-origins:http://localhost:*}")
|
||||||
|
private String allowedOrigins;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
http
|
http
|
||||||
.csrf(csrf -> csrf.disable())
|
.csrf(csrf -> csrf.disable())
|
||||||
|
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
|
||||||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||||
.authorizeHttpRequests(auth -> auth
|
.authorizeHttpRequests(auth -> auth
|
||||||
// Actuator endpoints
|
// Actuator endpoints
|
||||||
@ -31,4 +41,26 @@ public class SecurityConfig {
|
|||||||
|
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public CorsConfigurationSource corsConfigurationSource() {
|
||||||
|
CorsConfiguration configuration = new CorsConfiguration();
|
||||||
|
|
||||||
|
String[] origins = allowedOrigins.split(",");
|
||||||
|
configuration.setAllowedOriginPatterns(Arrays.asList(origins));
|
||||||
|
|
||||||
|
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
|
||||||
|
|
||||||
|
configuration.setAllowedHeaders(Arrays.asList(
|
||||||
|
"Authorization", "Content-Type", "X-Requested-With", "Accept",
|
||||||
|
"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers"
|
||||||
|
));
|
||||||
|
|
||||||
|
configuration.setAllowCredentials(true);
|
||||||
|
configuration.setMaxAge(3600L);
|
||||||
|
|
||||||
|
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||||
|
source.registerCorsConfiguration("/**", configuration);
|
||||||
|
return source;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,6 +54,14 @@ jwt:
|
|||||||
secret: ${JWT_SECRET:dev-jwt-secret-key-for-development-only}
|
secret: ${JWT_SECRET:dev-jwt-secret-key-for-development-only}
|
||||||
expiration: ${JWT_EXPIRATION:86400000}
|
expiration: ${JWT_EXPIRATION:86400000}
|
||||||
|
|
||||||
|
# CORS 설정
|
||||||
|
cors:
|
||||||
|
allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost:8081,http://localhost:8082,http://localhost:8083,http://localhost:8084,http://kt-event-marketing.20.214.196.128.nip.io}
|
||||||
|
allowed-methods: ${CORS_ALLOWED_METHODS:GET,POST,PUT,DELETE,OPTIONS,PATCH}
|
||||||
|
allowed-headers: ${CORS_ALLOWED_HEADERS:*}
|
||||||
|
allow-credentials: ${CORS_ALLOW_CREDENTIALS:true}
|
||||||
|
max-age: ${CORS_MAX_AGE:3600}
|
||||||
|
|
||||||
# 서버 설정
|
# 서버 설정
|
||||||
server:
|
server:
|
||||||
port: ${SERVER_PORT:8084}
|
port: ${SERVER_PORT:8084}
|
||||||
|
|||||||
@ -42,7 +42,7 @@
|
|||||||
<entry key="JWT_ACCESS_TOKEN_VALIDITY" value="604800000" />
|
<entry key="JWT_ACCESS_TOKEN_VALIDITY" value="604800000" />
|
||||||
|
|
||||||
<!-- CORS Configuration -->
|
<!-- CORS Configuration -->
|
||||||
<entry key="CORS_ALLOWED_ORIGINS" value="http://localhost:*" />
|
<entry key="CORS_ALLOWED_ORIGINS" value="http://localhost:*,http://*.nip.io:*" />
|
||||||
|
|
||||||
<!-- Logging Configuration -->
|
<!-- Logging Configuration -->
|
||||||
<entry key="LOG_LEVEL_APP" value="DEBUG" />
|
<entry key="LOG_LEVEL_APP" value="DEBUG" />
|
||||||
|
|||||||
@ -76,7 +76,11 @@ jwt:
|
|||||||
|
|
||||||
# CORS Configuration
|
# CORS Configuration
|
||||||
cors:
|
cors:
|
||||||
allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost:*}
|
allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost:8081,http://localhost:8082,http://localhost:8083,http://localhost:8084,http://kt-event-marketing.20.214.196.128.nip.io}
|
||||||
|
allowed-methods: ${CORS_ALLOWED_METHODS:GET,POST,PUT,DELETE,OPTIONS,PATCH}
|
||||||
|
allowed-headers: ${CORS_ALLOWED_HEADERS:*}
|
||||||
|
allow-credentials: ${CORS_ALLOW_CREDENTIALS:true}
|
||||||
|
max-age: ${CORS_MAX_AGE:3600}
|
||||||
|
|
||||||
# Actuator
|
# Actuator
|
||||||
management:
|
management:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user