시리즈 구성
- 1편: 개념과 동작 원리
- 2편: Spring Boot 실전 적용
- 3편: JDK 배포판 비교와 실무 선택 가이드 ← 현재 글
들어가며
앞선 두 편에서 CRaC의 개념과 Spring Boot 적용 방법을 살펴봤습니다. 이번 편에서는 실무에서 CRaC를 도입할 때 반드시 직면하는 질문을 다룹니다.
"CRaC JDK는 어디서 받아야 하나요?"
"Azul Zulu와 BellSoft Liberica 중 무엇을 써야 하나요?"
결론부터 말하면, 두 배포판의 차이는 단순한 브랜드 차이가 아닙니다. C/R 엔진 수준에서 근본적으로 다른 전략을 취하고 있으며, 이 차이가 Docker 배포 방식과 운영 환경 선택에 직접 영향을 미칩니다.
1. CRaC JDK 공급 구도
CRaC는 아직 OpenJDK 메인라인에 포함되지 않은 인큐베이터 프로젝트입니다. 따라서 CRaC를 사용하려면 이를 포함해서 빌드한 JDK 배포판을 별도로 선택해야 합니다.

CRaC 프로젝트 자체는 Azul Systems가 2021년 OpenJDK에 기여하며 시작했습니다. Azul이 CRaC 구현의 원조이며, 이후 독자적으로 Warp 엔진을 추가 개발했습니다.
Ubuntu apt 패키지: Ubuntu 24.10부터는 별도의 서드파티 JDK 없이 apt로 바로 설치할 수 있습니다. CRIU 기반이므로 Docker 권한 제약은 동일하게 적용되며, 서버에서 직접 실행하는 용도에 적합합니다.
sudo apt update && sudo apt install openjdk-21-crac-jdk-headless
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-crac-amd64
TCK 미검증 주의: CRaC 빌드는 현재 TCK(Technology Compatibility Kit) 검증을 받지 않습니다. Azul, BellSoft 모두 공식적으로 이를 명시합니다. 프로덕션 도입 전 충분한 검증이 필요합니다.
2. 핵심 차이: CRIU vs Warp 엔진
두 배포판의 가장 큰 차이는 C/R 엔진입니다.
BellSoft Liberica — CRIU 기반
BellSoft는 업스트림 OpenJDK CRaC의 CRIU 구현을 그대로 사용합니다.
CRIU는 외부 프로세스가 ptrace로 JVM 프로세스를 들여다보며 상태를 덤프하는 방식입니다. 이 구조 때문에 다음 두 권한이 반드시 필요합니다.
# Docker 컨테이너 실행 시 필수 플래그
docker run \
--cap-add CAP_CHECKPOINT_RESTORE \
--cap-add SYS_PTRACE \
bellsoft/liberica-runtime-container:jdk-21-crac-musl \
java -XX:CRaCCheckpointTo=/cr -jar app.jar
Docker 빌드 단계에서의 제약: Docker 이미지 빌드(docker build) 중에는 --cap-add 플래그를 줄 수 없습니다. 따라서 CRIU 기반으로는 멀티스테이지 Dockerfile 안에서 체크포인트를 생성하는 것이 불가능합니다. 체크포인트 생성과 컨테이너 이미지 빌드를 별도로 처리해야 합니다.
Azul Zulu — CRIU + Warp 엔진 모두 지원
Azul Zulu는 CRIU와 Warp 엔진을 모두 지원합니다. Warp는 2024년 10월 릴리스에서 추가됐으며, -XX:CRaCEngine=warp로 명시적으로 활성화합니다. 별도로 지정하지 않으면 기본값은 CRIU입니다.
Warp는 Azul이 자체 개발한 엔진으로, Linux 코어덤프 메커니즘에서 착안해 JVM이 자기 자신의 상태를 직접 저장합니다. 외부 프로세스가 개입하지 않으므로 추가 권한이 불필요합니다.
# Warp 엔진: Docker 빌드 단계에서 체크포인트 생성 가능 (권한 불필요)
# syntax=docker/dockerfile:1.7-labs
FROM azul/zulu-openjdk:21-jdk-crac AS checkpoint-builder
COPY app.jar /app.jar
# On-demand 방식: 웜업 트래픽 후 jcmd로 체크포인트
RUN <<END
#!/bin/bash
java -XX:CRaCEngine=warp \
-XX:CPUFeatures=generic \
-XX:CRaCCheckpointTo=/cr \
-jar /app.jar &
PID=$!
# 앱 기동 대기
until curl -sf http://localhost:8080/actuator/health > /dev/null 2>&1; do sleep 0.1; done
# 웜업 트래픽 발생 (JIT 최대 웜업)
# curl 루프 또는 ab, wrk 등 부하 도구 사용 가능
for i in $(seq 1 200); do curl -sf http://localhost:8080/ > /dev/null; done
# 체크포인트 생성
jcmd /app.jar JDK.checkpoint
wait $PID || true
END
FROM azul/zulu-openjdk:21-jre-crac
COPY --from=checkpoint-builder /cr /cr
CMD ["java", "-XX:CRaCEngine=warp", "-XX:CRaCRestoreFrom=/cr"]
또는 Automatic 방식(onRefresh)으로 더 단순하게 구성할 수도 있습니다.
RUN java -XX:CRaCEngine=warp \
-XX:CPUFeatures=generic \
-Dspring.context.checkpoint=onRefresh \
-XX:CRaCCheckpointTo=/cr \
-jar /app.jar || true
-XX:CPUFeatures=generic옵션은 빌드 환경과 다른 CPU 마이크로아키텍처를 가진 컨테이너에서도 복원할 수 있도록 합니다.
Warp 엔진의 추가 기능 (일부는 유료):
| 기능 | 구분 |
| LZ4 이미지 압축 | Azul 유료(SA) 빌드 Preview |
| Concurrent Memory Loading | Azul 유료(SA) 빌드 Preview |
| AWS S3 원격 체크포인트 저장 | Azul 유료(SA) 빌드 예정 |
| 이미지 암호화 | Azul 유료(SA) 빌드 예정 |
복원 시 PID/TID가 변경됩니다. PID에 직접 의존하는 코드가 있다면 Resource의 afterRestore에서 처리해야 합니다.
3. 상세 비교표
엔진·기능·지원 환경
| 항목 | Azul Zulu | BellSoft Liberica |
| 지원 엔진 | CRIU + Warp (선택 가능) | CRIU |
| Warp 활성화 방법 | -XX:CRaCEngine=warp 명시 필요 |
해당 없음 |
| root 권한 필요 여부 | Warp 사용 시 불필요 | 필요 |
| Docker 멀티스테이지 빌드 | Warp 사용 시 가능 | 불가 |
| Win/Mac 개발 지원 | simengine으로 콜백 테스트 가능 | 사실상 불가 |
| CRaC 지원 Java 버전 | 17, 21, 22 | 17, 21 |
| 지원 아키텍처 | x86_64, AArch64 | x86_64, AArch64 |
| 지원 OS | Linux (전체), Win/Mac (simengine) | Linux 전용 |
| CRaC 프로젝트 원조 | Azul이 시작 | 후발 구현 |
| TCK 검증 | 미검증 | 미검증 |
컨테이너 전략
| 항목 | Azul Zulu | BellSoft Liberica |
| 자체 OS | 없음 | Alpaquita Linux (Java 최적화) |
| 전용 베이스 이미지 | azul/zulu-openjdk:21-jdk-crac |
bellsoft/liberica-runtime-container:jdk-21-crac-musl |
| JRE + musl 최소 이미지 크기 | 72.43 MB | 45.37 MB |
| Docker 실행 시 추가 플래그 | Warp 사용 시 불필요 | --cap-add 2개 필요 |
이미지 크기는 JetBrains 블로그(2024년 4월 기준) Docker Hub 데이터 기준입니다. 시점에 따라 달라질 수 있습니다.
Spring Boot 통합 편의성
| 항목 | Azul Zulu | BellSoft Liberica |
| Spring Boot 공식 buildpack 기본 JDK | ❌ | ✅ |
| Paketo buildpack 기본값 | ❌ | ✅ |
| Spring 공식 문서 권장 | 언급됨 | 공식 권장 |
./gradlew bootBuildImage 한 줄로 생성되는 컨테이너 이미지는 자동으로 Liberica JDK 기반이 됩니다. Spring Boot 생태계 중심으로 작업한다면 Liberica가 마찰이 가장 적습니다.
4. 상황별 선택 가이드

5. 실무 적용 체크리스트
CRaC를 도입하기 전에 확인할 사항들입니다.
환경 확인
- Linux 환경인가? (CRIU/Warp 모두 실제 체크포인트는 Linux 전용)
- CRaC 지원 JDK로 교체 가능한가? (Java 17 또는 21)
- Docker 실행 환경에서
--cap-add플래그 추가 가능한가? (CRIU 사용 시) - CRaC 빌드 미검증(TCK 외) 상태를 팀·조직이 인지하고 있는가?
코드 확인
-
@Scheduled(fixedRate = ...)사용 여부 확인 → fixedDelay 또는 cron으로 변경 - Hikari 사용 시
allow-pool-suspension=true추가 - 체크포인트 시점에 민감 정보(DB 패스워드, API 키)가 JVM에 로드되어 있는지 확인
- Netty 등 사용 시
-Dio.netty.native.deleteLibAfterLoading=false필요 여부 확인
성능 검증
- 체크포인트 전 충분한 웜업 트래픽 발생 (on-demand 방식)
- 30~50회 반복 측정 후 P95 기준으로 비교
- 일반 기동과 CRaC 복원을 동일한 환경에서 측정
시리즈 마무리
3편에 걸쳐 CRaC를 다뤘습니다.
- 1편에서는 Cold Start 문제, CRaC의 핵심 아이디어, Resource API, C/R 엔진 3종, 타 기법과의 비교를 살펴봤습니다.
- 2편에서는 Spring Boot에서의 두 가지 체크포인트 모드, 기동 시간 측정 방법, 스케줄링·Hikari·보안 주의사항을 정리했습니다.
- 3편에서는 Azul Zulu와 BellSoft Liberica를 엔진 수준에서 비교하고, 상황별 선택 가이드를 제시했습니다.
CRaC는 아직 Java SE 표준에 포함되지 않은 기술이고 Linux 전용이라는 제약도 있습니다. 하지만 "빠른 기동"과 "JIT 최고 성능"을 동시에 달성할 수 있는 유일한 JVM 기반 접근법이라는 점에서, 컨테이너·서버리스 환경을 적극적으로 활용하는 팀이라면 주목할 만한 기술입니다.
참고 문서
'CS > JVM' 카테고리의 다른 글
| [JVM] CRaC 완전 정복 (2편) - Spring Boot 실전 적용 (1) | 2026.06.21 |
|---|---|
| [JVM] CRaC 완전 정복 (1편) - 개념과 동작 원리 (0) | 2026.06.21 |
| [JVM] Project Leyden과 AOT Cache - Java가 콜드 스타트 문제를 해결하는 방법 (0) | 2026.06.21 |
| [JVM] CDS와 AppCDS - JVM이 클래스 로딩을 캐싱하는 방법 (0) | 2026.06.20 |
| [JVM] invokevirtual과 invokeinterface — 바이트코드부터 vtable/itable까지 (1) | 2026.05.18 |