Skip to content

Conversation

@kgy1008
Copy link
Member

@kgy1008 kgy1008 commented Sep 21, 2025

📣 Jira Ticket

EDMT-454

👩‍💻 작업 내용

Docker 컨테이너 실행 시 JAVA_OPTS 환경 변수가 올바르게 전달되도록 엔트리포인트 설정을 개선했습니다.

주요 변경사항

  • Dockerfile 개선: Dockerfile-dev, Dockerfile-prod에서 shell 실행을 통한 JAVA_OPTS 변수 확장 지원
  • Docker Compose 설정 개선: docker-compose.dev.yml, docker-compose.prod.yml에 명시적인 엔트리포인트 설정 추가
  • 변수 이스케이프 처리: Docker Compose에서 $$JAVA_OPTS 형태로 적절한 변수 이스케이프 적용

기술적 개선사항

  • Java 애플리케이션 실행 시 런타임 옵션 설정 유연성 향상
  • 메모리, GC, JMX 등 다양한 JVM 옵션 동적 구성 가능
  • 블루-그린 배포 환경에서 일관된 설정 적용

📝 리뷰 요청 & 논의하고 싶은 내용

Docker 엔트리포인트에서 shell 실행 방식 변경이 보안이나 성능에 미치는 영향이 있는지 검토 부탁드립니다.

Test Plan

✅ Manual Testing Checklist

  • 로컬 개발 환경에서 JAVA_OPTS 설정 확인
  • Docker Compose dev 환경에서 컨테이너 정상 실행 확인
  • Docker Compose prod 환경에서 컨테이너 정상 실행 확인
  • JMX 포트 설정 및 메트릭 수집 정상 동작 확인
  • 블루-그린 배포 시나리오에서 설정 적용 확인

🧪 Automated Tests

  • Unit tests pass: ./gradlew test
  • Integration tests pass
  • Build succeeds: ./gradlew build
  • Docker image build 성공 확인

🔍 Code Quality

  • Docker 설정 파일 구문 검증
  • 환경 변수 이스케이프 처리 검토
  • 보안 고려사항 검토 (shell 실행)

Deployment Notes

  • 기존 배포된 컨테이너는 재시작 후 새로운 설정 적용
  • JAVA_OPTS 환경 변수가 설정되지 않은 경우에도 정상 동작
  • 개발/운영 환경 모두 동일한 방식으로 설정 적용

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • 컨테이너 실행 시 환경변수(JAVA_OPTS)로 JVM 옵션을 주입할 수 있도록 지원합니다.
    • 개발/운영의 블루-그린 서비스에 동일한 엔트리포인트 방식 적용으로 설정 일관성 제공.
  • Chores

    • 엔트리포인트를 셸 래퍼로 통일해 실행 구성을 유연화했습니다.
    • 기존 타임존(Asia/Seoul)과 프로필(dev/prod) 설정은 유지됩니다.
    • 인컨테이너 JMX 에이전트 및 관련 포트(9081/9082)·볼륨 매핑을 제거하여 런타임 설정을 단순화했습니다.

@coderabbitai
Copy link

coderabbitai bot commented Sep 21, 2025

Walkthrough

ENTRYPOINT를 직접 exec 형태의 Java 호출에서 셸 래퍼(sh -c)로 변경하여 런타임 JAVA_OPTS 확장을 허용하도록 수정했습니다. 개발·운영 컴포즈 서비스의 entrypoint가 추가되었고, JMX 관련 포트·볼륨·환경변수 및 jmx-config.yml의 Prometheus 규칙들이 제거되었습니다. 타임존과 Spring 프로필 설정은 유지됩니다.

Changes

Cohort / File(s) Summary
Dockerfiles (ENTRYPOINT → sh 래퍼)
Dockerfile-dev, Dockerfile-prod
ENTRYPOINT를 exec 형식에서 셸 래퍼로 변경: ["sh","-c","java $JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=<env> -jar /app.jar"] (<env>는 dev/prod).
Compose (entrypoint 추가 및 JMX 제거)
docker-compose.dev.yml, docker-compose.prod.yml
app-blue, app-greenentrypoint 오버라이드 추가(위 셸 명령). 기존 JAVA_OPTS env, JMX 관련 포트 매핑(9081/9082) 및 JMX 에이전트 관련 볼륨 마운트가 제거됨.
Monitoring config (규칙 삭제)
jmx-config.yml
Prometheus JMX 규칙 전체 삭제(톰캣 메트릭, JVM 메모리/GC/CPU/스레드 관련 규칙 일괄 제거).

Sequence Diagram(s)

sequenceDiagram
    autonumber
    actor Operator as Orchestrator/Compose
    participant C as Container
    participant SH as sh -c
    participant J as java (app.jar)

    Operator->>C: 컨테이너 시작
    C->>SH: ENTRYPOINT ["sh","-c","java $JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=<env> -jar /app.jar"]
    Note right of SH #f0f9ff: 런타임에서 `$JAVA_OPTS` 확장
    SH->>J: java $JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=<env> -jar /app.jar
    J-->>Operator: 프로세스 로그/상태
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

셸 속에 숨은 한 줌 옵션,
JAVA_OPTS 꺼내어 바람 불어넣네.
파랑 발·초록 발, 두 컨테이너 출동!
서울 시간 맞춰 프로필 켜고,
깡총! 런타임에 꽃핀 새벽의 배포 🐇🌙

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed 제목이 PR의 핵심 변경사항인 Docker 엔트리포인트에서 JAVA_OPTS 설정 개선을 명확하고 간결하게 요약하고 있어 동료가 변경 내용을 쉽게 이해할 수 있습니다.
Description Check ✅ Passed PR 설명은 Jira 티켓, 작업 내용, 리뷰 요청 섹션을 모두 포함하고 있으며 템플릿 구조를 충실히 따르고 있어 필요한 정보를 잘 전달하고 있습니다.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/EDMT-454

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


Comment @coderabbitai help to get the list of available commands and usage tips.

@kgy1008 kgy1008 self-assigned this Sep 21, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (1)
Dockerfile-dev (1)

4-4: Dockerfile-dev·Dockerfile-prod: ENTRYPOINT에 exec 추가 또는 셸 래퍼 제거 권장

  • 현상:

    ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=dev -jar /app.jar"]

    (prod 파일도 spring.profiles.active=prod로 동일)

  • 최소 변경(신호 전달·좀비 처리 개선, 쉘 인젝션 방어):

    - ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=dev -jar /app.jar"]
    + ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=dev -jar /app.jar"]

    ※ Dockerfile-prod 에도 동일하게 exec 추가 적용

  • 권장 대안(쉘 제거 + JAVA_TOOL_OPTIONS 활용):

    - ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=dev -jar /app.jar"]
    + ENTRYPOINT ["java", "-Duser.timezone=Asia/Seoul", "-Dspring.profiles.active=dev", "-jar", "/app.jar"]

    환경변수 주입은 기존 JAVA_OPTS 대신 JVM이 자동 인식하는 JAVA_TOOL_OPTIONS 사용

  • 추가 권장: 컨테이너 init 프로세스(tini 등) 도입으로 신호 전달·좀비 처리 보강

  • 검증:

    1. 컨테이너 실행 후 ps -o pid,ppid,comm -p 1 로 PID 1 프로세스 확인
    2. docker stop 시 애플리케이션이 그레이스풀 셧다운되는지 로그 점검
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 602390d and 7e61716.

📒 Files selected for processing (4)
  • Dockerfile-dev (1 hunks)
  • Dockerfile-prod (1 hunks)
  • docker-compose.dev.yml (2 hunks)
  • docker-compose.prod.yml (2 hunks)

- ./jmx-config.yml:/app/jmx-config.yml
networks:
- app-network
entrypoint: ["sh", "-c", "java $$JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=dev -jar /app.jar"]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

app-green도 동일 이슈 — 동일한 수정 적용 필요

아래와 같이 exec 추가 또는 JAVA_TOOL_OPTIONS 전환을 권장합니다.

-    entrypoint: ["sh", "-c", "java $$JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=dev -jar /app.jar"]
+    entrypoint: ["sh", "-c", "exec java $$JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=dev -jar /app.jar"]

app-green 서비스의 entrypoint 동일 여부 확인을 위해 아래 명령어 실행합니다.


🏁 Script executed:

#!/bin/bash
rg -n "entrypoint" -C3 docker-compose.dev.yml

Length of output: 520


app-green 서비스에도 exec 적용 필요
docker-compose.dev.yml의 44번째 줄 entrypoint를 아래와 같이 수정하세요:

-    entrypoint: ["sh", "-c", "java $$JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=dev -jar /app.jar"]
+    entrypoint: ["sh", "-c", "exec java $$JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=dev -jar /app.jar"]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
entrypoint: ["sh", "-c", "java $$JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=dev -jar /app.jar"]
entrypoint: ["sh", "-c", "exec java $$JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=dev -jar /app.jar"]
🤖 Prompt for AI Agents
In docker-compose.dev.yml around line 44, the app-green service entrypoint needs
to use exec so the Java process replaces the shell; update the entrypoint to run
the shell with exec before java (e.g., ["sh","-c","exec java $JAVA_OPTS
-Duser.timezone=Asia/Seoul -Dspring.profiles.active=dev -jar /app.jar"]) so
signals are forwarded correctly and the shell no longer becomes the main
process.

- ./jmx-config.yml:/app/jmx-config.yml
networks:
- app-network
entrypoint: ["sh", "-c", "java $$JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod -jar /app.jar"]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

❓ Verification inconclusive

prod app-green: 동일 수정 적용 필요

다음과 같이 exec 추가 또는 JAVA_TOOL_OPTIONS 전환을 적용해 주세요.

-    entrypoint: ["sh", "-c", "java $$JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod -jar /app.jar"]
+    entrypoint: ["sh", "-c", "exec java $$JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod -jar /app.jar"]

prod app-green: entrypoint에 exec 추가 필요

sh -c로 java를 실행하면 PID 1이 쉘이 되어 시그널 전달·종료 처리 문제가 발생할 수 있습니다. exec로 대체하세요.
파일: docker-compose.prod.yml (라인 44)

-    entrypoint: ["sh", "-c", "java $$JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod -jar /app.jar"]
+    entrypoint: ["sh", "-c", "exec java $$JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod -jar /app.jar"]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
entrypoint: ["sh", "-c", "java $$JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod -jar /app.jar"]
entrypoint: ["sh", "-c", "exec java $$JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod -jar /app.jar"]
🤖 Prompt for AI Agents
In docker-compose.prod.yml around line 44, the entrypoint currently runs java
via sh -c which leaves the shell as PID 1 and prevents proper signal
propagation; update the entrypoint to invoke exec within the sh -c command so
the java process replaces the shell (e.g., use sh -c "exec java ..."),
preserving the existing JVM options and environment variable escaping.

ARG JAR_FILE=build/libs/edukit-api.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java", "-Duser.timezone=Asia/Seoul", "-Dspring.profiles.active=prod", "-jar", "/app.jar"]
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod -jar /app.jar"]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

❓ Verification inconclusive

프로덕션 이미지에서의 sh -c는 보안/신호 전달 리스크 — exec 추가 또는 JAVA_TOOL_OPTIONS로 전환 필요

  • 프로덕션에서는 쉘 인젝션과 PID 1 문제의 영향이 더 큼.
  • 최소 변경:
-ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod -jar /app.jar"]
+ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod -jar /app.jar"]
  • 권장 대안:
-ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod -jar /app.jar"]
+ENTRYPOINT ["java", "-Duser.timezone=Asia/Seoul", "-Dspring.profiles.active=prod", "-jar", "/app.jar"]
  • 운영 환경에서는 JAVA_TOOL_OPTIONS로 옵션을 주입해 쉘을 제거하는 구성을 권장합니다.

프로덕션 Dockerfile: ENTRYPOINT에서 sh -c 제거 — 신호 전달·쉘 인젝션 위험 (긴급 수정 필요)

sh -c 사용 시 PID 1로서 SIGTERM/SIGINT 등이 자식 JVM으로 직접 전달되지 않으며, $JAVA_OPTS 같은 환경변수 확장으로 쉘 인젝션 위험이 있음.

최소 변경(신호 전달 보장):

-ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod -jar /app.jar"]
+ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod -jar /app.jar"]

권장(쉘 제거 — 안전·명시적 인수 전달):

-ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod -jar /app.jar"]
+ENTRYPOINT ["java", "-Duser.timezone=Asia/Seoul", "-Dspring.profiles.active=prod", "-jar", "/app.jar"]

운영 권장: 옵션은 JAVA_TOOL_OPTIONS로 주입하여 쉘을 제거한 exec 형식으로 실행. 파일: Dockerfile-prod (라인 4)

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod -jar /app.jar"]
ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod -jar /app.jar"]
Suggested change
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod -jar /app.jar"]
ENTRYPOINT ["java", "-Duser.timezone=Asia/Seoul", "-Dspring.profiles.active=prod", "-jar", "/app.jar"]
🤖 Prompt for AI Agents
Dockerfile-prod around line 4: the current ENTRYPOINT uses sh -c which breaks
signal forwarding and allows shell-injection via $JAVA_OPTS; change to an
exec-form ENTRYPOINT that invokes the JVM directly (no sh -c) and stop expanding
untrusted vars in the shell — pass JVM options via the standard
JAVA_TOOL_OPTIONS environment variable or as explicit JSON-array arguments so
signals (SIGTERM/SIGINT) are forwarded to the JVM and no shell interpolation
occurs; minimally replace the shell form with an exec-form ENTRYPOINT that calls
java with the timezone, profile and -jar arguments, and optionally set or
document use of JAVA_TOOL_OPTIONS for additional options.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7e61716 and 3a7115c.

📒 Files selected for processing (3)
  • docker-compose.dev.yml (2 hunks)
  • docker-compose.prod.yml (2 hunks)
  • jmx-config.yml (0 hunks)
💤 Files with no reviewable changes (1)
  • jmx-config.yml

- ./jmx-config.yml:/app/jmx-config.yml
networks:
- app-network
entrypoint: ["sh", "-c", "java $$JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=dev -jar /app.jar"]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

dev 환경도 동일하게 exec 적용 필요

dev compose 역시 sh -c로 인해 PID 1/signal 문제와 JAVA_OPTS 해석 문제가 동일하게 발생합니다. prod와 동일한 방식으로 exec를 추가해 주세요.

-    entrypoint: ["sh", "-c", "java $$JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=dev -jar /app.jar"]
+    entrypoint: ["sh", "-c", "exec java $$JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=dev -jar /app.jar"]

Also applies to: 36-36

🤖 Prompt for AI Agents
In docker-compose.dev.yml around lines 18 and 36, the entrypoint currently uses
sh -c which causes PID 1/signal forwarding and JAVA_OPTS expansion issues;
update both entrypoint definitions to use exec so the JVM runs as PID 1 and
signals are forwarded and environment expansion works — change the command
string to include exec before java (e.g., keep the existing shell wrapper but
use "sh", "-c", "exec java $$JAVA_OPTS -Duser.timezone=Asia/Seoul
-Dspring.profiles.active=dev -jar /app.jar" or the equivalent for the other
occurrence) so the shell replaces itself with the java process.

- ./jmx-config.yml:/app/jmx-config.yml
networks:
- app-network
entrypoint: ["sh", "-c", "java $$JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod -jar /app.jar"]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

쉘 entrypoint로 인한 신호 전달 및 명령 인젝션 위험 수정 필요

현재 sh -c "java $$JAVA_OPTS …" 형태는 셸이 PID 1로 남아 SIGTERM 등이 JVM까지 전달되지 않을 수 있고, $$JAVA_OPTS가 셸에서 그대로 해석되어 명령 인젝션 위험도 존재합니다. 최소한 exec를 추가해 셸이 자신을 Java 프로세스로 교체하도록 해 주세요.

-    entrypoint: ["sh", "-c", "java $$JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod -jar /app.jar"]
+    entrypoint: ["sh", "-c", "exec java $$JAVA_OPTS -Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod -jar /app.jar"]

Also applies to: 36-36

🤖 Prompt for AI Agents
In docker-compose.prod.yml around lines 18 and 36, the entrypoint uses a shell
form that leaves a shell as PID 1 and uses an unsafe variable expansion
(\"$$JAVA_OPTS\") which risks broken signal propagation and command injection;
update the entrypoints to run the Java process as PID 1 by prepending exec and
stop using the literal $$ expansion — use a shell invocation that calls exec and
a properly quoted environment variable (e.g., sh -c 'exec java "$JAVA_OPTS"
-Duser.timezone=Asia/Seoul -Dspring.profiles.active=prod -jar /app.jar') or,
preferably, move options into explicit args so the Java binary is launched
directly without an intermediate shell.

@kgy1008 kgy1008 merged commit fb9341f into develop Sep 25, 2025
2 checks passed
@kgy1008 kgy1008 deleted the fix/EDMT-454 branch September 25, 2025 04:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants