10 KiB
10 KiB
title, source_type, status, confidence, tags, related_projects, last_reviewed
| title | source_type | status | confidence | tags | related_projects | last_reviewed | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Runtime / Container / Health / Migration Baseline | llm-generated | draft | medium |
|
|
2026-05-22 |
Runtime / Container / Health / Migration Baseline
Layer:
wiki/concepts/— JVM 서비스의 container runtime · runtime health · migration startup 세 sub-topic을 한 문서로 통합한 baseline. 내 프로젝트 사실은project-template사용.
Summary
JVM 서비스의 runtime baseline은 세 축으로 구성된다.
- Container: Eclipse Temurin (Adoptium) JRE slim + JVM ergonomics (
-XX:MaxRAMPercentage=75,-XX:+UseContainerSupport). - Health: Kubernetes Probes (liveness/readiness/startup)를 세 endpoint로 분리 + Spring Boot Actuator Health Groups로 dependency 범위를 명시.
- Migration: Flyway forward-only migration을 readiness gated로 실행 + 표준 startup exit code (sysexits 계열 78/70/71/72).
세 축은 graceful shutdown 35s budget (app 20s + preStop 5s + grace 10s margin)으로 묶인다.
Standard (공식 정의)
Container
- Eclipse Temurin (Adoptium) — JEP/JCK 인증 OpenJDK 빌드. JRE slim 이미지는 JDK 대비 footprint 작고 production runtime에 권장.
- OCI Image spec — base image, layer, label 표준. Dockerfile은 OCI 호환 image를 산출.
- JVM container ergonomics:
-XX:+UseContainerSupport— JDK 10+ default. cgroup memory/cpu limit을 JVM이 인식.-XX:MaxRAMPercentage=<N>— container memory limit의 N%를 max heap으로 사용. 절대값-Xmx보다 container 환경에서 안전.-XX:+ExitOnOutOfMemoryError— JVMOutOfMemoryError발생 시 즉시 process exit (137).-XX:HeapDumpPath=...— OOM 진단용 heap dump.
Health
- Kubernetes Probes (kubelet 공식 모델):
- liveness — process가 살아있는가. 실패 시 container restart.
- readiness — traffic을 받을 수 있는가. 실패 시 Service endpoint 제거 (drain).
- startup — startup이 끝났는가. startup probe가 success할 때까지 liveness/readiness 비활성. 긴 migration/warmup 시 liveness 오판 방지.
- probe 분리는 K8s 공식 권장. single
/health로 묶지 않는다.
- Spring Boot Actuator Health Groups —
management.endpoint.health.group.liveness.include,.readiness.include로 endpoint별 HealthIndicator set을 분리.- Spring default readiness는 외부 dependency 미포함이므로 DB/broker 등 required dependency는 명시적 group 등록 필요.
Migration
- Flyway 공식:
- forward-only versioned migration이 기본 model.
flyway.repair— checksum/state 수정 도구. prod 사용은 공식이 직접 위험성 경고 (실제 schema 변경 없이 metadata만 수정).flyway.baselineOnMigrate— 기존 DB에 처음 Flyway 적용 시. 잘못 켜면 누락 migration이 skip된 채 baseline.flyway.outOfOrder— version 순서 외 migration 허용. 협업 환경에서 일관성 깨짐.
- sysexits.h (BSD
sysexits.h, 1990s) — Unix 관례적 exit code 의미.64— usage error70— internal software error71— OS error72— critical OS file missing78— config error- 표준이 강제하는 enum은 아니지만 ops/CI 진단에 관례적으로 사용.
한계 / 주의점
Container 선택 트레이드오프
- Temurin JRE slim (base):
- 운영/디버깅 친숙도 우위 (shell, JDK tools 가용).
- security surface는 distroless보다 크다 (apt, libc 등 OS 패키지 포함).
- Distroless (Google):
- OS 패키지 제거 → 보안 surface 축소 + image 크기 감소.
- shell·debug tool 없음 → in-container 디버깅 손실. 별도 sidecar/ephemeral container 필요.
- Alpine + musl libc:
- image 크기 작음.
- musl libc는 glibc 호환성 risk (DNS resolver 차이, native lib 미지원 등). Java 일부 native lib는 alpine에서 동작 미보장.
- GraalVM Native Image / Spring Boot Native:
- cold start/메모리 우위 (수십 MB heap, ms 단위 startup).
- reflection·dynamic proxy는 build-time metadata 필요. peak throughput은 HotSpot JIT보다 손실.
- Spring Boot Native는 Spring 6+ + Spring Boot 3+ AOT compile 의존.
- 우아한형제들 도입기는 전체 native 전환이 아닌 hybrid 채택 결론.
Health 분리의 한계
- Single
/healthendpoint (legacy):- liveness/readiness 구분 불가.
- K8s rolling update 시 dependency 일시 outage가 container restart loop 유발 가능. traffic 유실 risk.
- Custom HealthIndicator만 사용:
- Spring default readiness는 외부 dependency 미포함. DB/broker 등은 명시적으로 readiness group에 묶지 않으면 readiness가 traffic 가능 여부를 반영하지 않음.
- Service mesh-based health (Istio sidecar):
- mTLS 환경에서 편의성. 단 sidecar 살아있음 / app 살아있음 구분이 mesh layer에서 불명확.
- 추가 infra 의존 (sidecar 주입, mesh control plane).
Migration tool 트레이드오프
- Liquibase (XML/YAML changelog):
- DB-agnostic + rollback 기능.
- XML/YAML 기반은 SQL 대비 verbose. migration speed Flyway 대비 느림 (changelog parser 오버헤드).
- rollback 안전 보장 없음 (rollback script 사람이 작성).
- Hibernate
hbm2ddl=update등:- 공식 anti-pattern. prod 사용 금지가 일반 권고. schema drift 추적 불가.
- Atlas / Tern (schema-as-code):
- declarative + integrity hash 강점.
- Java/Spring 생태계 성숙도 부족. JVM 외부 CLI tool.
- K8s Init Container 패턴:
- replica마다 init container 실행 → multi-instance migration race.
- K8s Job + migration lock이 race 회피에 구조적 우월.
- Flyway 자체 한계:
repair/baselineOnMigrate/outOfOrder는 잘못 쓰면 schema state corruption. 공식이 직접 위험 경고.- forward-only 모델이라 rollback은 별도 forward migration으로 처리.
Exit code 한계
- sysexits.h는 관례. POSIX 강제 표준 아님. 조직 표준으로 명시적 enum 필요.
Project Application
- wiki/projects/ca-tmpl/runtime-container-health-migration — ca-tmpl 의사결정 기록 (현재
documented-only, Phase C2 미진입). 실제 구현 여부는 project 문서 참조. - raw/branch-notes/feature-container-runtime-contract — container runtime 결정 (Temurin JRE slim,
MaxRAMPercentage=75, UTC/UTF-8, graceful shutdown 35s). - raw/branch-notes/feature-runtime-health-lifecycle-contract — liveness/readiness/startup 3-endpoint 분리, Required vs Optional Dependency Matrix.
- raw/branch-notes/feature-migration-startup-contract — Flyway baseline + readiness gated + exit code 78/70/71/72.
- raw/project-notes/ca-skeleton-operational-contract (§15 Runtime / Lifecycle Contract).
Interview Questions
- JRE slim과 distroless 중 어떤 base image를 선택하고, 그 근거는 무엇인가?
-XX:MaxRAMPercentage=75로 설정한 이유는 무엇이고, 절대값-Xmx와 어떤 차이가 있는가?- liveness / readiness / startup 세 probe를 분리하는 이유는 무엇인가? single
/health로 묶으면 어떤 운영 문제가 생기는가? - graceful shutdown을 app 20s + preStop 5s + terminationGracePeriodSeconds 35s로 잡았다면 각 단계가 어떤 의미를 가지는가?
- Flyway
repair가 prod에서 위험하다고 보는 근거는? 어떤 대안 경로가 있는가? - startup exit code 78 / 70 / 71 / 72로 분리하면 어떤 진단상 이점이 생기는가? (config error / internal error / OS error / critical OS file missing)
Do Not Overclaim
- "GraalVM native-image가 곧 standard"라고 단정하지 말 것. reflection-heavy 코드와 peak throughput 손실은 실측 trade-off. 우아한형제들 사례도 hybrid 채택.
- "Flyway가 항상 우월"이라고 단정하지 말 것. 조직이 XML/YAML 기반 schema-as-doc을 요구하거나 DB-agnostic이 강제일 때는 Liquibase가 합리.
- "distroless가 보안상 무조건 정답"이라고 단정하지 말 것. in-container 디버깅 손실은 incident 대응 시간을 늘릴 수 있다.
- "K8s probe만 있으면 graceful shutdown은 자동"이라고 말하지 말 것. app shutdown timeout과 manifest grace period가 sync되지 않으면 SIGKILL로 inflight 요청 유실.
- "exit code 70/78은 표준"이라고 말하지 말 것. sysexits.h는 관례이고 조직 enum 명시가 필요.
Sources
- Eclipse Temurin / Adoptium project — 공식 OpenJDK 배포.
- Kubernetes — Configure Liveness, Readiness and Startup Probes (공식)
- Spring Boot Actuator — Health (공식)
- Flyway — Concepts / Repair (공식) — repair / baseline_on_migrate / out_of_order 위험성 경고 명시.
- sysexits.h — BSD man page — 64/70/71/72/78 등 관례적 exit code.
- raw/official-docs/container-distroless-google-github — Distroless 보안 surface vs 디버깅 손실.
- raw/official-docs/container-alpine-java-musl-tradeoffs — Alpine + musl libc 호환성 risk.
- raw/official-docs/container-graalvm-native-image-spring-boot — GraalVM native-image / Spring Boot Native AOT 비용·이득.
- raw/company-tech-blogs/container-woowahan-spring-native-tradeoffs — 우아한형제들 Spring Native 도입기 (hybrid 채택).
- raw/official-docs/runtime-health-k8s-probes-official — K8s liveness/readiness/startup 공식.
- raw/official-docs/runtime-health-spring-actuator-groups — Spring Boot Actuator Health Groups.
- raw/official-docs/runtime-health-istio-mesh-health-check — Istio mesh health 대안과 한계.
- raw/company-tech-blogs/runtime-health-datadog-engineering-graceful-shutdown — Datadog graceful shutdown preStop/drain/grace 비율 사례.
- raw/official-docs/migration-flyway-official-concepts-and-repair — Flyway 공식 repair/baseline_on_migrate/out_of_order 위험성.
- raw/official-docs/migration-liquibase-official-changelog-xml-yaml — Liquibase XML/YAML changelog.
- raw/official-docs/migration-atlas-schema-as-code — Atlas schema-as-code 대안.
- raw/official-docs/migration-k8s-init-container-job-pattern — K8s Init Container vs Job 패턴 비교.
- raw/project-notes/ca-skeleton-operational-contract — §15 Runtime / Lifecycle Contract.