Java를 공부하거나 Docker 이미지를 선택하다 보면 다음과 같은 이름을 만나게 된다.
Java
Java SE
JVM
JRE
JDK
OpenJDK
Eclipse Temurin
Amazon Corretto
Oracle JDK
이름은 많지만 모두 서로 다른 프로그래밍 언어를 의미하는 것은 아니다.
결론부터 말하면 다음과 같다.
Java라는 공통 표준과 OpenJDK라는 오픈소스 구현을 바탕으로 여러 회사와 재단이 각자의 Java 배포판을 만들어 제공한다.
자동차에 비유하면 이해하기 쉽다.
Java SE = 자동차가 따라야 하는 표준 규격
OpenJDK = 공개된 설계도와 원본 소스코드
Temurin = Eclipse 재단 계열에서 생산한 완제품
Corretto = Amazon에서 생산한 완제품
Oracle JDK = Oracle에서 생산한 완제품
Temurin, Corretto, Oracle JDK는 서로 다른 언어가 아니다.
같은 Java 표준을 구현한 서로 다른 배포 제품이다.
Java SE는 Java Platform, Standard Edition의 약자다.
Java 언어와 실행 환경이 지켜야 할 표준을 정의한다.
Java SE에는 다음과 같은 내용이 포함된다.
Java 21이라고 표현할 때는 Java SE 21 규격과 관련 구현을 의미한다.
배포판이 Java SE 호환성 검증을 통과했다면 일반적인 Java 프로그램은 배포판에 관계없이 동일하게 실행돼야 한다.
JVM은 Java Virtual Machine의 약자다.
Java 컴파일러가 만든 바이트코드를 실제 컴퓨터에서 실행한다.
Java 소스코드
↓ javac
바이트코드(.class)
↓ JVM
실제 CPU에서 실행
Java는 소스코드를 CPU 기계어로 바로 컴파일하는 대신 중간 형태인 바이트코드를 생성한다.
각 운영체제와 CPU에 맞는 JVM이 바이트코드를 실행한다.
동일한 Java 바이트코드
├── Windows AMD64용 JVM
├── Linux AMD64용 JVM
└── Linux ARM64용 JVM
이 구조 덕분에 Java는 다음 특징을 갖는다.
Write Once, Run Anywhere
단, 실행하는 장비에 적합한 JVM은 필요하다.
JRE는 Java Runtime Environment의 약자다.
Java 애플리케이션을 실행하는 데 필요한 구성요소를 제공한다.
개념적으로는 다음과 같이 이해할 수 있다.
JRE
├── JVM
└── Java 표준 라이브러리 및 실행 구성요소
이미 만들어진 Spring Boot JAR를 실행만 한다면 JRE 구성이면 충분하다.
java -jar app.jar
JDK는 Java Development Kit의 약자다.
Java 애플리케이션을 개발하고 실행하는 데 필요한 도구 모음이다.
JDK
├── Java 실행 환경
├── javac 컴파일러
├── jar 도구
├── javadoc
├── jlink
├── 디버깅 도구
└── 진단 도구
간단하게 표현하면 다음과 같다.
JDK = Java 실행 환경 + 개발 도구
Java 소스코드를 컴파일해야 한다면 JDK가 필요하다.
javac Main.java
이미 컴파일된 JAR를 실행만 한다면 전체 JDK가 반드시 필요한 것은 아니다.
OpenJDK는 Java Development Kit의 오픈소스 구현 프로젝트다.
여러 회사와 개발자가 OpenJDK 개발에 참여한다.
OpenJDK는 다음과 같이 이해할 수 있다.
OpenJDK 프로젝트
↓ 소스코드 개발
OpenJDK 소스
↓ 각 업체가 빌드·테스트·배포
Temurin / Corretto / Oracle OpenJDK 등
OpenJDK라는 말은 문맥에 따라 두 가지 의미로 사용된다.
따라서 단순히 “OpenJDK를 사용한다”라고 말하면 어느 업체의 빌드인지 추가 확인이 필요할 수 있다.
Eclipse Temurin은 Eclipse Adoptium 프로젝트가 제공하는 OpenJDK 배포판이다.
다음과 같은 특징이 있다.
Docker에서는 다음과 같이 사용할 수 있다.
FROM eclipse-temurin:21-jre-jammy
태그를 분해하면 다음과 같다.
eclipse-temurin → 배포판
21 → Java 버전
jre → 실행 중심 구성
jammy → Ubuntu 22.04 기반
Java 애플리케이션을 실행할 Docker 이미지를 간단하게 만들 때 적합하다.
Amazon Corretto는 Amazon이 제공하는 OpenJDK 배포판이다.
다음과 같은 특징이 있다.
Amazon Linux에서는 다음과 같이 설치할 수 있다.
FROM amazonlinux:2023
RUN dnf install -y java-21-amazon-corretto
이 구성은 다음 조합이다.
Amazon Linux 2023
+ Amazon Corretto 21
Corretto가 Amazon 제품이라고 해서 AWS에서만 실행할 수 있는 것은 아니다. 일반 서버나 로컬 컴퓨터에서도 사용할 수 있다.
Oracle JDK는 Oracle이 제공하는 JDK 배포 제품이다.
OpenJDK와 상당 부분 동일한 기반을 사용하지만 Oracle의 배포, 지원 및 라이선스 정책이 적용된다.
Oracle JDK를 사용할 때는 다음을 확인해야 한다.
Oracle JDK의 라이선스 정책은 Java 버전과 업데이트 시점에 따라 달라질 수 있으므로 기업 운영 환경에서는 반드시 해당 버전의 정책을 확인해야 한다.
일반적인 Java 애플리케이션 관점에서는 거의 같은 Java다.
다음 환경은 모두 Java 21 표준에 맞는 Java 프로그램을 실행할 수 있다.
Eclipse Temurin 21
Amazon Corretto 21
Oracle JDK 21
다른 Java 21 호환 OpenJDK 배포판
일반적인 Spring Boot JAR라면 배포판을 변경해도 소스코드를 수정할 가능성이 낮다.
하지만 배포 파일 자체가 완전히 똑같은 것은 아니다.
배포판에 따라 다음 요소가 달라질 수 있다.
따라서 “같은 Java 표준을 구현하지만 배포 제품은 다르다”라고 이해하면 된다.
Temurin, Corretto 및 일반적인 Oracle JDK는 보통 OpenJDK의 HotSpot JVM 계열을 사용한다.
따라서 일반적인 환경에서는 실행 특성이 매우 비슷하다.
하지만 모든 Java 배포판이 반드시 같은 JVM 구현을 사용하는 것은 아니다.
예를 들면 다음과 같은 JVM 또는 실행 기술이 있다.
JVM 구현이 달라지면 다음 특성이 달라질 수 있다.
따라서 Java 버전뿐 아니라 JVM 구현도 확인할 가치가 있다.
Java 코드는 일반적으로 바이트코드로 컴파일된다.
Main.java
↓ javac
Main.class
↓ jar
application.jar
JAR 내부의 바이트코드는 CPU 기계어가 아니다.
각 플랫폼용 JVM이 바이트코드를 현재 CPU에 맞게 실행한다.
application.jar
├── Temurin ARM64 JVM에서 실행
├── Temurin AMD64 JVM에서 실행
├── Corretto ARM64 JVM에서 실행
└── Corretto AMD64 JVM에서 실행
그러나 다음 요소가 포함되어 있다면 별도 확인이 필요하다.
.so, .dll, .dylibFROM eclipse-temurin:21-jre-jammy
COPY app.jar /app/app.jar
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
실행이 목적이므로 JRE 이미지가 적절하다.
컴파일 단계에서는 JDK가 필요하다.
FROM eclipse-temurin:21-jdk-jammy AS builder
WORKDIR /source
COPY . .
RUN ./gradlew bootJar
실행 단계에서는 JRE만 사용할 수 있다.
FROM eclipse-temurin:21-jre-jammy
WORKDIR /app
COPY --from=builder /source/build/libs/*.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
이를 멀티 스테이지 빌드라고 한다.
JDK 이미지
└── 애플리케이션 빌드
↓ JAR만 복사
JRE 이미지
└── 애플리케이션 실행
최종 이미지에 Gradle, 컴파일러 및 소스코드를 포함하지 않아도 되므로 이미지 크기와 공격 표면을 줄일 수 있다.
둘 다 일반적인 운영 환경에 사용할 수 있는 OpenJDK 배포판이다.
현재처럼 라즈베리파이에서 이미 빌드된 Spring Boot JAR를 실행하려면 다음 구성이 단순하다.
FROM eclipse-temurin:21-jre-jammy
다만 이것이 Corretto보다 Java 기능상 우월하다는 의미는 아니다. 배포 환경과 운영 정책에 더 잘 맞는 선택이라는 의미다.
JVM은 Java 바이트코드를 실행하는 가상 머신이다. JRE는 JVM과 Java 애플리케이션 실행에 필요한 라이브러리를 포함하는 실행 환경이다. JDK는 Java 실행 환경에 컴파일러, 디버거 및 개발 도구를 추가한 개발 도구 모음이다.
간단히 표현하면 다음과 같다.
JDK ⊃ 실행 환경 ⊃ JVM
Java SE 표준을 구현하는 오픈소스 JDK 프로젝트다. 여러 기업과 개발자가 참여하며 Temurin과 Corretto 같은 배포판은 OpenJDK 소스를 기반으로 빌드되고 테스트된다.
OpenJDK는 오픈소스 프로젝트와 원본 구현을 의미한다. Temurin은 Eclipse Adoptium이 OpenJDK 소스를 빌드하고 테스트해서 제공하는 배포판이다.
서로 다른 언어는 아니다. 둘 다 Java 표준을 준수하는 OpenJDK 기반 배포판이다. 공급자, 업데이트 정책, 지원 기간, 운영체제 패키징 및 기술지원 정책 등이 다르다.
상당 부분 같은 기반 기술을 공유하지만 배포 주체, 라이선스, 지원 정책 및 일부 패키징 요소가 다르다. Oracle JDK를 운영 환경에서 사용할 때는 해당 버전과 업데이트에 적용되는 라이선스를 확인해야 한다.
Java 소스가 특정 CPU의 기계어가 아니라 JVM이 실행할 수 있는 바이트코드로 컴파일되기 때문이다. 각 운영체제와 CPU에 맞는 JVM이 동일한 바이트코드를 실행한다.
일반적인 바이트코드는 플랫폼 독립적이지만 JNI, 네이티브 라이브러리, 운영체제 파일 경로, 문자 인코딩 및 외부 실행 파일을 사용하면 플랫폼에 종속될 수 있다.
이미 생성된 JAR를 실행만 한다면 JRE 기반 이미지가 적합하다. 컨테이너 내부에서 컴파일하거나 JDK 진단 도구가 필요하면 JDK가 필요하다.
컴파일에는 javac와 빌드 도구가 필요하지만 실행에는 JVM과 런타임 라이브러리만 필요하기 때문이다. 실행 이미지에서 불필요한 개발 도구를 제외하면 이미지 크기와 공격 표면을 줄일 수 있다.
일반적으로 실행할 수 없다. Java 21로 컴파일된 클래스 파일은 Java 17 JVM이 이해하지 못할 수 있으며 UnsupportedClassVersionError가 발생한다.
반대로 Java 17 대상으로 컴파일된 JAR는 일반적으로 Java 21에서 실행할 수 있지만, 제거되거나 변경된 API 및 라이브러리 호환성은 별도로 확인해야 한다.
장기 지원 대상으로 지정되어 비교적 오랫동안 보안 및 안정성 업데이트를 받을 수 있는 버전이다. 기업 운영 환경에서는 빈번한 메이저 버전 변경을 줄이기 위해 LTS 버전을 주로 선택한다.
OpenJDK 및 여러 JDK 배포판에서 사용하는 대표적인 JVM 구현이다. JIT 컴파일과 여러 가비지 컬렉터를 제공한다. OpenJDK는 전체 JDK 프로젝트를 의미하고 HotSpot은 그 안에서 바이트코드를 실행하는 JVM 구현을 의미한다.
JVM이 실행 중 자주 사용되는 바이트코드를 분석하고 현재 CPU의 네이티브 기계어로 컴파일하는 기술이다. 반복 실행되는 코드의 성능을 향상하는 데 사용된다.
같은 HotSpot 기반 배포판이면 대체로 비슷하지만 공급자 패치, JVM 빌드 옵션, 운영체제 라이브러리, 기본 설정 및 업데이트 버전에 따라 차이가 발생할 수 있다. 실제 선택은 서비스 환경과 부하를 기준으로 측정해야 한다.