프로젝트마다 Java 버전이 다르고, Gradle과 Maven 버전까지 제각각이라 매번 수동으로 설치하고 경로를 바꿔주는 일이 번거롭다면 SDKMAN을 주목할 만하다. SDKMAN(Software Development Kit MANager)은 macOS, Linux, WSL 환경에서 JDK를 비롯한 40종 이상의 개발 도구를 터미널 명령어 한 줄로 설치하고 버전을 전환할 수 있는 CLI 도구다. 공식 사이트에서 배포하고 있으며, 2024년 기준 GitHub에서 6,000개 이상의 스타를 받을 만큼 JVM 생태계에서 사실상 표준 도구로 자리 잡았다. 이 글에서는 SDKMAN 설치부터 핵심 사용법, 프로젝트별 빌드 환경 고정(.sdkmanrc), 그리고 실무에서 자주 마주치는 트러블슈팅까지 한 번에 정리한다.
SDKMAN 설치, 터미널 한 줄이면 끝
macOS, Linux 및 Windows(WSL) 과 같은 UNIX 환경에서 SDKMAN 설치는 매우 간단하다. BASH, ZSH 쉘 모두 호환이 된다.
$> curl -s "https://get.sdkman.io" | bash
$> source "$HOME/.sdkman/bin/sdkman-init.sh"Bash기본적으로 $HOME 경로 하위의 .sdkman 디렉터리에 설치된다.
설치 완료 후 bash 쉘을 사용하는 경우 $HOME/.bashrc 혹은 $HOME/.bash_profile 파일에, zsh 쉘을 사용하는 경우 $HOME/.zshrc 파일에 SDKMAN 초기화 스니펫이 추가된다.
#zshell 의 경우 .zshrc 파일에 추가된 초기화 스니펫
#THIS MUST BE AT THE END OF THE FILE FOR SDKMAN TO WORK!!!
export SDKMAN_DIR="$HOME/.sdkman"<br>[[ -s "$HOME/.sdkman/bin/sdkman-init.sh" ]] && source "$HOME/.sdkman/bin/sdkman-init.sh"Bash위 명령이 정상적으로 수행이 되면 설치가 완료된 것이다. 아래 명령을 통해서 버전 정보를 확인할 수 있다.
$> sdk version
SDKMAN!
script: 5.18.2
native: 0.4.2BashWindows에서 SDKMAN 쓰려면? WSL 세팅 가이드
윈도우 환경에서는 WSL 환경 혹은 Git Bash에서 설치가 가능하다.
- WSL 환경
- SDKMAN 설치하기 전에 Linux 용 Windows 하위 시스템 (WSL) 설치가 필요하다. WSL 설치 후 bash, zip, unzip, curl 패키지 설치가 필요하다.
- Git Bash 환경
- SDKMAN에 필요한 도구집합 (bash, zip, unzip, curl)을 갖추려면 MinGW로 보완을 해야 한다. 별로 추천하지 않는 듯하다. Cygwin 환경에서는 지원되지 않는다고 한다.
새 기능 먼저 써보기: SDKMAN beta 채널
새로운 SDKMAN CLI 기능을 체험해 보고 싶다면 배타판을 설치하여 체험해 볼 수 있다.
$> curl -s "https://beta.sdkman.io"Bash베타판 체험을 그만두고 싶다면 ~/.sdkman/etc/config 파일에서 sdkman_beta_channel 설정을 false로 변경 후 아래 명령을 실행한다.
$> sdk selfupdate forceBashSDKMAN 깔끔하게 삭제하기
- 기존에 설치된 sdkman을 백업 후 제거 하고자 하는 경우 .sdkman 을 백업 후 .sdkman 디렉터리를 제거한다.
$>tar cvfpz ~/sdkman-backup_$(date +%F).tar.gz -C ~/ .sdkman
$>rm -rf ~/.sdkmanBash위 명령은 $HOME/.sdkman 디렉터리를 $HOME/sdkman-backup_yyyy-mm-dd.tar.gz 형식으로 파일을 압축하여 백업 후 $HOME/.sdkman 디렉터리를 삭제한다.
- SDKMAN 설치시에 .bashrc 혹은 .zshrc 에 추가된 아래 SDKMAN 초기화 스니펫을 제거한다.
#THIS MUST BE AT THE END OF THE FILE FOR SDKMAN TO WORK!!!
export SDKMAN_DIR="$HOME/.sdkman"
[[ -s "$HOME/.sdkman/bin/sdkman-init.sh" ]] && source "$HOME/.sdkman/bin/sdkman-init.sh"Bash원하는 경로에 SDKMAN 설치하기
SDKMAN 은 기본적으로 $HOME/.sdkman 에 설치되지만 다른 경로로 SDKMAN을 설치할 수 있다.
SDKMAN 을 설치하기 전에 아래 명령으로 SDKMAN_DIR 환경 변수를 설치하고자 하는 디렉터리로 미리 세팅 후 설치를 진행한다.
$> export SDKMAN_DIR="/usr/local/sdkman" && curl -s "https://get.sdkman.io" | bashBash위 명령은 /usr/local/sdkman 디렉터리에 sdkman을 설치한다.
SDKMAN 핵심 명령어 총정리
sdkman 은 CLI 자동 완성을 지원한다. sdk <tab> 키를 통해서 사용할 수 있는 명령 옵션을 확인할 수 있다.
sdk list — 설치 가능한 패키지 한눈에 보기
$> sdk listBash설치 가능한 패키지 목록을 조회한다. 결과는 아래와 같이 출력된다.
================================================================================
Available Candidates
================================================================================
q-quit /-search down
j-down ?-search up
k-up h-help
--------------------------------------------------------------------------------
Apache ActiveMQ (Classic) (5.17.1) https://activemq.apache.org/
Apache ActiveMQ® is a popular open source, multi-protocol, Java-based message
broker. It supports industry standard protocols so users get the benefits of
client choices across a broad range of languages and platforms. Connect from
clients written in JavaScript, C, C++, Python, .Net, and more. Integrate your
multi-platform applications using the ubiquitous AMQP protocol. Exchange
messages between your web applications using STOMP over websockets. Manage your
IoT devices using MQTT. Support your existing JMS infrastructure and beyond.
ActiveMQ offers the power and flexibility to support any messaging use-case.
$ sdk install activemq
--------------------------------------------------------------------------------
Ant (1.10.13) https://ant.apache.org/
Apache Ant is a Java library and command-line tool whose mission is to drive
processes described in build files as targets and extension points dependent
upon each other. The main known usage of Ant is the build of Java applications.
Ant supplies a number of built-in tasks allowing to compile, assemble, test and
run Java applications. Ant can also be used effectively to build non Java
applications, for instance C or C++ applications. More generally, Ant can be
used to pilot any type of process which can be described in terms of targets and
tasks.
$ sdk install ant
--------------------------------------------------------------------------------
AsciidoctorJ (2.5.10) http://asciidoctor.org/
AsciidoctorJ is the official library for running Asciidoctor on the JVM. Using
AsciidoctorJ, you can convert AsciiDoc content or analyze the structure of a
parsed AsciiDoc document from Java and other JVM languages.
...
--------------------------------------------------------------------------------
Java (17.0.8.1-tem) https://projects.eclipse.org/projects/adoptium.temurin/
Java Platform, Standard Edition (or Java SE) is a widely used platform for
development and deployment of portable code for desktop and server environments.
Java SE uses the object-oriented Java programming language. It is part of the
Java software-platform family. Java SE defines a wide range of general-purpose
APIs – such as Java APIs for the Java Class Library – and also includes the Java
Language Specification and the Java Virtual Machine Specification.
$ sdk install java
...Bashsdk list <tab> 자동 완성을 이용하여 간단하게 설치 가능한 패키지 목록을 확인할 수 있다.
아래 명령은 특정 패키지의 설치가능한 목록을 보여준다.
$> sdk list <패키지명>
# 설치 가능한 java 패키지 목록 조회
$> sdk list java
================================================================================
Available Java Versions for macOS ARM 64bit
================================================================================
Vendor | Use | Version | Dist | Status | Identifier
--------------------------------------------------------------------------------
Corretto | | 20.0.2 | amzn | | 20.0.2-amzn
| | 20.0.1 | amzn | | 20.0.1-amzn
| | 17.0.8 | amzn | | 17.0.8-amzn
| | 17.0.7 | amzn | | 17.0.7-amzn
| | 11.0.20 | amzn | | 11.0.20-amzn
| | 11.0.19 | amzn | | 11.0.19-amzn
| | 8.0.382 | amzn | | 8.0.382-amzn
| | 8.0.372 | amzn | | 8.0.372-amzn
Gluon | | 22.1.0.1.r17 | gln | | 22.1.0.1.r17-gln
| | 22.1.0.1.r11 | gln | | 22.1.0.1.r11-gln
GraalVM CE | | 20.0.2 | graalce | | 20.0.2-graalce
| | 20.0.1 | graalce | | 20.0.1-graalce
| | 17.0.8 | graalce | | 17.0.8-graalce
| | 17.0.7 | graalce | | 17.0.7-graalce
GraalVM Oracle| | 20.0.2 | graal | | 20.0.2-graal
| | 20.0.1 | graal | | 20.0.1-graal
| | 17.0.8 | graal | | 17.0.8-graal
| | 17.0.7 | graal | | 17.0.7-graal
Java.net | | 22.ea.13 | open | | 22.ea.13-open
| | 22.ea.12 | open | | 22.ea.12-open
...
...
...
Temurin | | 20.0.2 | tem | | 20.0.2-tem
| | 20.0.1 | tem | | 20.0.1-tem
| | 17.0.8 | tem | | 17.0.8-tem
| | 17.0.8.1 | tem | | 17.0.8.1-tem
| | 17.0.7 | tem | | 17.0.7-tem
| | 11.0.20 | tem | | 11.0.20-tem
| | 11.0.20.1 | tem | | 11.0.20.1-tem
| | 11.0.19 | tem | | 11.0.19-tem
...Bashsdk install — 원하는 SDK를 골라 설치하기
# latest stable한 패키지 설치
$> sdk install <패키지명>
# 버전을 지정하여 설치
$> sdk install <패키지명> <Version | Identifier>
ex1) asciidoctorj 2.5.10 설치
$> sdk install asciidoctorj 2.5.10
ex2) Temurin 20.0.2-tem java 설치
$> sdk install java 20.0.2-temBash간단하게 sdk install <패키지명> <tab>을 통해서 자동완성으로 설치 가능한 버전을 확인할 수 있다.
아래 이미지는 sdk install java <tab>을 통해 자동 완성된 것을 보여주는 이미지다.
sdkman을 통해 설치된 패키지는 [sdkman 설치경로] 하위의 candidates/<패키지명>/<버전>에 설치된다.
예를 들어 sdk install java 20.0.2-tem 명령으로 temurin java 20.0.2를 설치한 경우 설치 디렉터리는 아래와 같다.
<sdkman 설치 경로>/candidates/java/20.0.2-temBash<sdkman 설치 경로>/candidates/java 디렉터리의 목록을 보면
drwxr-xr-x@ 11 staff 352 7 20 15:05 20.0.2-tem
lrwxr-xr-x@ 1 staff 10 9 2 21:32 current -> 20.0.2-temBash위와 같은데 current symbolic link를 통해서 현재 버전 변경을 관리하는 듯하다.
이미 설치된 SDK를 SDKMAN에 등록하기
sdkman을 통해서 설치한 것이 아닌 다른 방식으로 이미 패키지를 설치한 경우라도 sdkman 패키지 관리에 포함시킬 수 있다.
$> sdk install java tem-17-local /Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/HomeBash위 명령은 이미 설치된 temurin 17 java 가 /Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/Home 에 설치된 java 패키지를 sdkman에 포함시킨다.
tem-17-local로 지정한 값은 sdk list java 결과에 포함되지 않은 이름이어야 한다.
<sdkman 설치 경로>/candidates/java 디렉터리 목록을 보면 아래와 같이 변경된 것을 확인할 수 있다.
drwxr-xr-x@ 11 staff 352 7 20 15:05 20.0.2-tem
lrwxr-xr-x@ 1 staff 10 9 2 21:32 current -> 20.0.2-tem
lrwxr-xr-x@ 1 staff 62 9 2 21:43 tem-17-local -> /Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/HomeBashsdk use vs sdk default, 뭐가 다를까?
sdkman을 통해서 설치된 버전이 여러 개인 경우 버전을 변경할 수 있다.
$> sdk use <패키지명> <버전>
ex) java 패키지 버전을 tem-17-local 로 변경
$> sdk use java tem-17-local
$> sdk default <패키지명> <버전>
ex) java 패키지 버전을 tem-17-local 로 변경. current 의 링크가 tem-17-local 로 변경됨.
$> sdk default java tem-17-local
$> ls -l ~/.sdkman/candidates/java
drwxr-xr-x@ 11 staff 352 7 20 15:05 20.0.2-tem
lrwxr-xr-x@ 1 staff 56 9 2 22:05 current -> ~/.sdkman/candidates/java/tem-17-local
lrwxr-xr-x@ 1 staff 62 9 2 21:43 tem-17-local -> /Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/HomeBash버전을 변경하는 명령은 use와 default 가 있는데 차이점은 use의 경우에는 현재 쉘에만 적용되고, default의 경우에는 영구적으로 변경한다는 것이다.
안 쓰는 버전 정리하기: sdk uninstall
$> sdk uninstall <패키지명> <설치버전>
ex) temurin 20.0.2 java 버전 제거. tem-20.0.2 디렉토리가 삭제됨을 확인할 수 있다.
$> sdk uninatall java 20.0.2-tem
$>ls -l ~/.sdkman/candidates/java
lrwxr-xr-x@ 1 staff 56 9 2 22:05 current -> ~/.sdkman/candidates/java/tem-17-local
lrwxr-xr-x@ 1 staff 62 9 2 21:43 tem-17-local -> /Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/HomeBash위 명령은 설치된 패키지 버전을 제거한다. 만약 제거하고자 하는 버전이 current 버전이라면 삭제는 되지 않는다.
–force 옵션을 추가하거나 설치된 다른 버전이 있다면 current 버전을 다른 버전으로 변경 후 삭제를 진행한다.
지금 쓰고 있는 버전 확인하기
현재 설치되어 적용된 패키지 버전을 확인할 수 있다.
$> sdk current
Using:
java: tem-17-local
$> sdk current java
Using java version tem-17-localBash나에게 맞는 SDKMAN 설정 커스터마이징
sdkman의 설정 파일은 <sdkman 설치 경로>/etc/config 이다. sdk config 명령을 통해 설정 파일을 바로 편집할 수 있다.
$> sdk configBash설정 파일 항목은 아래와 같다.
# make sdkman non-interactive, preferred for CI environments
sdkman_auto_answer=true|false
# check for newer versions and prompt for update
sdkman_selfupdate_feature=true|false
# disables SSL certificate verification
# https://github.com/sdkman/sdkman-cli/issues/327
# HERE BE DRAGONS....
sdkman_insecure_ssl=true|false
# configure curl timeouts
sdkman_curl_connect_timeout=5
sdkman_curl_continue=true
sdkman_curl_max_time=10
# subscribe to the beta channel
sdkman_beta_channel=true|false
# enable verbose debugging
sdkman_debug_mode=true|false
# enable colour mode
sdkman_colour_enable=true|false
# enable automatic env
sdkman_auto_env=true|false
# enable rosetta2 compatibility for apple silicon
sdkman_rosetta2_compatible=true|false
# enable bash or zsh auto-completion
# 이 설정이 true 로 되어 있어야 sdkman 자동완성이 지원된다.
sdkman_auto_complete=true|falseBash.sdkmanrc로 프로젝트별 SDK 버전 고정하기
IntelliJ와 같은 IDE 환경에서 프로젝트 빌드를 수행할 수 있지만 때로는 CLI 환경에서 빌드를 하는 경우도 있다. 프로젝트를 함께 개발하고 있는 여러 팀원들이 각자 개발환경을 맞출 수도 있겠지만 sdkman을 활용하여 CLI 환경에서 동일한 빌드 환경을 손쉽게 맞출 수 있다.
.sdkmanrc 파일 만들기
프로젝트 루트에서 다음 명령을 실행하면 해당 경로에 .sdkmanrc 파일이 생성된다.
$> sdk env initBash위 명령으로 초기에 생성된 .sdkmanrc 파일에는 java 버전 항목만 설정된 채로 생성된다.
java를 키로 한 설정항목에 지정되는 값은 현재 sdkman에 지정된 현재 버전이 설정된다.
sdkman에서 관리하고 있는 패키지에 대한 현재 사용 중인 버전을 확인하려면 아래 명령을 통해 확인한다.
$> sdk current
Using:
gradle: 8.6
java: 17.0.14-temBash위 의미는 sdkman을 통해서 설치된 패키지 모듈은 gradle과 java인데 현재 시스템에 설정된 버전은 각각 8.6, 17.0.14-tem이라는 의미다.
실제로 ~/.sdkman/candidates/java 디렉터리를 보면 다음과 같이 되어 있다.
$> ll ~/.sdkman/candidates/java
total 0
drwxr-xr-x@ 6 xxxxxxxxx staff 192 7 11 10:28 .
drwxr-xr-x 5 xxxxxxxxx staff 160 4 2 2024 ..
drwxr-xr-x@ 11 xxxxxxxxx staff 352 1 19 2024 11.0.22-tem
drwxr-xr-x@ 11 xxxxxxxxx staff 352 1 22 2025 17.0.14-tem
drwxr-xr-x@ 11 xxxxxxxxx staff 352 1 17 2024 21.0.2-tem
lrwxr-xr-x@ 1 xxxxxxxxx staff 52 7 11 10:28 current -> /Users/nohacking/.sdkman/candidates/java/17.0.14-temBash그럼 초기에 생성되는 파일에는 다음과 같은 값이 설정되어 있을 것이다.
# Enable auto-env through the sdkman_auto_env config
# Add key=value pairs of SDKs to use below
java=17.0.14-temBash생성된 .sdkmanrc 파일에 빌드에 필요한 각 패키지 모듈에 대한 버전을 설정하면 된다.
예를 들어 java 21 temurin, gradle 8.6 버전으로 빌드하고자 한다면 .sdkmanrc 파일은 다음과 같이 수정한다.
# Enable auto-env through the sdkman_auto_env config
# Add key=value pairs of SDKs to use below
java=21.0.2-tem
gradle=8.6Bash.sdkmanrc 파일에서 설정 키는 ‘sdk current’ 명령으로 출력되는 candidate를 사용할 수 있다. (sdkman은 각 SDK 종류를 “candidate”라고 부른다.)
즉 위 예에서 .sdkmanrc에 설정할 수 있는 키는 java와 gradle이다.
만약 다른 SDK를 지정하기 위해서는 sdk 명령으로 수동으로 해당 SDK를 추가한 후 .sdkmanrc 파일에 설정을 추가해야 한다.
프로젝트 진입 시 SDK 자동 전환
사용하고자 하는 SDK에 대한 버전을 설정했다면 다음 명령을 통해서 적용할 수 있다.
$> sdk envBash위 명령은 현재 디렉토리에 .sdkmanrc 파일이 있으면 그 안의 키-값을 읽어 그 쉘 세션에서만 해당 버전으로 전환을 한다.
기본값 (sdk default …)을 바꾸지 않으며, SDKMAN의 current 심볼릭 링크도 건드리지 않는다.
# 프로젝트 루트( .sdkmanrc 존재 )에서
sdk env
# → .sdkmanrc에 설저된 SDK 버전을 이 세션에서만 활성화Bash만약 .sdkmanrc에 설정된 항목 중에 미설치 candidate가 있다면 설치 필요를 알려준다.
Stop! maven 3.9.9 is not installed.Bash이 경우 다음 명령을 통해서 자동 설치 및 전환을 할 수 있다.
$> sdk env installBash미설치된 candidate가 있다면 다음과 같이 출력한다.
java 21.0.2-tem is already installed.
gradle 8.6 is already installed.
Downloading: maven 3.9.9
In progress...
######################################################################## 100.0%
Installing: maven 3.9.9
Done installing!
Using java version 21.0.2-tem in this shell.
Using gradle version 8.6 in this shell.
Setting maven version 3.9.9 as default.
Using maven version 3.9.9 in this shell.Bashmaven 3.9.9 버전을 설치하고 설정된 각 candidate 버전으로 변경됨을 알 수 있다.
~/.sdkman/candidates 디렉터리를 보면 다음과 같이 maven candidate가 추가되어 있다.
$> ll ~/.sdkman/candidates
drwxr-xr-x 4 xxxxxxxxx staff 128 3 8 2024 gradle
drwxr-xr-x@ 6 xxxxxxxxx staff 192 7 11 10:28 java
drwxr-xr-x@ 4 xxxxxxxxx staff 128 10 22 14:15 mavenBashsdkman_auto_env로 완전 자동화하기
sdkman 설정 파일 ~/.sdkman/etc/config 파일에서 sdkman_auto_env=true (디폴트 false)로 설정하면 해당 디렉터리로 진입/이탈 시 자동으로 .sdkmanrc가 적용/복원된다.
다음 명령을 통해서 바로 config 파일을 vi 모드로 열 수 있다.
$> sdk configBash.sdkmanrc 파일 설정 후 git에 함께 커밋하여 같은 프로젝트를 하는 팀원들 간에 빌드 환경을 손쉽게 공유할 수 있다.
물론 각 팀원의 시스템 환경에 sdkman이 설치되어 있어야 한다.
CI와 Docker에서 SDKMAN 쓰기: 비대화형 설치와 자동화
CI 파이프라인이나 Dockerfile에서 SDKMAN을 쓸 때 가장 많이 막히는 지점은 “설치는 됐는데 sdk 명령이 안 먹는다”는 것이다. 원인은 sdk가 실행 파일이 아니라 셸 함수이기 때문이다. 대화형 셸에서는 .bashrc가 이 함수를 자동으로 불러오지만, CI나 docker build의 비대화형 셸에서는 그렇지 않다. 그래서 스크립트마다 초기화 스크립트를 직접 source 해야 하고, 설치도 프롬프트에 자동 응답하는 CI 모드로 해야 한다.
먼저 비대화형 설치다. 쿼리 파라미터 ci=true를 붙이면 모든 프롬프트에 자동 응답하고, 컬러 출력과 self-update를 꺼서 CI 로그를 깔끔하게 만든다.
# CI 친화 설치 (프롬프트 자동 응답 + 컬러/셀프업데이트 비활성화)
curl -s "https://get.sdkman.io?ci=true" | bash
# 설치 경로를 바꾸고 싶으면 SDKMAN_DIR을 먼저 지정한다
export SDKMAN_DIR="/usr/local/sdkman"
curl -s "https://get.sdkman.io?ci=true" | bashShellScriptci=true는 내부적으로 sdkman_auto_answer=true, sdkman_colour_enable=false, sdkman_selfupdate_feature=false를 설정한다. 셸 설정 파일(.bashrc 등)을 아예 건드리지 않고 설치만 하려면 rcupdate=false를 대신 쓴다. 설치 위치를 팀 공용이나 시스템 경로로 두려면 SDKMAN_DIR을 설치 전에 export 한다.
설치 뒤에는 매 스크립트에서 초기화 스크립트를 source 해야 sdk 함수가 살아난다. 이게 CI에서 “command not found”가 나는 진짜 이유다.
# 비대화형 셸(스크립트·CI)에서는 반드시 먼저 source 한다
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk install java 21.0.5-tem
sdk install gradleShellScriptsdkman-init.sh를 source 하면 그 셸 세션에 sdk 함수가 등록된다. 주의할 점은 이 효과가 현재 셸에만 유효하다는 것이다. GitHub Actions에서 스텝이 나뉘면 각 스텝이 새 셸이므로, 스텝마다 source를 다시 하거나 한 스텝 안에서 이어서 실행해야 한다.
Dockerfile에서는 SHELL을 bash로 바꾸고, source와 설치를 하나의 RUN으로 묶는 게 정석이다.
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y curl zip unzip && rm -rf /var/lib/apt/lists/*
# CI 모드로 비대화형 설치
RUN curl -s "https://get.sdkman.io?ci=true" | bash
# 이후 RUN은 비대화형 셸 → init 스크립트를 source 해야 sdk가 동작한다
SHELL ["/bin/bash", "-c"]
RUN source "$HOME/.sdkman/bin/sdkman-init.sh" && \
sdk install java 21.0.5-tem && \
sdk install gradle
ENV JAVA_HOME="/root/.sdkman/candidates/java/current"
ENV PATH="$JAVA_HOME/bin:$PATH"Dockerfile이 Dockerfile은 curl·zip·unzip을 먼저 설치하고(SDKMAN이 아카이브 해제에 zip/unzip을 쓴다), ci=true로 SDKMAN을 깐 뒤, SHELL을 bash로 바꿔 source와 sdk install을 한 레이어에 묶는다. 마지막에 JAVA_HOME과 PATH를 current 심볼릭 링크로 고정하면, 이후 애플리케이션 실행 단계에서 SDKMAN을 거치지 않고도 자바가 잡힌다. GitHub Actions라면 같은 원리를 한 run 스텝 안에서 source ... && sdk install ...로 그대로 쓰면 된다.
SDKMAN vs mise vs asdf: 언제 무엇을 쓸까
버전 관리 도구 선택 기준은 하나다. JVM 생태계만 다루면 SDKMAN, 여러 언어를 한 도구로 묶고 싶으면 mise나 asdf다. SDKMAN은 JDK·Gradle·Maven·Kotlin 같은 JVM 도구에 특화돼 벤더별 JDK를 이름만으로 설치하는 게 강점이고, mise·asdf는 Node·Python·Ruby까지 한 파일로 관리하는 범용성이 강점이다.
| 항목 | SDKMAN | mise | asdf | jenv |
|---|---|---|---|---|
| 대상 | JVM 도구 특화(JDK·Gradle·Maven·Kotlin 등 40여 종) | 다언어(Node·Python·Ruby·JVM 등) | 다언어(플러그인) | 이미 설치된 JDK 전환만 |
| JDK 설치 | 벤더별 직접 다운로드(sdk list java) | 지원(java 플러그인) | 플러그인 필요 | 불가(전환만) |
| 프로젝트 고정 | .sdkmanrc | .mise.toml·.tool-versions | .tool-versions | .java-version |
| 자동 전환 | sdkman_auto_env=true | 기본 제공(shim/hook) | direnv·훅 필요 | 자동 |
| 설치 방식 | 자체 아카이브 다운로드 | 자체·플러그인 | 플러그인 | 전환만 |
표에서 보듯 SDKMAN은 “자바 개발자가 JVM 도구만 편하게 관리”하는 데 최적화돼 있다. Java와 Gradle, Kotlin만 쓴다면 SDKMAN 하나로 충분하고, 벤더 선택(Temurin·Corretto·GraalVM)이 명령어 한 줄로 끝나는 편의는 다른 도구가 따라오기 어렵다. 반면 한 팀이 Java 백엔드와 Node 프런트, Python 스크립트를 함께 다룬다면 mise 같은 범용 버전 매니저로 통일하는 편이 관리 포인트를 줄인다. jenv는 설치 기능이 없어 성격이 다르므로, jenv는 이미 설치된 JDK만 전환하고 싶을 때 선택한다.
굳이 하나만 고르라면, JVM 위주 개발이라면 SDKMAN을 기본으로 두고 필요할 때 mise를 곁들이는 조합을 권한다. 둘은 배타적이지 않아서, 자바는 SDKMAN으로 나머지 언어는 mise로 나눠 쓰는 팀도 많다.
SDKMAN 트러블슈팅: 자주 겪는 문제와 해결법
sdk: command not found
SDKMAN 설치 후 터미널을 새로 열었는데 sdk 명령어가 인식되지 않는 경우가 있다. 대부분 쉘 초기화 파일에 SDKMAN 스니펫이 제대로 추가되지 않았거나, 스니펫 위치가 잘못된 것이 원인이다.
ZSH 사용자라면 ~/.zshrc 파일 맨 끝에 아래 스니펫이 있는지 확인한다. oh-my-zsh 플러그인이 SDKMAN 초기화보다 뒤에 로드되면 PATH가 덮어씌워질 수 있으므로, SDKMAN 스니펫은 반드시 파일의 가장 마지막에 위치해야 한다.
Download has failed, aborting!
회사 네트워크나 방화벽 환경에서 SDK 다운로드가 실패하는 경우다. 프록시 설정이 필요하다면 ~/.sdkman/etc/config 파일에서 프록시 관련 환경변수를 세팅하거나, 네트워크 관리자에게 api.sdkman.io와 download.sdkman.io 도메인의 아웃바운드 허용을 요청한다.
쉘 기동이 느려졌다면: healthcheck 설정
SDKMAN은 쉘 시작 시 버전 업데이트 확인(healthcheck)을 수행하는데, 네트워크 상태가 불안정하면 터미널 기동이 수 초간 지연될 수 있다. ~/.sdkman/etc/config 파일에서 sdkman_auto_selfupdate=false로 설정하면 자동 업데이트 확인을 끌 수 있다. 필요할 때 sdk selfupdate로 수동 업데이트하면 된다.
WSL에서 zip/unzip 미설치 오류
WSL 환경에서 SDKMAN을 처음 설치할 때 zip과 unzip 패키지가 없으면 설치가 실패한다. 아래 명령으로 필요한 패키지를 먼저 설치한 뒤 SDKMAN 설치를 진행하면 해결된다.
sudo apt-get install zip unzip curl위 명령은 Ubuntu/Debian 기반 WSL에서 SDKMAN이 요구하는 zip, unzip, curl 세 가지 필수 패키지를 한번에 설치한다. 이 패키지들이 없으면 SDK 아카이브 압축 해제 과정에서 오류가 발생하므로 반드시 사전에 설치해야 한다.
자주 묻는 질문 (FAQ)
SDKMAN이란 무엇인가요?
SDKMAN은 JDK, Gradle, Maven, Kotlin, Scala 등 JVM 기반 개발 도구의 설치와 버전 관리를 자동화하는 CLI 도구다. macOS, Linux, WSL 환경에서 동작하며, sdk install java 21.0.5-tem 같은 명령어 한 줄로 원하는 버전을 설치하고 전환할 수 있다.
SDKMAN과 jenv의 차이점은?
jenv는 이미 설치된 JDK의 버전 전환만 담당하는 반면, SDKMAN은 JDK 다운로드/설치부터 버전 전환, 삭제까지 전체 라이프사이클을 관리한다. 또한 SDKMAN은 Java뿐 아니라 Gradle, Maven, Spring Boot CLI, Quarkus CLI 등 40종 이상의 도구를 함께 관리할 수 있다는 점이 가장 큰 차이다.
Windows에서 SDKMAN을 사용할 수 있나요?
네이티브 Windows 환경에서는 직접 사용할 수 없지만, WSL(Windows Subsystem for Linux)을 설치하면 Linux와 동일하게 SDKMAN을 사용할 수 있다. Git Bash에서도 가능하지만 MinGW 보완이 필요해 WSL 방식을 권장한다.
SDKMAN으로 설치 가능한 SDK에는 어떤 것들이 있나요?
Java(Temurin, Corretto, GraalVM, Zulu 등 다양한 벤더), Gradle, Maven, Kotlin, Scala, Groovy, Spring Boot CLI, Quarkus CLI, Apache Ant, Micronaut, VisualVM 등 40종 이상의 SDK와 도구를 지원한다. sdk list 명령으로 전체 목록을 확인할 수 있으며, 공식 SDK 목록 페이지에서도 확인 가능하다.
.sdkmanrc 파일은 팀원 모두 SDKMAN이 설치되어 있어야 하나요?
그렇다. .sdkmanrc는 SDKMAN이 읽는 설정 파일이므로, 팀원 각자의 로컬 환경에 SDKMAN이 설치되어 있어야 sdk env install 명령이 동작한다. 다만 SDKMAN이 없는 팀원에게 영향을 주지는 않으며, .sdkmanrc 파일 자체가 오류를 발생시키지 않으므로 Git에 커밋해 두어도 안전하다.
CI나 Docker에서 sdk 명령이 “command not found”로 안 돼요.
sdk는 실행 파일이 아니라 셸 함수라서 그렇다. 비대화형 셸(스크립트·docker build·CI)에서는 source "$HOME/.sdkman/bin/sdkman-init.sh"를 먼저 실행해 함수를 등록해야 sdk 명령이 동작한다. 설치도 curl -s "https://get.sdkman.io?ci=true" | bash처럼 CI 모드로 하면 프롬프트가 자동 응답된다. 자세한 방법은 본문 “CI와 Docker에서 SDKMAN 쓰기” 절을 참고한다.
설치한 SDK를 최신 버전으로 한꺼번에 올리려면?
sdk upgrade를 쓴다. 인자 없이 sdk upgrade를 실행하면 설치된 후보 중 새 버전이 나온 것을 알려주고, sdk upgrade java처럼 특정 후보만 지정할 수도 있다. 다만 쓰던 옛 버전을 자동으로 지우지는 않으므로, 새 버전 설치 후 필요 없어진 버전은 sdk uninstall로 정리한다.
mise나 asdf가 있는데 굳이 SDKMAN을 써야 하나요?
JVM 도구만 다룬다면 SDKMAN이 더 편하다. 벤더별 JDK를 이름만으로 설치·전환하고 Gradle·Maven·Kotlin까지 한 도구로 묶는 데 특화돼 있기 때문이다. 여러 언어(Node·Python 등)를 함께 관리해야 한다면 mise나 asdf가 낫다. 둘은 배타적이지 않아 자바만 SDKMAN, 나머지는 mise로 나눠 쓰기도 한다. 자세한 비교는 본문의 비교 표를 참고한다.
SDKMAN을 쓰기 시작한 건 몇 년 전 팀 프로젝트에서 JDK 11과 JDK 17을 동시에 쓸 일이 생기면서부터였다. 그 전에는 JAVA_HOME을 수동으로 바꿔가며 썼는데 한두 번은 괜찮아도 프로젝트가 서너 개 되니까 어느 터미널에 어떤 버전이 잡혀있는지 헷갈리기 시작했다. SDKMAN을 도입한 뒤로는 .sdkmanrc 하나 커밋해 두면 신규 팀원 온보딩 때 “Java 몇 버전 깔아야 해요?” 같은 질문이 사라졌다. 새 프로젝트 디렉터리에 들어가면 알아서 버전이 전환되니까 머릿속에서 “지금 이 터미널은 17이었나 21이었나” 같은 인지 부하가 사라진 게 가장 크다. 도구 하나 잘 골라서 세팅해두면 이렇게 매일 반복하는 작은 불편이 통째로 사라지는 경험을 할 수 있다.
최종 업데이트: 2026년 8월
관련링크
SDKMAN 공식 사이트 | SDKMAN 사용법 공식 문서 | SDKMAN GitHub | 지원 SDK 전체 목록
함께 읽으면 좋은 글
- Java 25 주요 변경 사항 완벽 정리 — LTS 신기능과 실무 적용 가이드
- Java 26 새 기능 총정리: HTTP/3, G1 GC 개선부터 Structured Concurrency까지
- JDK 21에서 JDK 25로: 성능 업데이트
- Quarkus Native Image 빌드 완벽 가이드: 0.049초 기동의 비밀
