From 8c3443a12f078a192d59021ea2f9bc2b25f7d866 Mon Sep 17 00:00:00 2001
From: MIN KYU LEE <107491279+costRider@users.noreply.github.com>
Date: Tue, 23 Dec 2025 01:25:08 +0900
Subject: [PATCH] Remove unavailable spring-boot-starter-restclient dependency
---
.dockerignore | 10 +++
.github/workflows/ci-petclinic-eks.yaml | 4 +-
.github/workflows/ci-petclinic-gke.yaml | 4 +-
Dockerfile | 77 +++++++++----------
README.md | 25 ++++++
build.gradle | 8 +-
k8s/aws/20-petclinic-Deployments-postgre.yaml | 8 +-
k8s/gcp/10-petclinic-secret-whatap.yaml | 26 +++++++
k8s/gcp/20-petclinic-Deployments-postgre.yaml | 6 +-
pom.xml | 10 +--
10 files changed, 116 insertions(+), 62 deletions(-)
create mode 100644 .dockerignore
create mode 100644 k8s/gcp/10-petclinic-secret-whatap.yaml
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 000000000..20a088516
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,10 @@
+target
+.mvn
+.git
+.github
+.idea
+*.iml
+Dockerfile*
+node_modules
+build
+out
diff --git a/.github/workflows/ci-petclinic-eks.yaml b/.github/workflows/ci-petclinic-eks.yaml
index 0ad081fac..1bce6e212 100644
--- a/.github/workflows/ci-petclinic-eks.yaml
+++ b/.github/workflows/ci-petclinic-eks.yaml
@@ -29,7 +29,7 @@ jobs:
uses: actions/setup-java@v4
with:
distribution: temurin
- java-version: "25"
+ java-version: "21"
cache: maven
- name: Maven build & test
@@ -61,7 +61,7 @@ jobs:
uses: actions/setup-java@v4
with:
distribution: temurin
- java-version: "25"
+ java-version: "21"
cache: maven
- name: Configure AWS credentials (OIDC)
diff --git a/.github/workflows/ci-petclinic-gke.yaml b/.github/workflows/ci-petclinic-gke.yaml
index ce778a069..7fbf9c770 100644
--- a/.github/workflows/ci-petclinic-gke.yaml
+++ b/.github/workflows/ci-petclinic-gke.yaml
@@ -31,7 +31,7 @@ jobs:
uses: actions/setup-java@v4
with:
distribution: temurin
- java-version: "25"
+ java-version: "21"
cache: maven
- name: Maven build & test
@@ -63,7 +63,7 @@ jobs:
uses: actions/setup-java@v4
with:
distribution: temurin
- java-version: "25"
+ java-version: "21"
cache: maven
- name: Authenticate to Google Cloud (WIF)
diff --git a/Dockerfile b/Dockerfile
index 20954e271..3018290e0 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,9 +1,9 @@
# syntax=docker/dockerfile:1.6
ARG JAVA_VERSION=21
-ARG MAVEN_IMAGE=maven:3.9-eclipse-temurin-21
-ARG JDK_IMAGE=eclipse-temurin:21-jdk
-ARG DISTROLESS_IMAGE=gcr.io/distroless/base-debian12:nonroot
+ARG MAVEN_IMAGE=maven:3.9-eclipse-temurin-${JAVA_VERSION}
+ARG JDK_IMAGE=eclipse-temurin:${JAVA_VERSION}-jdk
+ARG RUNTIME_IMAGE=eclipse-temurin:${JAVA_VERSION}-jre
# =========================
# 1) Build
@@ -17,7 +17,7 @@ RUN --mount=type=cache,target=/root/.m2 \
COPY . .
RUN --mount=type=cache,target=/root/.m2 \
- mvn -q -DskipTests package
+ mvn -q -DskipTests clean package
RUN set -eux; \
JAR="$(ls -1 target/*.jar | head -n 1)"; \
@@ -37,7 +37,6 @@ RUN set -eux; \
mkdir -p /whatap; \
tar -xzf /tmp/whatap.agent.java.tar.gz -C /whatap; \
rm -f /tmp/whatap.agent.java.tar.gz; \
- # agent jar 찾기
AGENT_JAR="$(find /whatap -maxdepth 6 -type f \
\( -name 'whatap.agent*.jar' -o -name '*whatap*agent*.jar' \) | head -n 1)"; \
test -n "$AGENT_JAR"; \
@@ -46,48 +45,44 @@ RUN set -eux; \
chmod -R a=rX /whatap
# =========================
-# 3) jlink Slim JRE
+# 3) Runtime (fallback-first: temurin JRE)
# =========================
-FROM ${JDK_IMAGE} AS jre
-WORKDIR /jrebuild
-
-COPY --from=builder /app/app.jar ./app.jar
-
-RUN set -eux; \
- DEPS="$(jdeps --ignore-missing-deps --multi-release=21 --print-module-deps app.jar)"; \
- jlink --strip-debug --no-man-pages --no-header-files --compress=2 \
- --add-modules "$DEPS,\
-java.desktop,java.management,jdk.management,java.sql,java.naming,\
-java.logging,java.security.jgss,jdk.security.auth,java.security.sasl,java.instrument,\
-jdk.crypto.ec,jdk.unsupported,java.xml" \
- --output /opt/jre
-
-# =========================
-# 4) Runtime (Distroless)
-# =========================
-FROM ${DISTROLESS_IMAGE}
+# 기본 목표는 “정상 기동”이므로 디버깅이 용이한 eclipse-temurin JRE를 사용한다.
+# distroless/jlink 최적화는 별도 커밋에서 재적용한다.
+FROM ${RUNTIME_IMAGE}
WORKDIR /app
-COPY --from=jre /opt/jre /opt/jre
-COPY --from=builder /app/app.jar ./app.jar
+COPY --from=builder /app/app.jar /app/app.jar
+COPY --from=whatap_agent /whatap /whatap
-# ✅ 핵심: /whatap 을 nonroot(65532)가 소유하도록 복사
-COPY --from=whatap_agent --chown=65532:65532 /whatap /whatap
+ENV JAVA_TOOL_OPTIONS="" \
+ JAVA_OPTS="" \
+ENABLE_WHATAP=false \
+WHATAP_HOME=/whatap
-ENV JAVA_HOME=/opt/jre
-ENV PATH="/opt/jre/bin:${PATH}"
+# ENTRYPOINT wrapper: ENABLE_WHATAP=true 일 때만 agent 옵션을 추가한다.
+COPY <<'EOF' /entrypoint.sh
+#!/bin/sh
+set -eu
-# ✅ whatap home 명시(에이전트가 내부 파일 쓸 때 경로 확정)
-ENV WHATAP_HOME=/whatap
+JAVA_ARGS=${JAVA_OPTS:-}
+case "${ENABLE_WHATAP:-false}" in
+ true|TRUE|True)
+ JAVA_ARGS="$JAVA_ARGS -javaagent:/whatap/whatap.agent.jar"
+ JAVA_ARGS="$JAVA_ARGS -Dwhatap.paramkey=/whatap/paramkey.txt"
+ JAVA_ARGS="$JAVA_ARGS -Dwhatap.server.host=${WHATAP_SERVER_HOST:-}"
+ JAVA_ARGS="$JAVA_ARGS -Dlicense=${WHATAP_LICENSE:-}"
+ JAVA_ARGS="$JAVA_ARGS -Dwhatap.micro.enabled=${WHATAP_MICRO_ENABLED:-}"
+ JAVA_ARGS="$JAVA_ARGS --add-opens=java.base/java.lang=ALL-UNNAMED"
+ ;;
+esac
-ENV JAVA_TOOL_OPTIONS="\
--javaagent:/whatap/whatap.agent.jar \
--Dwhatap.paramkey=/whatap/paramkey.txt \
---add-opens=java.base/java.lang=ALL-UNNAMED \
--XX:+UseContainerSupport \
--XX:MaxRAMPercentage=75 \
--XX:+ExitOnOutOfMemoryError \
--XX:+AlwaysActAsServerClassMachine"
+exec java $JAVA_ARGS -XX:+UseContainerSupport -XX:MaxRAMPercentage=75 \
+ -XX:+ExitOnOutOfMemoryError -XX:+AlwaysActAsServerClassMachine \
+ -jar /app/app.jar
+EOF
+
+RUN chmod +x /entrypoint.sh
EXPOSE 8080
-ENTRYPOINT ["/opt/jre/bin/java", "-jar", "/app/app.jar"]
+ENTRYPOINT ["/entrypoint.sh"]
diff --git a/README.md b/README.md
index c2eec708c..603ab2261 100644
--- a/README.md
+++ b/README.md
@@ -110,3 +110,28 @@ CSP별 Ingress, Registry, Secret 차이로 매니페스트 분리
본 프로젝트는 멀티클라우드 환경에서 GitOps 기반 CI/CD와
운영 분리를 어떻게 설계할 수 있는지를 보여주는 예제입니다.
+
+---
+
+## 9. Spring Boot 3.x 다운그레이드 메모 (Boot 4.0.0-M3 → Boot 3.2.5)
+
+- 참고 문서: *Spring Boot 3 Migration Guide*, *Spring Boot 3.2 Release Notes*, *Spring Framework 6.x*.
+- Jakarta 네임스페이스 전환 이후 API 의존성은 Boot 3.x 기본 BOM을 따라가며, Boot 4 / Spring 7 전용 의존성은 제거/하향 조정했다.
+- Java 21 런타임을 유지하며, 모듈 경계 문제를 피하기 위해 `--add-opens=java.base/java.lang=ALL-UNNAMED` 옵션을 Whatap 활성화 시에만 주입한다.
+- distroless/jlink 최적화는 별도 커밋으로 재적용 예정이며, 현재는 디버깅 및 호환성을 우선한 `eclipse-temurin:21-jre` 런타임을 사용한다.
+
+### 잠재 호환 이슈 및 대응
+- 서드파티 라이브러리의 Spring 7 전용 API 사용 → Boot 3.x BOM 기준으로 의존성 하향. 필요 시 BOM에 맞는 버전으로 재빌드.
+- 에이전트/모듈 경계(`--add-opens`) 누락 시 JVM 시작 실패 가능 → Whatap 활성화 경로에서만 옵션을 주입하고, 기본 OFF 모드로 기동 보장.
+- 컨테이너 디버깅(쉘 유무) → distroless 대신 temurin JRE를 기본값으로 사용, 추후 최적화는 별도 PR로 진행.
+
+---
+
+## 10. WhaTap APM 토글 사용법
+
+- 기본값: OFF (`ENABLE_WHATAP=false`).
+- 활성화: 컨테이너/Deployment 환경 변수로 아래를 설정한다.
+ - `ENABLE_WHATAP=true`
+ - `WHATAP_LICENSE`, `WHATAP_SERVER_HOST`, `WHATAP_MICRO_ENABLED`
+- 이미지에 `/whatap/whatap.agent.jar`, `/whatap/paramkey.txt`가 포함되어 있으며, 활성화 시 엔트리포인트 래퍼가 자동으로 JVM 옵션을 주입한다.
+- 외부 Secret(ExternalSecret: `whatap-apm-secret`)은 라이선스/서버/마이크로 트레이싱 키만 제공하며, `paramkey.txt`는 이미지에 포함된 파일을 사용한다.
diff --git a/build.gradle b/build.gradle
index c0b4c0a6f..b3f4f3c3f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,7 +1,7 @@
plugins {
id 'java'
id 'checkstyle'
- id 'org.springframework.boot' version '4.0.0-M3'
+ id 'org.springframework.boot' version '3.2.5'
id 'io.spring.dependency-management' version '1.1.7'
id 'org.graalvm.buildtools.native' version '0.11.1'
id 'org.cyclonedx.bom' version '3.0.0'
@@ -13,11 +13,11 @@ plugins {
gradle.startParameter.excludedTaskNames += [ "checkFormatAot", "checkFormatAotTest" ]
group = 'org.springframework.samples'
-version = '4.0.0-SNAPSHOT'
+version = '3.2.5-SNAPSHOT'
java {
toolchain {
- languageVersion = JavaLanguageVersion.of(25)
+ languageVersion = JavaLanguageVersion.of(21)
}
}
@@ -77,7 +77,7 @@ checkstyleNohttp {
}
tasks.withType(JavaCompile).configureEach {
- options.release = 17
+ options.release = 21
options.errorprone {
disableAllChecks = true
}
diff --git a/k8s/aws/20-petclinic-Deployments-postgre.yaml b/k8s/aws/20-petclinic-Deployments-postgre.yaml
index 65931160e..2de3111ce 100644
--- a/k8s/aws/20-petclinic-Deployments-postgre.yaml
+++ b/k8s/aws/20-petclinic-Deployments-postgre.yaml
@@ -37,17 +37,15 @@ spec:
- name: SPRING_DATASOURCE_DRIVER_CLASS_NAME
value: "org.postgresql.Driver"
- name: APP_VERSION
- value: "A-4.0.0-49c6082"
+ value: "A-3.2.x"
- name: NODE_IP
valueFrom: {fieldRef: {fieldPath: status.hostIP}}
- name: NODE_NAME
valueFrom: {fieldRef: {fieldPath: spec.nodeName}}
- name: POD_NAME
valueFrom: {fieldRef: {fieldPath: metadata.name}}
- # ✅ Whatap + 기존 JVM 옵션 (덮어쓰기 주의 OK)
- - name: JAVA_TOOL_OPTIONS
- value: >-
- -javaagent:/whatap/whatap.agent.jar -Dwhatap.server.host=$(WHATAP_SERVER_HOST) -Dlicense=$(WHATAP_LICENSE) -Dwhatap.micro.enabled=$(WHATAP_MICRO_ENABLED) -Dwhatap.paramkey=/whatap/paramkey.txt -XX:+UseContainerSupport -XX:MaxRAMPercentage=75 -XX:+ExitOnOutOfMemoryError -XX:+AlwaysActAsServerClassMachine
+ - name: ENABLE_WHATAP
+ value: "false"
ports:
- name: http
containerPort: 8080
diff --git a/k8s/gcp/10-petclinic-secret-whatap.yaml b/k8s/gcp/10-petclinic-secret-whatap.yaml
new file mode 100644
index 000000000..ebf7a3d5f
--- /dev/null
+++ b/k8s/gcp/10-petclinic-secret-whatap.yaml
@@ -0,0 +1,26 @@
+apiVersion: external-secrets.io/v1
+kind: ExternalSecret
+metadata:
+ name: whatap-apm-secret
+ namespace: petclinic-ns
+spec:
+ refreshInterval: 1h
+ secretStoreRef:
+ name: gcp-secretmanager
+ kind: ClusterSecretStore
+ target:
+ name: whatap-apm-secret
+ creationPolicy: Owner
+ data:
+ - secretKey: WHATAP_LICENSE
+ remoteRef:
+ key: finalproj-dev-whatap-apm
+ property: license
+ - secretKey: WHATAP_SERVER_HOST
+ remoteRef:
+ key: finalproj-dev-whatap-apm
+ property: server_host
+ - secretKey: WHATAP_MICRO_ENABLED
+ remoteRef:
+ key: finalproj-dev-whatap-apm
+ property: micro_enabled
diff --git a/k8s/gcp/20-petclinic-Deployments-postgre.yaml b/k8s/gcp/20-petclinic-Deployments-postgre.yaml
index 25219c1c0..a345fee6a 100644
--- a/k8s/gcp/20-petclinic-Deployments-postgre.yaml
+++ b/k8s/gcp/20-petclinic-Deployments-postgre.yaml
@@ -35,6 +35,8 @@ spec:
envFrom:
- secretRef:
name: petclinic-db-secret
+ - secretRef:
+ name: whatap-apm-secret
# 🔹 여기: Spring profile을 postgres용으로
env:
@@ -48,7 +50,9 @@ spec:
- name: SPRING_JPA_HIBERNATE_DDL_AUTO
value: "none"
- name: APP_VERSION
- value: "local"
+ value: "A-3.2.x"
+ - name: ENABLE_WHATAP
+ value: "false"
ports:
- name: http
diff --git a/pom.xml b/pom.xml
index e3a2f692b..49c352197 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,13 +5,13 @@
org.springframework.boot
spring-boot-starter-parent
- 4.0.0-M3
+ 3.2.5
org.springframework.samples
spring-petclinic
- 4.0.0-SNAPSHOT
+ 3.2.5-SNAPSHOT
petclinic
@@ -72,11 +72,6 @@
spring-boot-starter-test
test
-
- org.springframework.boot
- spring-boot-starter-restclient
- test
-
@@ -316,6 +311,7 @@
org.cyclonedx
cyclonedx-maven-plugin
+ 2.9.1