12 KiB
title, source_type, status, confidence, tags, related_projects, last_reviewed
| title | source_type | status | confidence | tags | related_projects | last_reviewed | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ca-tmpl - Runtime / Container / Health / Migration 결정 | project | verified | high |
|
|
2026-07-02 |
ca-tmpl - Runtime / Container / Health / Migration 결정
Layer:
wiki/projects/— 내 프로젝트 사실. 일반 개념은 wiki/concepts/runtime-container-health-migration 참조.
프로젝트 컨텍스트
ca-tmpl은 Clean Architecture 기반 백엔드 skeleton 프로젝트다. 운영 계약(operational contract) 단계에서 JVM 서비스의 runtime baseline을 세 축으로 묶어 단일 운영 계약으로 통합하는 결정을 했다.
- Container: Eclipse Temurin (Adoptium) JRE slim + JVM ergonomics (
-XX:MaxRAMPercentage=75,-XX:+UseContainerSupport,-XX:+ExitOnOutOfMemoryError) + UTC / UTF-8 locale 고정. - Health: Kubernetes Probes 3종 (liveness / readiness / startup) 분리 + Spring Boot Actuator Health Groups + Required / Optional Dependency Matrix.
- Migration: Flyway forward-only migration을 readiness-gated로 실행 +
repair/baselineOnMigrate/outOfOrder모두 prod forbidden + 표준 startup exit code 78 / 70 / 71 / 72 매핑. - Graceful shutdown budget: app 20s + preStop 5s + terminationGracePeriodSeconds 35s (10s margin).
현재 진행 상태:
- C2 구현 + 로컬 검증 완료 —
src/Dockerfile, runtime safety/startup validators, Actuator health group contract, Flyway prod safety guard, startup exit-code mapping, graceful shutdown settings가 코드화되어 있다. 2026-07-02./gradlew check통과로 로컬 검증했다. Kubernetes manifest와 운영 rolling update 실측은 없다.
문서/설계 산출물만 존재하며, 코드/검증/측정은 전무하다.
실제 구현 내용 (actually-implemented)
src/Dockerfile과 runtime settings가 존재한다.app-bootstrap의RuntimeSafetyConfig,RuntimeSafetySettings,RuntimeNumericBoundsValidator,OpenInViewSafetyValidator,HikariPoolConstraintValidator가 startup/runtime guard를 구성한다.MigrationStartupConfig,MigrationStartupRunner,FlywayProdSafetyValidator,StartupFailureException,StartupErrorCode가 migration readiness-gate와 exit code mapping을 구성한다.adapter-web의HealthcheckController와app-bootstraphealth group contract가 liveness/readiness/startup 구분을 검증한다.
로컬/dev 검증 (locally-verified)
./gradlew check통과(2026-07-02,BUILD SUCCESSFUL, 114 tasks).RuntimeHealthLifecycleContractTest가 liveness/readiness/startup group membership과 readiness-vs-liveness 분리를 검증한다.FlywayProdSafetyValidatorTest,MigrationStartupRunnerTest,RequiredEnvironmentValidatorTest,StartupErrorCodeTest,StartupFailureExceptionTest가 migration/startup failure contract와 exit code를 검증한다.ContainerRuntimeOomContractTest,OperationalContractRuntimeTest,RuntimeNumericBoundsValidatorTest,OpenInViewSafetyValidatorTest,HikariPoolConstraintValidatorTest가 runtime/container/startup guard를 검증한다.
운영 검증 (prod-verified)
없음. 운영 환경 검증 없음. K8s rolling update 동작, graceful shutdown 실측, cold start latency, migration 실패 복구 모두 없음.
문서/계획만 존재 (documented-only / planned)
운영 계약 문서(canonical §15 Runtime / Lifecycle Contract, §29 G-D)와 3 branch-note에 다음이 설계 수준으로만 기록되어 있다.
Container (actually-implemented / locally-verified)
- Base image: Eclipse Temurin JRE slim 채택 (distroless / alpine+musl / GraalVM native 대안 모두 검토 후 보류).
- JVM ergonomics:
-XX:+UseContainerSupport(JDK 10+ default 명시) +-XX:MaxRAMPercentage=75+-XX:+ExitOnOutOfMemoryError+-XX:HeapDumpPath. - Locale: UTC / UTF-8 고정 (env
TZ=UTC,LANG=C.UTF-8). - 대안 검토: distroless (보안 surface 축소 vs 디버깅 손실), alpine+musl (image 크기 vs glibc 호환성 risk), GraalVM native-image (cold start vs reflection/peak throughput 손실, hybrid 사례) — branch-note
feature-container-runtime-contract.
Health (actually-implemented / locally-verified)
- K8s Probes 3 endpoint 분리:
/livez,/readyz,/startupz(or Actuator/actuator/health/{liveness,readiness}+ startup variant). - Spring Boot Actuator Health Groups로 endpoint별 HealthIndicator set 분리.
- Required / Optional Dependency Matrix — DB·broker는 readiness 필수, 외부 cache는 optional 등 dependency 범위 명시.
- 대안 검토: single
/health(legacy, restart loop risk), custom HealthIndicator only (default readiness 외부 dependency 미포함), Istio mesh-based health (sidecar/app 구분 모호) — branch-notefeature-runtime-health-lifecycle-contract.
Migration (actually-implemented / locally-verified)
- Flyway forward-only + readiness-gated: migration 완료 전 readiness probe
false. - prod forbidden:
flyway.repair,flyway.baselineOnMigrate,flyway.outOfOrder모두 prod에서 사용 금지. - 표준 startup exit code 매핑 (sysexits.h 관례):
78— config error (env / property 누락·잘못된 값)70— internal software error (예상 외 application failure)71— OS error (system call / resource 실패)72— critical OS file missing
- 대안 검토: Liquibase (DB-agnostic + rollback, XML/YAML verbose), Hibernate
hbm2ddl=update(anti-pattern), Atlas (declarative, JVM 외부), K8s Init Container (replica race) vs Job + migration lock — branch-notefeature-migration-startup-contract.
Graceful Shutdown (partially-implemented)
- App SIGTERM 수신 후 in-flight 처리 20s + preStop hook 5s drain + K8s terminationGracePeriodSeconds 35s (10s margin).
- Spring Boot
server.shutdown=graceful+spring.lifecycle.timeout-per-shutdown-phase설정 예정.
Kubernetes manifest와 실제 rolling update/drain 실측은 아직 없다. 따라서 local/runtime guard와 운영 가정의 경계를 분리해서 말해야 한다.
면접에서 말할 수 있는 범위
자신 있게 답할 수 있는 (개념·설계 의도)
- JRE slim vs distroless 선택 근거 — 운영/디버깅 친숙도 vs 보안 surface trade-off.
- liveness / readiness / startup 3 probe 분리 이유 — single
/health로 묶으면 dependency 일시 outage가 container restart loop를 유발하고, startup 단계 liveness 오판이 긴 migration/warmup을 죽일 수 있다. - Graceful shutdown 단계 — SIGTERM → app drain 20s → preStop 5s → grace 35s. 각 timeout이 sync되지 않으면 SIGKILL로 inflight 요청 유실.
- Flyway
repair가 prod에서 위험한 이유 — 실제 schema 변경 없이 metadata만 수정. 공식이 직접 위험성 경고.baselineOnMigrate는 누락 migration skip,outOfOrder는 협업 일관성 깨짐. - Exit code 78/70/71/72 의미 — sysexits.h 관례. config error / internal / OS / critical OS file missing 진단 분리.
적당히 답할 수 있는
- GraalVM native-image trade-off — cold start/메모리 우위 vs reflection·dynamic proxy build-time metadata 비용, peak throughput 손실. 우아한형제들도 hybrid 채택.
-XX:MaxRAMPercentage=75vs 절대값-Xmx— container memory limit 변경에 따라가는 비율 방식이 안전한 이유.
답하면 안 되는 (실측·운영 경험 없음)
- "K8s rolling update를 운영하면서…" — 운영 경험 없음.
- "cold start latency를 측정해보니…" — 측정 없음.
- "DB migration이 prod에서 실패해서 복구한 경험" — 없음.
- "liveness probe 오판으로 restart loop가 발생했을 때…" — 운영 incident 없음.
- "graceful shutdown 35s budget이 실제로 충분했다" — 실측 없음.
과장 금지 지점
- "GraalVM native-image가 곧 표준" → ❌. reflection-heavy 코드와 peak throughput 손실은 실측 trade-off. ca-tmpl은 채택하지 않았고 hybrid 사례만 참조했다.
- "K8s probe 동작을 운영에서 확인했다" → ❌. health group contract는 로컬 테스트로 검증했지만 Kubernetes manifest/cluster 검증은 없다.
- "Flyway readiness-gated migration이 운영에서 동작한다" → ❌. startup guard와 prod forbidden option은 로컬 테스트로 검증했지만 prod migration 복구 경험은 없다.
- "graceful shutdown 35s가 충분히 검증되었다" → ❌. graceful shutdown 설정은 존재하지만 운영 drain 실측은 없다.
- "distroless가 보안상 우월하다고 채택했다" → ❌. ca-tmpl은 JRE slim 채택. distroless는 대안으로 검토만 했고 디버깅 손실을 이유로 보류.
- "exit code 78/70/71/72가 표준이다" → ❌. sysexits.h는 BSD 관례. POSIX 강제 표준 아님. 조직 enum 명시가 필요.
Blog-topic ingest: runtime 묶음 (2026-07-02)
raw/blog-topics/jvm-oom-vs-container-oomkill-exit-137-2026-07-02 는 JVM OOM과 container OOMKill이 비슷한 종료 신호로 보일 때 heap dump/native stderr/runtime signal을 어떻게 구분할지 정리하기 위한 raw seed다.
- canonical 반영 범위: container/JVM runtime failure 해석을 runtime/container 결정 문서의 blog-topic 후보로 연결했다.
- blogify 전 조건: 충족. 이 문서는 2026-07-02 기준 코드와
./gradlew check로 검증됨. - 블로그 전 과장 방지: Kubernetes 운영 장애 대응 경험처럼 쓰지 않고, local/container evidence와 운영 가정을 분리한다.
- raw/blog-topics/spring-actuator-health-probe-group-split-2026-07-02: Spring Actuator health group을 liveness/readiness/startup으로 분리하고 startup guard/shutdown lifecycle을 같은 운영 계약으로 보는 글감. Kubernetes end-to-end readiness 보장처럼 쓰지 않는다.
- raw/blog-topics/java21-context-propagation-strategy-virtual-threads-2026-07-02: Java 21에서 request/security/tenant context를 ThreadLocal, Micrometer Context Propagation, ScopedValue 중 어디까지 다룰지 선택 기준을 정리하는 글감. ScopedValue 채택 경험처럼 쓰지 않고 후보/기준으로 제한한다.
- raw/blog-topics/spring-boot-startup-exit-code-propagation-2026-06-10: startup failure exit code를
ExitCodeGenerator/Spring Boot uncaught exception path와 sysexits 관례로 분리해 설명하는 글감. POSIX 표준처럼 쓰지 않고, ca-tmpl 내부 convention과 local 검증 경계를 구분한다. - raw/blog-topics/spring-async-taskdecorator-bounded-executor-saturation-shutdown-2026-06-13: executor await timeout과 app shutdown / Kubernetes grace period의 계층 부등식을 다루는 글감. executor sizing 숫자를 측정값으로 쓰지 않는다.
관련 개념
Sources
- raw/project-notes/ca-skeleton-operational-contract — ca-tmpl 운영 계약 SSOT (§15 Runtime / Lifecycle Contract, §29 G-D).
- raw/branch-notes/feature-container-runtime-contract — Temurin JRE slim + JVM ergonomics + UTC/UTF-8 계약.
- raw/blog-topics/jvm-oom-vs-container-oomkill-exit-137-2026-07-02 — JVM OOM vs container OOMKill 블로그 글감 raw seed. canonical 반영 범위: runtime/container failure interpretation + 과장 금지 항목.
- raw/branch-notes/feature-runtime-health-lifecycle-contract — liveness/readiness/startup 3-endpoint 분리 + Required/Optional Dependency Matrix.
- raw/blog-topics/spring-actuator-health-probe-group-split-2026-07-02 — Actuator health probe group split 블로그 글감 raw seed.
- raw/branch-notes/feature-runtime-context-propagation-contract — Java 21 context propagation 선택 기준 parent branch.
- raw/blog-topics/java21-context-propagation-strategy-virtual-threads-2026-07-02 — Java 21 context propagation strategy 블로그 글감 raw seed.
- raw/branch-notes/feature-migration-startup-contract — Flyway readiness-gated + prod forbidden 옵션 + exit code 78/70/71/72 매핑.
- raw/blog-topics/spring-boot-startup-exit-code-propagation-2026-06-10 — startup exit code propagation 블로그 글감 raw seed.
- raw/blog-topics/spring-async-taskdecorator-bounded-executor-saturation-shutdown-2026-06-13 — async executor shutdown budget 블로그 글감 raw seed.