diff --git a/shp-exporter/DOCKER.md b/shp-exporter/DOCKER.md new file mode 100644 index 0000000..1c4c420 --- /dev/null +++ b/shp-exporter/DOCKER.md @@ -0,0 +1,98 @@ +# Docker 빌드 및 실행 가이드 + +## 추가된 파일 + +| 파일 | 설명 | +|------|------| +| `Dockerfile` | 멀티스테이지 빌드 정의 | +| `.dockerignore` | Docker 빌드 컨텍스트 제외 목록 | + +--- + +## Dockerfile 구조 + +### Stage 1 — Builder (`eclipse-temurin:21-jdk-jammy`) + +1. Gradle wrapper 및 `build.gradle` 복사 → 의존성 레이어 캐싱 +2. 소스 코드 복사 후 `./gradlew clean bootJar -x test` 실행 +3. 출력: `build/libs/shp-exporter-v2.jar` + +### Stage 2 — Runtime (`eclipse-temurin:21-jre-jammy`) + +- JDK 없이 JRE만 포함 → 이미지 크기 최소화 +- 출력 디렉토리 `/data/model_output/export` 사전 생성 +- JVM 옵션 포함 (`-Xmx4g`, G1GC 튜닝 등) + +--- + +## 빌드 + +```bash +docker build -t shp-exporter . +``` + +--- + +## 실행 + +### Spring Batch 모드 (권장) + +```bash +docker run --rm \ + -v /data/model_output/export:/data/model_output/export \ + -e GEOSERVER_USERNAME=admin \ + -e GEOSERVER_PASSWORD=geoserver \ + shp-exporter \ + --batch \ + --converter.batch-ids[0]=252 +``` + +### GeoServer 등록 포함 + +```bash +docker run --rm \ + -v /data/model_output/export:/data/model_output/export \ + -e GEOSERVER_USERNAME=admin \ + -e GEOSERVER_PASSWORD=geoserver \ + shp-exporter \ + --batch \ + --geoserver.enabled=true \ + --converter.inference-id=D5E46F60FC40B1A8BE0CD1F3547AA6 \ + --converter.batch-ids[0]=252 \ + --converter.batch-ids[1]=253 +``` + +### Shapefile 업로드 모드 + +```bash +docker run --rm \ + -v /data/model_output/export:/data/model_output/export \ + -e GEOSERVER_USERNAME=admin \ + -e GEOSERVER_PASSWORD=geoserver \ + shp-exporter \ + --upload-shp /data/model_output/export/path/to/file.shp \ + --layer layer_name +``` + +### DB 주소 오버라이드 + +`application-prod.yml`의 DB 호스트(`kamco-cd-postgis`)가 네트워크 환경과 다를 경우: + +```bash +docker run --rm \ + --network your-network \ + -v /data/model_output/export:/data/model_output/export \ + shp-exporter \ + --batch \ + --spring.datasource.url=jdbc:postgresql://HOST:5432/kamco_cds \ + --converter.batch-ids[0]=252 +``` + +--- + +## 주의사항 + +- **볼륨 마운트 필수**: 출력 파일(`/data/model_output/export`)은 호스트 볼륨으로 마운트하지 않으면 컨테이너 종료 시 소실됨 +- **네트워크**: DB 호스트명 `kamco-cd-postgis`가 컨테이너에서 resolve되어야 함 (`--network` 또는 `--add-host` 활용) +- **GeoServer 크리덴셜**: `GEOSERVER_USERNAME` / `GEOSERVER_PASSWORD` 환경변수로 주입 (`application-prod.yml`에 하드코딩된 값은 덮어씌워짐) +- **`.dockerignore`는 `.gitignore`에 등록**되어 있어 git에 커밋되지 않음 — 필요 시 `.gitignore`에서 해당 라인 제거 diff --git a/shp-exporter/Dockerfile b/shp-exporter/Dockerfile new file mode 100644 index 0000000..6e8d5c9 --- /dev/null +++ b/shp-exporter/Dockerfile @@ -0,0 +1,38 @@ +# ---- Build Stage ---- +FROM eclipse-temurin:21-jdk-jammy AS builder + +WORKDIR /workspace + +# Gradle wrapper 및 빌드 설정 복사 (캐시 레이어 최적화) +COPY gradlew settings.gradle build.gradle ./ +COPY gradle ./gradle + +# 의존성 다운로드 (소스 변경 시 재빌드 방지) +RUN chmod +x gradlew && ./gradlew dependencies --no-daemon -q || true + +# 소스 복사 후 빌드 (테스트 제외) +COPY src ./src +RUN ./gradlew clean bootJar -x test --no-daemon -q + +# ---- Runtime Stage ---- +FROM eclipse-temurin:21-jre-jammy + +WORKDIR /app + +# 출력 디렉토리 생성 +RUN mkdir -p /data/model_output/export + +# JAR 복사 +COPY --from=builder /workspace/build/libs/shp-exporter-v2.jar app.jar + +# GeoServer 크리덴셜은 환경변수로 주입 +ENV GEOSERVER_USERNAME="" +ENV GEOSERVER_PASSWORD="" + +ENTRYPOINT ["java", \ + "-Xmx4g", "-Xms512m", \ + "-XX:+UseG1GC", \ + "-XX:MaxGCPauseMillis=200", \ + "-XX:G1HeapRegionSize=16m", \ + "-XX:+ParallelRefProcEnabled", \ + "-jar", "app.jar"] diff --git a/shp-exporter/build.gradle b/shp-exporter/build.gradle index 0a7d18d..f6e8ea4 100755 --- a/shp-exporter/build.gradle +++ b/shp-exporter/build.gradle @@ -14,27 +14,16 @@ java { } } -//repositories { -// mavenCentral() -// maven { -// url 'https://repo.osgeo.org/repository/release/' -// } -// maven { -// url 'https://repo.osgeo.org/repository/geotools-releases/' -// } -// maven { -// url 'https://repo.osgeo.org/repository/snapshot/' -// } -//} - -def repoUrl = System.getProperty("org.gradle.project.repoUrl") - ?: System.getenv("ORG_GRADLE_PROJECT_repoUrl") - ?: "http://172.16.4.56:18100/repository/maven-public/" - repositories { + mavenCentral() maven { - url = uri(repoUrl) - allowInsecureProtocol = true + url 'https://repo.osgeo.org/repository/release/' + } + maven { + url 'https://repo.osgeo.org/repository/geotools-releases/' + } + maven { + url 'https://repo.osgeo.org/repository/snapshot/' } } @@ -98,3 +87,10 @@ spotless { tasks.named('test') { useJUnitPlatform() } + +bootRun { + jvmArgs = ['-Xmx4g', '-Xms512m', '-XX:+UseG1GC', + '-XX:MaxGCPauseMillis=200', // GC 목표 멈춤 시간 + '-XX:G1HeapRegionSize=16m', // 큰 geometry 객체 처리 + '-XX:+ParallelRefProcEnabled'] // 참조 처리 병렬화 +} diff --git a/shp-exporter/gradle/wrapper/gradle-wrapper.properties b/shp-exporter/gradle/wrapper/gradle-wrapper.properties index 078b65d..be5743b 100755 --- a/shp-exporter/gradle/wrapper/gradle-wrapper.properties +++ b/shp-exporter/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -#distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip -distributionUrl=http\://172.16.4.56:18100/repository/gradle-distributions/gradle-8.14.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip +#distributionUrl=http\://172.16.4.56:18100/repository/gradle-distributions/gradle-8.14.3-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/shp-exporter/src/main/resources/application-dev.yml b/shp-exporter/src/main/resources/application-dev.yml index 38e2e87..96feb5b 100755 --- a/shp-exporter/src/main/resources/application-dev.yml +++ b/shp-exporter/src/main/resources/application-dev.yml @@ -29,9 +29,9 @@ converter: crs: 'EPSG:5186' batch: - chunk-size: 5000 # 청크 크기 증가 (1000 → 5000, 성능 5배 향상) + chunk-size: 1000 # 청크 크기 증가 (1000 → 5000, 성능 5배 향상) skip-limit: 100 # 청크당 skip 허용 건수 - fetch-size: 5000 # JDBC 커서 fetch 크기 (chunk-size와 동일하게) + fetch-size: 1000 # JDBC 커서 fetch 크기 (chunk-size와 동일하게) enable-partitioning: false geoserver: diff --git a/shp-exporter/src/main/resources/application-prod.yml b/shp-exporter/src/main/resources/application-prod.yml index 722e987..ae20722 100755 --- a/shp-exporter/src/main/resources/application-prod.yml +++ b/shp-exporter/src/main/resources/application-prod.yml @@ -29,9 +29,9 @@ converter: crs: 'EPSG:5186' batch: - chunk-size: 5000 # 청크 크기 (1000→5000, 성능 5배 향상, 메모리 ~200MB per chunk) + chunk-size: 1000 # 4.7M 건 OOM 방지: 청크별 트랜잭션 커밋으로 GeoTools 메모리 해제 skip-limit: 100 # 청크당 skip 허용 건수 - fetch-size: 5000 # JDBC 커서 fetch 크기 (chunk-size와 동일하게) + fetch-size: 1000 # JDBC 커서 fetch 크기 (chunk-size와 동일하게) enable-partitioning: false # 초기에는 비활성화 partition-concurrency: 4 # Map ID별 병렬 처리 동시성 (4=~300MB, 8=~600MB) @@ -46,7 +46,7 @@ geoserver: logging: level: - com.kamco.makesample: DEBUG + com.kamco.makesample: INFO # DEBUG → INFO: 4.7M 건 write 중 불필요한 로그 I/O 제거 org.springframework: WARN pattern: console: '%d{yyyy-MM-dd HH:mm:ss} - %msg%n' diff --git a/shp-exporter/src/main/resources/test b/shp-exporter/src/main/resources/test new file mode 100644 index 0000000..24715bf --- /dev/null +++ b/shp-exporter/src/main/resources/test @@ -0,0 +1,9 @@ + java -Xmx4g -Xms512m -XX:+UseG1GC \ + -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=16m \ + -jar build/libs/shp-exporter.jar \ + --batch \ + --converter.inference-id=test009 \ + --converter.batch-ids[0]=111 \ + --converter.batch-ids[1]=114 \ + --converter.batch-ids[2]=162 \ + --geoserver.enabled=true