From c10d44d0688a3116107c05df99362932fc0a605f Mon Sep 17 00:00:00 2001 From: juhanByeon Date: Sat, 9 May 2026 20:01:39 +0900 Subject: [PATCH] =?UTF-8?q?#=20chore(docker):=20app=20profile=20=ED=92=80?= =?UTF-8?q?=EC=8A=A4=ED=83=9D=20=EC=BB=A8=ED=85=8C=EC=9D=B4=EB=84=88=20?= =?UTF-8?q?=EC=8B=A4=ED=96=89=20=EC=B6=94=EA=B0=80=20+=20Prometheus=20scra?= =?UTF-8?q?pe=20=EA=B2=BD=EB=A1=9C=20=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Summary `docker compose --profile app up -d --build` 한 번으로 4개 앱(`remittance-api`, `payout-worker`, `webhook-dispatcher`, `reconciler`)까지 기동할 수 있도록 풀스택 컨테이너 실행 구성을 추가했습니다. 동시에 Prometheus scrape 대상을 `host.docker.internal`에서 앱 컨테이너 직접 scrape 방식으로 전환하고, README에 개발 모드/풀스택 모드 실행 가이드를 정리했습니다. --- ### Changes #### 1) Docker 컨테이너 빌드/실행 기반 추가 - `Dockerfile` (신규) - 단일 Dockerfile + `ARG MODULE`로 4개 모듈 공통 이미지 빌드 - Spring Boot Layered JAR(`dependencies/spring-boot-loader/snapshot-dependencies/application`) 분리 COPY - runtime `HEALTHCHECK` (`/actuator/health`) 추가 - `.dockerignore` (신규) - build context 최소화 (`docs`, `docker`, `mock-*`, `.git` 등 제외) #### 2) docker-compose 풀스택 app profile 추가 - `docker-compose.yml` - `remittance-api`, `payout-worker`, `webhook-dispatcher`, `reconciler` 서비스 추가 (`profiles: ["app"]`) - 각 앱 컨테이너 내부 포트 `8080` 통일 + 호스트 포트만 분리 - `8080:8080`, `8081:8080`, `8082:8080`, `8084:8080` - 앱별 DB/Kafka/Redis/외부 mock URL 환경변수 주입 - WireMock healthcheck를 `wget --spider`(HEAD)에서 `wget -O /dev/null`(GET) 방식으로 변경 #### 3) Prometheus scrape 대상 전환 - `docker/prometheus.yml` - scrape target을 호스트 기반에서 컨테이너 DNS 기반으로 변경 - `remittance-api:8080` - `payout-worker:8080` - `webhook-dispatcher:8080` - `reconciler:8080` - 중복 수집(동일 인스턴스 host-published 경로 재수집) 회피 목적 주석 추가 #### 4) 애플리케이션 설정 보강 - `remittance-api/src/main/resources/application.yaml` - `payout-worker/src/main/resources/application.yaml` - `webhook-dispatcher/src/main/resources/application.yaml` - `reconciler/src/main/resources/application.yaml` - container 환경 주입(`SERVER_PORT`, `DB_URL` 등) 기반 실행에 맞춘 설정 정리 #### 5) 문서 업데이트 - `README.md` - 실행 모드 분리: - 개발 모드(인프라만) - 풀스택 모드(`--profile app`) - E2E 검증 절차/헬스체크/관측성 설명 업데이트 - Layered JAR + `ARG MODULE` 컨테이너 전략 설명 추가 --- ### Checklist - [x] 단일 Dockerfile 기반 멀티 모듈 컨테이너 빌드 추가 - [x] docker-compose `app` profile로 4개 앱 컨테이너 기동 추가 - [x] WireMock healthcheck false-negative 이슈 수정 - [x] Prometheus scrape 대상을 컨테이너 직접 scrape로 전환 - [x] 실행/관측성 README 가이드 업데이트 --- ### How to Test ```bash # 1) 풀스택 기동 docker compose --profile app up -d --build # 2) 앱 헬스 확인 for p in 8080 8081 8082 8084; do curl -fsS http://localhost:$p/actuator/health; echo; done # 3) Prometheus 타겟 확인 curl -s http://localhost:9090/api/v1/targets | jq '.data.activeTargets[] | {scrapeUrl: .scrapeUrl, health: .health}' # 4) Debezium connector 상태 확인 curl -sS http://localhost:8083/connectors/openremit-outbox/status | jq --- .dockerignore | 24 ++++ Dockerfile | 50 ++++++++ README.md | 97 +++++++++++---- docker-compose.yml | 117 +++++++++++++++++- docker/prometheus.yml | 13 +- .../src/main/resources/application.yaml | 6 +- .../src/main/resources/application.yaml | 6 +- .../src/main/resources/application.yaml | 13 +- .../src/main/resources/application.yaml | 6 +- 9 files changed, 289 insertions(+), 43 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..74d7b3a --- /dev/null +++ b/.dockerignore @@ -0,0 +1,24 @@ +# Gradle / Kotlin / IDE 캐시 — 빌드 컨텍스트 비대화 + 호스트 잔여물 차단 +**/build +**/.gradle +**/.kotlin +.idea +*.iml + +# VCS / 인프라 산출물 — 컨테이너 안에서 필요 없음 +.git +.github +.gitignore +.gitattributes + +# 인프라/문서 — Dockerfile build stage에서 미사용 +docs +docker +debezium +mock-fx +mock-payout +mock-webhook +mysql-init +docker-compose.yml +README.md +AGENTS.md diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f06ffde --- /dev/null +++ b/Dockerfile @@ -0,0 +1,50 @@ +# syntax=docker/dockerfile:1.7 +# +# 단일 Dockerfile로 4개 Spring Boot 모듈(remittance-api, payout-worker, +# webhook-dispatcher, reconciler)을 ARG MODULE 로 빌드. +# +# Layered JAR 패턴: dependencies / spring-boot-loader / snapshot-dependencies +# / application 4개 layer를 분리 COPY 하여 코드 변경 시 application layer만 +# 갱신되도록 Docker layer 캐시 효율을 확보. + +# === build stage: gradle → bootJar === +FROM eclipse-temurin:21-jdk AS build +WORKDIR /workspace + +COPY gradlew settings.gradle.kts build.gradle.kts ./ +COPY gradle ./gradle +COPY common ./common +COPY payment-module ./payment-module +COPY remittance-api ./remittance-api +COPY payout-worker ./payout-worker +COPY webhook-dispatcher ./webhook-dispatcher +COPY reconciler ./reconciler + +ARG MODULE +RUN chmod +x gradlew && ./gradlew :${MODULE}:bootJar --no-daemon -x test + +# === extract stage: layered JAR을 layer별 디렉터리로 분해 === +# tools jarmode의 extract --destination은 디렉터리가 비어있길 요구하므로 +# JAR은 /tmp에 두고 빈 /extract를 destination으로 사용. +FROM eclipse-temurin:21-jdk AS extract +ARG MODULE +COPY --from=build /workspace/${MODULE}/build/libs/*.jar /tmp/app.jar +WORKDIR /extract +RUN java -Djarmode=tools -jar /tmp/app.jar extract \ + --layers dependencies,spring-boot-loader,snapshot-dependencies,application \ + --launcher --destination . + +# === runtime stage: layer 순서대로 별도 COPY → 별도 Docker layer 형성 === +FROM eclipse-temurin:21-jre +# curl: HEALTHCHECK가 actuator/health를 polling 하기 위해 필요 +RUN apt-get update \ + && apt-get install -y --no-install-recommends curl \ + && rm -rf /var/lib/apt/lists/* +WORKDIR /app +COPY --from=extract /extract/dependencies/ ./ +COPY --from=extract /extract/spring-boot-loader/ ./ +COPY --from=extract /extract/snapshot-dependencies/ ./ +COPY --from=extract /extract/application/ ./ +HEALTHCHECK --interval=10s --timeout=3s --start-period=30s --retries=12 \ + CMD curl -fsS http://localhost:8080/actuator/health || exit 1 +ENTRYPOINT ["java","org.springframework.boot.loader.launch.JarLauncher"] diff --git a/README.md b/README.md index bafccf0..ecb5b3f 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,30 @@ ## 실행 +두 가지 모드를 지원합니다. **개발 모드**는 인프라만 컨테이너로 띄우고 4개 앱은 IDE/호스트 JVM에서 `bootRun`, **풀스택 모드**는 4개 앱까지 컨테이너로 한 번에 기동합니다. + +### 개발 모드 (인프라만) + +```bash +docker compose up -d # 인프라만 (MySQL/Redis/Kafka/Debezium/WireMock×3/Prometheus/Grafana) +./gradlew :remittance-api:bootRun # 다른 터미널에서 모듈별 bootRun +``` + +### 풀스택 모드 — 1-command 실행 (`--profile app`) + ```bash -docker compose up -d -./gradlew :remittance-api:bootRun +docker compose --profile app up -d --build ``` -헬스체크: `http://localhost:8080/actuator/health` +4개 앱(remittance-api / payout-worker / webhook-dispatcher / reconciler)까지 컨테이너로 띄웁니다. 첫 실행은 Gradle 의존성 다운로드 때문에 수 분 걸리지만, 이후 코드 변경 시에는 layered JAR의 `application` layer만 갱신되어 빌드/푸시가 빠릅니다(상세는 ["컨테이너화 — Layered JAR + ARG MODULE"](#컨테이너화--layered-jar--arg-module) 섹션). + +헬스체크 (두 모드 공통): +``` +http://localhost:8080/actuator/health # remittance-api +http://localhost:8081/actuator/health # payout-worker +http://localhost:8082/actuator/health # webhook-dispatcher +http://localhost:8084/actuator/health # reconciler +``` ## 모듈 @@ -192,54 +210,85 @@ GitHub Actions CI에서도 동일한 Testcontainers 기반으로 매 커밋 검 ## docker-compose 풀스택 검증 (Debezium 포함 E2E) -```bash -docker compose up -d -``` - -기동 컨테이너: +기동 컨테이너 (default 프로필 — 인프라만): - `openremit-mysql` (3306, binlog ROW + GTID 활성) - `openremit-redis` (6379) - `openremit-kafka` (9092 host / 29092 internal, KRaft single-node) - `openremit-mock-fx` (9999), `openremit-mock-payout` (9998), `openremit-mock-webhook` (9997) — WireMock - `openremit-debezium` (8083) — Connect standalone - `openremit-debezium-register` — outbox 커넥터 자동 등록 (1회성, retry 6회) -- `openremit-prometheus` (9090) — `host.docker.internal`로 호스트 JVM의 4개 모듈 scrape +- `openremit-prometheus` (9090) — 풀스택 모드의 컨테이너 앱(`remittance-api:8080` 등)을 직접 scrape. 호스트 JVM 모드에서는 Grafana 대시보드 비어 보임(트레이드오프) - `openremit-grafana` (3000) — anonymous Viewer 허용, datasource(`prometheus`) + 대시보드(`openremit`) provisioning -검증: +`--profile app` 추가 시 4개 앱 컨테이너도 기동: +- `openremit-remittance-api` (8080:8080), `openremit-payout-worker` (8081:8080), `openremit-webhook-dispatcher` (8082:8080), `openremit-reconciler` (8084:8080) + +E2E 검증: ```bash +docker compose --profile app up -d --build + # Debezium 커넥터 상태 curl -sS http://localhost:8083/connectors/openremit-outbox/status | jq -# remittance-api 기동 -./gradlew :remittance-api:bootRun -# 다른 터미널에서 payout-worker 기동 -./gradlew :payout-worker:bootRun +# 4개 앱 헬스 +for p in 8080 8081 8082 8084; do curl -fsS http://localhost:$p/actuator/health; echo; done -# 송금 요청 (POST /api/v1/remittances) 후 토픽에 흐르는지 확인 +# 송금 요청(POST /api/v1/remittances) 후 토픽에 흐르는지 확인 docker exec -it openremit-kafka /opt/kafka/bin/kafka-console-consumer.sh \ --bootstrap-server localhost:9092 --topic remittance.paid --from-beginning ``` -볼륨 초기화가 필요하면 `docker compose down -v` 후 재기동 (mysql-init 스크립트가 다시 실행되어 Debezium 사용자가 생성됨). +볼륨 초기화가 필요하면 `docker compose --profile app down -v` 후 재기동 (mysql-init 스크립트가 다시 실행되어 Debezium 사용자가 생성됨). + +## 컨테이너화 — Layered JAR + ARG MODULE + +루트의 단일 [`Dockerfile`](Dockerfile) 한 벌로 4개 Spring Boot 모듈을 모두 빌드합니다. 두 가지 결정이 들어가 있습니다. + +**1. `ARG MODULE` — Dockerfile 한 벌로 4개 이미지** + +```dockerfile +ARG MODULE +RUN ./gradlew :${MODULE}:bootJar --no-daemon -x test +COPY --from=build /workspace/${MODULE}/build/libs/*.jar app.jar +``` + +`docker-compose.yml`에서 모듈마다 `build.args.MODULE`만 다르게 넘겨 4번 호출. Dockerfile 4개 복붙을 피하고, 빌드 패턴 변경 시 한 곳만 수정하면 됩니다. + +**2. Layered JAR — 변경 빈도가 다른 4개 layer를 분리** + +Spring Boot의 `tools` jarmode로 fat JAR을 layer별로 분해해 별도 `COPY`로 가져옵니다. + +```dockerfile +RUN java -Djarmode=tools -jar app.jar extract --layers --destination . +COPY --from=extract /extract/dependencies/ ./ # 거의 안 바뀜 +COPY --from=extract /extract/spring-boot-loader/ ./ # 거의 안 바뀜 +COPY --from=extract /extract/snapshot-dependencies/ ./ # 가끔 +COPY --from=extract /extract/application/ ./ # 매 커밋 +``` + +코드만 바꾼 재빌드에서 dependencies layer는 Docker 캐시 hit로 재전송 0, application layer(수백 KB)만 갱신됩니다. 단순 `COPY *.jar` 방식은 코드 한 줄 변경에도 fat JAR 전체(수십 MB)가 새 layer로 묶여 레지스트리 푸시·노드 풀 비용을 그대로 받습니다. + +**3. 컨테이너 내부 포트 표준화** + +application.yaml의 `server.port`(8080/8081/8082/8084)는 호스트 JVM 모드를 위한 값이고, 컨테이너에서는 `SERVER_PORT=8080`을 ENV로 주입해 모두 8080을 듣게 합니다. HEALTHCHECK·Prometheus scrape 경로를 컨테이너 단에서 단일화하고, 호스트 포트는 매핑 단계(`8081:8080` 등)에서만 분리합니다. ## 관측성 — 메트릭 / 로그 (Day 12) ### 메트릭 -각 Spring Boot 모듈이 `/actuator/prometheus`를 노출하고, `docker-compose`의 Prometheus가 `host.docker.internal:808x`로 scrape 합니다. +각 Spring Boot 모듈이 `/actuator/prometheus`를 노출하고, `docker-compose`의 Prometheus가 풀스택 모드의 컨테이너 앱(`remittance-api:8080` 등)을 직접 scrape 합니다. 호스트 JVM 모드(인프라만 띄우고 IDE에서 `bootRun`)에서는 Grafana 대시보드가 비어 보이며, raw 메트릭은 `curl localhost:808x/actuator/prometheus`로 확인합니다 — 호스트 JVM 잡과 컨테이너 잡을 동시에 두면 `host-published` 포트를 통해 같은 인스턴스가 중복 scrape 되어 Grafana 집계가 2배로 보이는 문제가 있어 풀스택 모드 정확도를 우선했습니다. ```bash curl -s http://localhost:8080/actuator/prometheus | head # remittance-api -curl -s http://localhost:9090/api/v1/targets | jq '.data.activeTargets[].health' +curl -s http://localhost:9090/api/v1/targets | jq '.data.activeTargets[] | {job, health}' ``` -| 모듈 | actuator 포트 | prometheus 라벨 | -|---|---|---| -| `remittance-api` | 8080 | `service="remittance-api"` | -| `payout-worker` | 8081 | `service="payout-worker"` | -| `webhook-dispatcher` | 8082 | `service="webhook-dispatcher"` | -| `reconciler` | 8084 | `service="reconciler"` | +| 모듈 | host 포트 | 컨테이너 포트 | prometheus 라벨 | +|---|---|---|---| +| `remittance-api` | 8080 | 8080 | `service="remittance-api"` | +| `payout-worker` | 8081 | 8080 | `service="payout-worker"` | +| `webhook-dispatcher` | 8082 | 8080 | `service="webhook-dispatcher"` | +| `reconciler` | 8084 | 8080 | `service="reconciler"` | Grafana 접속: `http://localhost:3000` (anonymous Viewer). 좌측 메뉴 → Dashboards → **OpenRemit / OpenRemit — Service Overview** 자동 로드. 대시보드 UID는 `openremit`이며 [`docker/grafana/dashboards/openremit.json`](docker/grafana/dashboards/openremit.json)에서 관리합니다. diff --git a/docker-compose.yml b/docker-compose.yml index 977202e..fa9b37e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -52,7 +52,9 @@ services: - ./mock-fx/mappings:/home/wiremock/mappings:ro command: ["--port", "8080", "--global-response-templating"] healthcheck: - test: ["CMD-SHELL", "wget -q --spider http://localhost:8080/__admin/health || exit 1"] + # WireMock /__admin/health는 GET만 응답(HEAD는 404). wget --spider가 HEAD를 + # 보내서 false-negative가 나므로 GET 후 응답 폐기 형태로 변경. + test: ["CMD-SHELL", "wget -q -O /dev/null http://localhost:8080/__admin/health || exit 1"] interval: 5s timeout: 3s retries: 10 @@ -66,7 +68,9 @@ services: - ./mock-payout/mappings:/home/wiremock/mappings:ro command: ["--port", "8080", "--global-response-templating"] healthcheck: - test: ["CMD-SHELL", "wget -q --spider http://localhost:8080/__admin/health || exit 1"] + # WireMock /__admin/health는 GET만 응답(HEAD는 404). wget --spider가 HEAD를 + # 보내서 false-negative가 나므로 GET 후 응답 폐기 형태로 변경. + test: ["CMD-SHELL", "wget -q -O /dev/null http://localhost:8080/__admin/health || exit 1"] interval: 5s timeout: 3s retries: 10 @@ -80,7 +84,9 @@ services: - ./mock-webhook/mappings:/home/wiremock/mappings:ro command: ["--port", "8080"] healthcheck: - test: ["CMD-SHELL", "wget -q --spider http://localhost:8080/__admin/health || exit 1"] + # WireMock /__admin/health는 GET만 응답(HEAD는 404). wget --spider가 HEAD를 + # 보내서 false-negative가 나므로 GET 후 응답 폐기 형태로 변경. + test: ["CMD-SHELL", "wget -q -O /dev/null http://localhost:8080/__admin/health || exit 1"] interval: 5s timeout: 3s retries: 10 @@ -208,6 +214,111 @@ services: timeout: 3s retries: 10 + # ---------- 풀스택 모드 (--profile app) ---------- + # 평소 개발은 인프라만 띄우고 호스트 JVM에서 :module:bootRun, 검증/시연 시 + # `docker compose --profile app up -d --build` 로 4개 앱까지 한 번에 기동. + # 컨테이너 내부 포트는 모두 8080으로 표준화(SERVER_PORT 주입), 호스트 포트 + # 매핑만 모듈별로 분리해 호스트 JVM 모드와 포트 충돌 없도록 정렬. + + remittance-api: + profiles: ["app"] + build: + context: . + args: + MODULE: remittance-api + container_name: openremit-remittance-api + depends_on: + mysql: + condition: service_healthy + redis: + condition: service_healthy + kafka: + condition: service_healthy + debezium-register: + condition: service_completed_successfully + mock-fx-api: + condition: service_healthy + environment: + SERVER_PORT: 8080 + DB_URL: jdbc:mysql://mysql:3306/openremit?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC + DB_USER: openremit + DB_PASSWORD: openremit + KAFKA_BOOTSTRAP: kafka:29092 + REDIS_ADDRESS: redis://redis:6379 + FX_BASE_URL: http://mock-fx-api:8080 + ports: + - "8080:8080" + + payout-worker: + profiles: ["app"] + build: + context: . + args: + MODULE: payout-worker + container_name: openremit-payout-worker + depends_on: + mysql: + condition: service_healthy + kafka: + condition: service_healthy + debezium-register: + condition: service_completed_successfully + mock-payout-api: + condition: service_healthy + environment: + SERVER_PORT: 8080 + DB_URL: jdbc:mysql://mysql:3306/openremit?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC + DB_USER: openremit + DB_PASSWORD: openremit + KAFKA_BOOTSTRAP: kafka:29092 + PAYOUT_BASE_URL: http://mock-payout-api:8080 + ports: + - "8081:8080" + + webhook-dispatcher: + profiles: ["app"] + build: + context: . + args: + MODULE: webhook-dispatcher + container_name: openremit-webhook-dispatcher + depends_on: + mysql: + condition: service_healthy + kafka: + condition: service_healthy + debezium-register: + condition: service_completed_successfully + mock-webhook: + condition: service_healthy + environment: + SERVER_PORT: 8080 + DB_URL: jdbc:mysql://mysql:3306/openremit?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC + DB_USER: openremit + DB_PASSWORD: openremit + KAFKA_BOOTSTRAP: kafka:29092 + WEBHOOK_TARGET_URL: http://mock-webhook:8080/webhook + ports: + - "8082:8080" + + reconciler: + profiles: ["app"] + build: + context: . + args: + MODULE: reconciler + container_name: openremit-reconciler + depends_on: + mysql: + condition: service_healthy + environment: + SERVER_PORT: 8080 + DB_URL: jdbc:mysql://mysql:3306/openremit?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC + DB_USER: openremit + DB_PASSWORD: openremit + ports: + - "8084:8080" + volumes: mysql-data: redis-data: diff --git a/docker/prometheus.yml b/docker/prometheus.yml index 4219b3d..0a6bd92 100644 --- a/docker/prometheus.yml +++ b/docker/prometheus.yml @@ -2,15 +2,20 @@ global: scrape_interval: 15s evaluation_interval: 15s +# 풀스택 모드(--profile app)에서 컨테이너 앱을 직접 scrape. host.docker.internal +# 잡을 같이 두면 host-published 포트를 통해 같은 인스턴스를 중복 수집해 Grafana +# 대시보드(`sum by (service)`)가 2배로 보이므로 container 잡 단독 사용. +# 호스트 JVM 모드에서는 Grafana 대시보드가 비고 raw 메트릭은 actuator/prometheus +# 직접 curl 로 확인. scrape_configs: - job_name: openremit metrics_path: /actuator/prometheus static_configs: - - targets: ["host.docker.internal:8080"] + - targets: ["remittance-api:8080"] labels: { service: remittance-api } - - targets: ["host.docker.internal:8081"] + - targets: ["payout-worker:8080"] labels: { service: payout-worker } - - targets: ["host.docker.internal:8082"] + - targets: ["webhook-dispatcher:8080"] labels: { service: webhook-dispatcher } - - targets: ["host.docker.internal:8084"] + - targets: ["reconciler:8080"] labels: { service: reconciler } diff --git a/payout-worker/src/main/resources/application.yaml b/payout-worker/src/main/resources/application.yaml index 614fa4f..a1a7e3e 100644 --- a/payout-worker/src/main/resources/application.yaml +++ b/payout-worker/src/main/resources/application.yaml @@ -7,9 +7,9 @@ spring: jackson: property-naming-strategy: SNAKE_CASE datasource: - url: jdbc:mysql://localhost:3306/openremit?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC - username: openremit - password: openremit + url: ${DB_URL:jdbc:mysql://localhost:3306/openremit?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC} + username: ${DB_USER:openremit} + password: ${DB_PASSWORD:openremit} driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate: diff --git a/reconciler/src/main/resources/application.yaml b/reconciler/src/main/resources/application.yaml index a29a4a2..dd2a2ba 100644 --- a/reconciler/src/main/resources/application.yaml +++ b/reconciler/src/main/resources/application.yaml @@ -7,9 +7,9 @@ spring: jackson: property-naming-strategy: SNAKE_CASE datasource: - url: jdbc:mysql://localhost:3306/openremit?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC - username: openremit - password: openremit + url: ${DB_URL:jdbc:mysql://localhost:3306/openremit?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC} + username: ${DB_USER:openremit} + password: ${DB_PASSWORD:openremit} driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate: diff --git a/remittance-api/src/main/resources/application.yaml b/remittance-api/src/main/resources/application.yaml index 13de563..a2509e9 100644 --- a/remittance-api/src/main/resources/application.yaml +++ b/remittance-api/src/main/resources/application.yaml @@ -7,9 +7,9 @@ spring: jackson: property-naming-strategy: SNAKE_CASE datasource: - url: jdbc:mysql://localhost:3306/openremit?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC - username: openremit - password: openremit + url: ${DB_URL:jdbc:mysql://localhost:3306/openremit?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC} + username: ${DB_USER:openremit} + password: ${DB_PASSWORD:openremit} driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate: @@ -21,6 +21,13 @@ spring: flyway: enabled: true locations: classpath:db/migration + # 풀스택 모드(--profile app)에서 다른 모듈이 자기 마이그레이션을 먼저 실행해 + # 스키마가 비어있지 않은 상태가 되면 default baseline-on-migrate=false에서는 + # FlywayException이 발생. 다른 3개 모듈(payout/webhook/reconciler)의 패턴과 + # 동일하게 baseline 자동 생성. 모듈별 테이블 네임스페이스가 겹치지 않아 + # V1 이후의 CREATE TABLE 과 충돌하지 않음. + baseline-on-migrate: true + baseline-version: "0" kafka: bootstrap-servers: ${KAFKA_BOOTSTRAP:localhost:9092} consumer: diff --git a/webhook-dispatcher/src/main/resources/application.yaml b/webhook-dispatcher/src/main/resources/application.yaml index 3fb54a4..9b1a51a 100644 --- a/webhook-dispatcher/src/main/resources/application.yaml +++ b/webhook-dispatcher/src/main/resources/application.yaml @@ -7,9 +7,9 @@ spring: jackson: property-naming-strategy: SNAKE_CASE datasource: - url: jdbc:mysql://localhost:3306/openremit?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC - username: openremit - password: openremit + url: ${DB_URL:jdbc:mysql://localhost:3306/openremit?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC} + username: ${DB_USER:openremit} + password: ${DB_PASSWORD:openremit} driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate: