네이티브 이미지로 배포

네이티브 이미지로 배포 (Deploy as Native Image)

개요

JDBC 드라이버는 GraalVM Native Image 실행 파일 안에서 실행돼요. Graal Native Image는 Java 애플리케이션을 사전에(ahead of time) 컴파일해 밀리초 단위로 시작하고 대상 머신에 JVM이 필요 없는 독립 실행 바이너리로 만들어요. 명령줄 도구, 서버리스 함수, 작은 컨테이너에 어울리죠.

최근 드라이버 버전은 native-image가 필요로 하는 JNI reachability 메타데이터를 포함하며, 빌드는 클래스패스에서 그것을 자동으로 가져와요.

애플리케이션이 구성할 것이 두 가지 남아요. 네이티브 접근과 DuckDB 공유 라이브러리의 위치예요.

1.5.5 이하 드라이버 버전은 이 메타데이터를 포함하지 않아요. 그 버전에서는 tracing agent로 JVM에서 애플리케이션을 한 번 실행해 생성해요.

java -agentlib:native-image-agent=config-output-dir=⟨config_dir⟩ -cp ⟨classpath⟩ ⟨MainClass⟩

그다음 빌드에 -H:ConfigurationFileDirectories=⟨config_dir⟩로 디렉터리를 넘겨요.

요구 사항

GraalVM for JDK 22 이상이 필요해요. 더 오래된 GraalVM 릴리스는 이미지 빌드 시점에 드라이버의 클래스를 초기화해 빌드 머신 경로를 실행 파일에 구워 넣고, 실행 시 UnsatisfiedLinkError로 실패해요.

native-image--enable-native-access=ALL-UNNAMED를 넘기거나, Native Build Tools Maven·Gradle 플러그인의 빌드 인자로 추가해요.

첫 커넥션을 열기 전에 드라이버를 명시적으로 로드해요.

Class.forName("org.duckdb.DuckDBDriver");

ServiceLoader를 통한 드라이버 자동 등록은 Graal Native Image의 폐쇄 세계 분석에 항상 보이지 않아요. 명시적 로드로 등록을 결정적으로(deterministically) 만들어요.

출처: 문서

본문

공유 라이브러리 제공

DuckDB의 엔진은 드라이버 JAR 안에 번들된 네이티브 라이브러리인데, 플랫폼마다 파일 하나씩 있어요. 실행 파일이 그것을 사용할 수 있게 하는 두 가지 방법 중 하나를 골라요.

옵션 1: 라이브러리를 실행 파일에 내장

-H:ConfigurationFileDirectories로 전달된 설정 디렉터리나 자신의 프로젝트의 META-INF/native-image 아래에 플랫폼 라이브러리를 이름 짓는 리소스 항목을 추가해요.

{ "resources": { "includes": [ { "pattern": "libduckdb_java\\.so_linux_amd64" } ] } }

번들된 라이브러리 이름은 libduckdb_java.so_linux_amd64, libduckdb_java.so_linux_arm64, libduckdb_java.so_osx_universal, libduckdb_java.so_windows_amd64이에요.

대상 플랫폼의 것을 명시적으로 이름 지어요. 모두와 일치하는 와일드카드는 실행 파일에 약 260MB를 더해요.

이 옵션은 단일 자체 포함 파일(약 120MB)을 만들어요. 드라이버는 첫 커넥션이 열릴 때 라이브러리를 임시 디렉터리로 추출하는데, 시작 시간에 최대 1초가 더해지고 쓰기 가능한 임시 디렉터리가 필요해요.

옵션 2: 실행 파일 옆에 라이브러리 배치

리소스 항목 없이 빌드하고 공유 라이브러리를 실행 파일과 같은 디렉터리에 둬요. 파일은 번들된 이름(예: libduckdb_java.so_linux_amd64) 또는 플랫폼 관례(libduckdb_java.so(Linux), libduckdb_java.dylib(macOS), duckdb_java.dll(Windows))로 동작해요. 조회는 작업 디렉터리가 아니라 실행 파일에 고정되므로 프로그램이 어디서든 제대로 실행돼요.

이 옵션은 작은 실행 파일(간단한 애플리케이션은 20MB 미만)을 만들고 커넥션이 열릴 때 추출 비용이 없어요. 라이브러리는 드라이버 JAR에서 추출하거나, -nolib 배포에서 별도 라이브러리 아티팩트와 함께 가져올 수 있어요.

빌드

현재 디렉터리에 드라이버 JAR가 있는 최소 빌드:

javac -cp duckdb_jdbc-⟨version⟩.jar App.java
native-image --no-fallback --enable-native-access=ALL-UNNAMED \
    -cp duckdb_jdbc-⟨version⟩.jar:. -o app App

--no-fallback는 여전히 JVM이 필요한 이미지를 만드는 대신 빌드를 아예 실패시켜요. Maven·Gradle 프로젝트에서는 Native Build Tools 플러그인이 같은 빌드를 감싸 mvn packagegradle nativeCompile 동안 실행해요.

더 알아보기 (Learn more)

  • [Troubleshoot]({% link docs/current/clients/java/troubleshoot.md %}) — 누락된 메타데이터나 누락된 공유 라이브러리를 나타내는 Native Image 오류.
  • [Define Connections]({% link docs/current/clients/java/connecting.md %}) — 드라이버 등록과 커넥션 구성.
  • [Java (JDBC) Client]({% link docs/current/clients/java/overview.md %}) — Maven Central에서 드라이버 설치.