This commit is contained in:
dean
2026-04-01 08:55:17 +09:00
parent 50ad05b53b
commit 6cc9b54ba9
15 changed files with 280 additions and 325 deletions

View File

@@ -57,7 +57,7 @@ public class StartupLogger {
""" """
╔════════════════════════════════════════════════════════════════════════════════╗ ╔════════════════════════════════════════════════════════════════════════════════╗
║ 🚀 APPLICATION STARTUP INFORMATION 2 ║ 🚀 APPLICATION STARTUP INFORMATION 3
╠════════════════════════════════════════════════════════════════════════════════╣ ╠════════════════════════════════════════════════════════════════════════════════╣
║ PROFILE CONFIGURATION ║ ║ PROFILE CONFIGURATION ║
╠────────────────────────────────────────────────────────────────────────────────╣ ╠────────────────────────────────────────────────────────────────────────────────╣

View File

@@ -48,7 +48,7 @@ public class ModelTrainDetailApiController {
private final ModelTrainDetailService modelTrainDetailService; private final ModelTrainDetailService modelTrainDetailService;
private final RangeDownloadResponder rangeDownloadResponder; private final RangeDownloadResponder rangeDownloadResponder;
@Value("${train.docker.responseDir}") @Value("${train.docker.response_dir}")
private String responseDir; private String responseDir;
@Operation(summary = "모델학습관리> 모델관리 > 상세정보탭 > 학습 진행정보", description = "학습 진행정보, 모델학습 정보 API") @Operation(summary = "모델학습관리> 모델관리 > 상세정보탭 > 학습 진행정보", description = "학습 진행정보, 모델학습 정보 API")

View File

@@ -53,7 +53,7 @@ public class ModelTrainDetailService {
private final ModelTrainDetailCoreService modelTrainDetailCoreService; private final ModelTrainDetailCoreService modelTrainDetailCoreService;
private final ModelTrainMngCoreService mngCoreService; private final ModelTrainMngCoreService mngCoreService;
@Value("${train.docker.responseDir}") @Value("${train.docker.response_dir}")
private String responseDir; private String responseDir;
/** /**

View File

@@ -46,11 +46,14 @@ public class ModelTrainMngService {
private final TrainJobService trainJobService; private final TrainJobService trainJobService;
private final ModelTrainDetailService modelTrainDetailService; private final ModelTrainDetailService modelTrainDetailService;
@Value("${train.docker.basePath}") @Value("${train.docker.base_path}")
private String basePath; private String basePath;
@Value("${train.docker.responseDir}") @Value("${train.docker.response_dir}")
private String responseDir; private String responseDir;
@Value("${train.docker.symbolic_link_dir}")
private String symbolicDir;
/** /**
* 모델학습 조회 * 모델학습 조회
@@ -80,7 +83,7 @@ public class ModelTrainMngService {
} }
// ===== 2. 경로 생성 ===== // ===== 2. 경로 생성 =====
Path tmpBase = Path.of(basePath, "tmp").toAbsolutePath().normalize(); Path tmpBase = Path.of(symbolicDir).toAbsolutePath().normalize();
Path tmp = tmpBase.resolve(model.getRequestPath()).normalize(); Path tmp = tmpBase.resolve(model.getRequestPath()).normalize();
Path responseBase = Paths.get(responseDir).toAbsolutePath().normalize(); Path responseBase = Paths.get(responseDir).toAbsolutePath().normalize();

View File

@@ -23,11 +23,11 @@ import org.springframework.stereotype.Service;
public class DataSetCountersService { public class DataSetCountersService {
private final ModelTrainMngCoreService modelTrainMngCoreService; private final ModelTrainMngCoreService modelTrainMngCoreService;
@Value("${train.docker.requestDir}") @Value("${train.docker.request_dir}")
private String requestDir; private String requestDir;
@Value("${train.docker.basePath}") @Value("${train.docker.symbolic_link_dir}")
private String trainBaseDir; private String symbolicDir;
public String getCount(Long modelId) { public String getCount(Long modelId) {
ModelTrainMngDto.Basic basic = modelTrainMngCoreService.findModelById(modelId); ModelTrainMngDto.Basic basic = modelTrainMngCoreService.findModelById(modelId);
@@ -45,7 +45,7 @@ public class DataSetCountersService {
} }
// tmp // tmp
Path tmpPath = Path.of(trainBaseDir, "tmp", basic.getRequestPath()); Path tmpPath = Path.of(symbolicDir, basic.getRequestPath());
// 차이나는거 // 차이나는거
diffMergedRequestsVsTmp(uids, tmpPath); diffMergedRequestsVsTmp(uids, tmpPath);

View File

@@ -31,27 +31,26 @@ public class DockerTrainService {
private String image; private String image;
// 학습 요청 데이터가 위치한 호스트 디렉토리 // 학습 요청 데이터가 위치한 호스트 디렉토리
@Value("${train.docker.requestDir}") @Value("${train.docker.request_dir}")
private String requestDir; private String requestDir;
// 학습 결과가 저장될 호스트 디렉토리 // 학습 결과가 저장될 호스트 디렉토리
@Value("${train.docker.responseDir}") @Value("${train.docker.response_dir}")
private String responseDir; private String responseDir;
// 컨테이너 이름 prefix
@Value("${train.docker.containerPrefix}")
private String containerPrefix;
// 공유메모리 사이즈 설정 (대용량 학습시 필요) // 공유메모리 사이즈 설정 (대용량 학습시 필요)
@Value("${train.docker.shmSize:16g}") @Value("${train.docker.shm_size:16g}")
private String shmSize; private String shmSize;
// data 경로 request,response 상위 폴더 // data 경로 request,response 상위 폴더
@Value("${train.docker.basePath}") @Value("${train.docker.base_path}")
private String basePath; private String basePath;
@Value("${train.docker.symbolic_link_dir}")
private String symbolicDir;
// IPC host 사용 여부 // IPC host 사용 여부
@Value("${train.docker.ipcHost:true}") @Value("${train.docker.ipc_host:true}")
private boolean ipcHost; private boolean ipcHost;
@Value("${spring.profiles.active}") @Value("${spring.profiles.active}")
@@ -260,12 +259,12 @@ public class DockerTrainService {
c.add("NCCL_SOCKET_IFNAME=eth0"); c.add("NCCL_SOCKET_IFNAME=eth0");
// 요청/결과 디렉토리 볼륨 마운트 // 요청/결과 디렉토리 볼륨 마운트
// c.add("-v");
// c.add(basePath + ":" + basePath); // 심볼릭 링크와 연결되는 실제 파일 경로도 마운트를 해줘야 함
c.add("-v"); c.add("-v");
c.add(basePath + "/tmp:/data"); c.add(basePath + ":" + basePath); // 심볼릭 링크와 연결되는 실제 파일 경로도 마운트를 해줘야 함
c.add("-v"); c.add("-v");
c.add(responseDir + ":/checkpoints"); c.add(symbolicDir + ":/data"); //요청할경로
c.add("-v");
c.add(responseDir + ":/checkpoints"); //저장될경로
// 표준입력 유지 (-it 대신 -i만 사용) // 표준입력 유지 (-it 대신 -i만 사용)
c.add("-i"); c.add("-i");

View File

@@ -50,7 +50,7 @@ public class JobRecoveryOnStartupService {
* *
* <p>컨테이너가 --rm 으로 삭제된 경우에도 이 경로에 val.csv / *.pth 등이 남아있으면 정상 종료 여부를 "파일 기반"으로 판정합니다. * <p>컨테이너가 --rm 으로 삭제된 경우에도 이 경로에 val.csv / *.pth 등이 남아있으면 정상 종료 여부를 "파일 기반"으로 판정합니다.
*/ */
@Value("${train.docker.responseDir}") @Value("${train.docker.response_dir}")
private String responseDir; private String responseDir;
/** /**

View File

@@ -42,7 +42,7 @@ public class ModelTestMetricsJobService {
private String profile; private String profile;
// 학습 결과가 저장될 호스트 디렉토리 // 학습 결과가 저장될 호스트 디렉토리
@Value("${train.docker.responseDir}") @Value("${train.docker.response_dir}")
private String responseDir; private String responseDir;
@Value("${file.pt-path}") @Value("${file.pt-path}")

View File

@@ -33,7 +33,7 @@ public class ModelTrainMetricsJobService {
private String profile; private String profile;
// 학습 결과가 저장될 호스트 디렉토리 // 학습 결과가 저장될 호스트 디렉토리
@Value("${train.docker.responseDir}") @Value("${train.docker.response_dir}")
private String responseDir; private String responseDir;
/** 결과 csv 파일 정보 등록 */ /** 결과 csv 파일 정보 등록 */

View File

@@ -14,12 +14,11 @@ import org.springframework.stereotype.Service;
@RequiredArgsConstructor @RequiredArgsConstructor
public class TmpDatasetService { public class TmpDatasetService {
@Value("${train.docker.requestDir}") @Value("${train.docker.request_dir}")
private String requestDir; private String requestDir;
@Value("${train.docker.basePath}") @Value("${train.docker.symbolic_link_dir}")
private String trainBaseDir; private String symbolicDir;
/** /**
* train, val, test 폴더별로 link * train, val, test 폴더별로 link
* *
@@ -36,7 +35,7 @@ public class TmpDatasetService {
throw new IOException("links is empty"); throw new IOException("links is empty");
} }
Path tmp = Path.of(trainBaseDir, "tmp", uid); Path tmp = Path.of(symbolicDir, uid);
long linksMade = 0; long linksMade = 0;
@@ -115,7 +114,7 @@ public class TmpDatasetService {
log.info("requestDir(raw)={}", requestDir); log.info("requestDir(raw)={}", requestDir);
Path BASE = toPath(requestDir); Path BASE = toPath(requestDir);
Path tmp = Path.of(trainBaseDir, "tmp", uid); Path tmp = Path.of(symbolicDir, uid);
log.info("BASE={}", BASE); log.info("BASE={}", BASE);
log.info("BASE exists? {}", Files.isDirectory(BASE)); log.info("BASE exists? {}", Files.isDirectory(BASE));

View File

@@ -40,7 +40,7 @@ public class TrainJobService {
private final DataSetCountersService dataSetCounters; private final DataSetCountersService dataSetCounters;
// 학습 결과가 저장될 호스트 디렉토리 // 학습 결과가 저장될 호스트 디렉토리
@Value("${train.docker.responseDir}") @Value("${train.docker.response_dir}")
private String responseDir; private String responseDir;
public Long getModelIdByUuid(UUID uuid) { public Long getModelIdByUuid(UUID uuid) {

View File

@@ -5,14 +5,10 @@ spring:
jpa: jpa:
show-sql: true show-sql: true
hibernate:
ddl-auto: validate
properties: properties:
hibernate: hibernate:
default_batch_fetch_size: 100 # ✅ 성능 - N+1 쿼리 방지 use_sql_comments: true # ⚠️ 선택 - SQL에 주석 추가 (디버깅용)
order_updates: true # ✅ 성능 - 업데이트 순서 정렬로 데드락 방지 format_sql: true # ⚠️ 선택 - SQL 포맷팅 (가독성)
use_sql_comments: true # ⚠️ 선택 - SQL에 주석 추가 (디버깅용)
format_sql: true # ⚠️ 선택 - SQL 포맷팅 (가독성)
datasource: datasource:
url: jdbc:postgresql://192.168.2.127:15432/kamco_training_db url: jdbc:postgresql://192.168.2.127:15432/kamco_training_db
@@ -21,14 +17,6 @@ spring:
hikari: hikari:
minimum-idle: 10 minimum-idle: 10
maximum-pool-size: 20 maximum-pool-size: 20
connection-timeout: 60000 # 60초 연결 타임아웃
idle-timeout: 300000 # 5분 유휴 타임아웃
max-lifetime: 1800000 # 30분 최대 수명
leak-detection-threshold: 60000 # 연결 누수 감지
transaction:
default-timeout: 300 # 5분 트랜잭션 타임아웃
jwt: jwt:
secret: "kamco_token_dev_dfc6446d-68fc-4eba-a2ff-c80a14a0bf3a" secret: "kamco_token_dev_dfc6446d-68fc-4eba-a2ff-c80a14a0bf3a"
@@ -37,23 +25,12 @@ jwt:
token: token:
refresh-cookie-name: kamco-dev # 개발용 쿠키 이름 refresh-cookie-name: kamco-dev # 개발용 쿠키 이름
refresh-cookie-secure: false # 로컬 http 테스트면 false refresh-cookie-secure: false # 로컬 http 테스트면 false
springdoc:
swagger-ui:
persist-authorization: true # 스웨거 새로고침해도 토큰 유지, 로컬스토리지에 저장
member:
init_password: kamco1234!
swagger: swagger:
local-port: 8080 local-port: 8080
file: file:
sync-root-dir: /app/original-images/
sync-tmp-dir: ${file.sync-root-dir}tmp/
sync-file-extention: tfw,tif
dataset-dir: /home/kcomu/data/request/ dataset-dir: /home/kcomu/data/request/
dataset-tmp-dir: ${file.dataset-dir}tmp/ dataset-tmp-dir: ${file.dataset-dir}tmp/
@@ -63,10 +40,10 @@ file:
train: train:
docker: docker:
image: kamco-cd-train:latest image: kamco-cd-train:latest
requestDir: /home/kcomu/data/request base_path: /home/kcomu/data
responseDir: /home/kcomu/data/response request_dir: ${train.docker.base_path}/request
basePath: /home/kcomu/data response_dir: ${train.docker.base_path}/response
containerPrefix: kamco-cd-train symbolic_link_dir: ${train.docker.base_path}/tmp
shmSize: 16g container_prefix: kamco-cd-train
ipcHost: true shm_size: 16g
ipc_host: true

View File

@@ -3,15 +3,6 @@ spring:
activate: activate:
on-profile: prod on-profile: prod
jpa:
show-sql: false # 운영 환경에서는 성능을 위해 비활성화
hibernate:
ddl-auto: validate
properties:
hibernate:
default_batch_fetch_size: 100 # N+1 쿼리 방지
order_updates: true # 업데이트 순서 정렬로 데드락 방지
datasource: datasource:
url: jdbc:postgresql://kamco-cd-train-db:5432/kamco_training_db url: jdbc:postgresql://kamco-cd-train-db:5432/kamco_training_db
username: kamco_training_user username: kamco_training_user
@@ -19,13 +10,6 @@ spring:
hikari: hikari:
minimum-idle: 10 minimum-idle: 10
maximum-pool-size: 20 maximum-pool-size: 20
connection-timeout: 60000 # 60초 연결 타임아웃
idle-timeout: 300000 # 5분 유휴 타임아웃
max-lifetime: 1800000 # 30분 최대 수명
leak-detection-threshold: 60000 # 연결 누수 감지
transaction:
default-timeout: 300 # 5분 트랜잭션 타임아웃
jwt: jwt:
# ⚠️ 운영 환경에서는 반드시 별도의 강력한 시크릿 키를 사용하세요 # ⚠️ 운영 환경에서는 반드시 별도의 강력한 시크릿 키를 사용하세요
@@ -37,36 +21,23 @@ token:
refresh-cookie-name: kamco refresh-cookie-name: kamco
refresh-cookie-secure: true # HTTPS 환경에서 필수 refresh-cookie-secure: true # HTTPS 환경에서 필수
springdoc:
swagger-ui:
persist-authorization: true # 스웨거 새로고침해도 토큰 유지, 로컬스토리지에 저장
member:
init_password: kamco1234!
swagger: swagger:
local-port: 9080 local-port: 9080
file: file:
# sync-root-dir: /app/original-images/ dataset-dir: /data/training/request/
# sync-tmp-dir: ${file.sync-root-dir}tmp/
# sync-file-extention: tfw,tif
dataset-dir: /data/request/
dataset-tmp-dir: ${file.dataset-dir}tmp/ dataset-tmp-dir: ${file.dataset-dir}tmp/
pt-path: /data/response/v6-cls-checkpoints/ pt-path: /data/training/response/v6-cls-checkpoints/
pt-FileName: yolov8_6th-6m.pt pt-FileName: yolov8_6th-6m.pt
train: train:
docker: docker:
image: kamco-cd-train:latest image: kamco-cd-train:latest
requestDir: /data/request base_path: /data/training
responseDir: /data/response request_dir: ${train.docker.base_path}/request
basePath: /data response_dir: ${train.docker.base_path}/response
containerPrefix: kamco-cd-train symbolic_link_dir: ${train.docker.base_path}/tmp
shmSize: 16g container_prefix: kamco-cd-train
ipcHost: true shm_size: 16g
ipc_host: true

View File

@@ -10,25 +10,25 @@ spring:
datasource: datasource:
driver-class-name: org.postgresql.Driver driver-class-name: org.postgresql.Driver
hikari: hikari:
minimum-idle: 2 connection-timeout: 60000 # 60초 연결 타임아웃
maximum-pool-size: 2 idle-timeout: 300000 # 5분 유휴 타임아웃
connection-timeout: 20000 max-lifetime: 1800000 # 30분 최대 수명
idle-timeout: 300000 leak-detection-threshold: 60000 # 연결 누수 감지
max-lifetime: 1800000 # minimum-idle, maximum-pool-size 는 프로파일별 설정
leak-detection-threshold: 60000
jpa: jpa:
hibernate: hibernate:
ddl-auto: update # 스키마 자동 관리 활성화 ddl-auto: validate
properties: properties:
hibernate: hibernate:
javax: jakarta:
persistence: persistence:
validation: validation:
mode: none mode: none
jdbc: jdbc:
batch_size: 50 batch_size: 50
default_batch_fetch_size: 100 default_batch_fetch_size: 100
order_updates: true
show-sql: false show-sql: false
servlet: servlet:
@@ -36,6 +36,10 @@ spring:
enabled: true enabled: true
max-file-size: 10GB max-file-size: 10GB
max-request-size: 10GB max-request-size: 10GB
transaction:
default-timeout: 300 # 5분 트랜잭션 타임아웃
logging: logging:
level: level:
org: org:
@@ -44,7 +48,12 @@ logging:
security: INFO security: INFO
root: INFO root: INFO
springdoc:
swagger-ui:
persist-authorization: true # 스웨거 새로고침해도 토큰 유지
member:
init_password: kamco1234!
# actuator # actuator
management: management:

View File

@@ -23,9 +23,7 @@ spring:
ddl-auto: none # 테스트 환경에서는 DDL 자동 생성/수정 비활성화 ddl-auto: none # 테스트 환경에서는 DDL 자동 생성/수정 비활성화
properties: properties:
hibernate: hibernate:
hbm2ddl: jakarta:
auto: none
javax:
persistence: persistence:
validation: validation:
mode: none mode: none
@@ -74,4 +72,3 @@ token:
member: member:
init_password: test1234! init_password: test1234!