hdfs 명령이나 하둡 생태계의 자바 클라이언트를 돌리면 다음이 나고 멈춘다.
java.lang.UnsupportedOperationException:
getSubject is supported only if a security manager is allowed
hdfs dfs -ls, hive CLI, Spark 제출, 자체 작성한 HDFS 클라이언트 모두에서 볼 수 있다. Kerberos 를 쓰지 않는 클러스터에서도 난다.
JDK 17 에서 Security Manager 가 폐기 예정으로 표시됐고, JDK 18 부터는 기본으로 사용할 수 없게 바뀌었다. javax.security.auth.Subject.getSubject(AccessControlContext) 는 Security Manager 를 전제로 하는 API 라 이 상태에서 호출하면 위 예외를 던진다.
하둡의 UserGroupInformation 은 현재 사용자를 알아내기 위해 바로 이 API 를 쓴다. 그래서 하둡 클라이언트를 JDK 18 이상에서 돌리면 인증 여부와 무관하게 첫 호출에서 걸린다.
즉 설정이 잘못된 것이 아니라 JDK 버전이 하둡이 지원하는 범위를 벗어난 것이다.
셸의 java -version 이 아니라 그 명령이 실제로 쓰는 JDK 를 봐야 한다.
echo "$JAVA_HOME"
"$JAVA_HOME/bin/java" -version
하둡 클라이언트는 hadoop-env.sh 의 값을 우선한다.
grep -n 'JAVA_HOME' /etc/hadoop/conf/hadoop-env.sh
정석이다. 쓰고 있는 하둡 배포판이 지원하는 JDK 로 맞춘다. 대부분의 하둡 3.x 계열은 JDK 8 과 11 을 지원한다. 정확한 범위는 Hadoop 자바 버전 호환성 을 본다.
설치된 JDK 를 확인하고 고른다.
sudo alternatives --config java
특정 명령에서만 바꾸려면 환경 변수로 지정한다.
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk
export PATH="$JAVA_HOME/bin:$PATH"
hdfs dfs -ls /
JDK 를 당장 내릴 수 없으면 Security Manager 를 허용 상태로 두면 예외가 나지 않는다. JDK 18 이상에서 쓰는 플래그다.
export HADOOP_OPTS="$HADOOP_OPTS -Djava.security.manager=allow"
hdfs dfs -ls /
자체 작성한 자바 프로그램이면 실행 인자에 직접 준다.
java -Djava.security.manager=allow -cp "$(hadoop classpath)" com.example.HdfsClient
Spark 나 YARN 위에서 도는 경우에는 드라이버와 익스큐터 양쪽에 줘야 한다.
spark-submit \
--conf spark.driver.extraJavaOptions=-Djava.security.manager=allow \
--conf spark.executor.extraJavaOptions=-Djava.security.manager=allow \
...
이것은 임시 조치다. Security Manager 는 제거 수순을 밟고 있어 이후 JDK 에서는 이 플래그도 사라진다. 지원 JDK 로 돌리는 것이 정답이다.
같은 원인, 즉 최신 JDK 의 강한 캡슐화 때문에 나는 다른 예외도 함께 본다.
java.lang.reflect.InaccessibleObjectException: Unable to make ... accessible
java.lang.IllegalAccessError
이쪽은 --add-opens 로 여는데, 역시 임시 조치다. 대응 방법은 Hadoop 자바 버전 호환성 에 정리돼 있다.