4. WAS 종류별 에이전트 설정 방법
이 장에서 하는 일
3장에서 받은 에이전트를 각 WAS 제품의 기동 옵션에 실제로 넣는 방법을 다룹니다.
왜 제품마다 다른가
넣어야 할 내용은 어느 제품이든 같습니다.
-javaagent:<에이전트 jar 경로> # 에이전트를 JVM 에 붙인다
-Dkhan.config.file=<설정 파일 이름> # 어느 설정을 쓸지 지정한다 (인스턴스가 여러 개일 때)
다른 것은 이 옵션을 어디에 적는가입니다. WAS 제품마다 기동 옵션을 읽는 파일과 변수 이름이 다릅니다.
| 제품 | 적는 곳 | 변수 |
|---|---|---|
| Spring Boot | 실행 명령 또는 기동 스크립트 | JAVA_OPTS |
| Tomcat | bin/setenv.sh | CATALINA_OPTS · JAVA_OPTS |
| JBoss EAP · WildFly (Standalone) | bin/standalone.conf | JAVA_OPTS |
| JBoss EAP · WildFly (Domain) | domain.xml · host-slave.xml | <jvm-options> |
| WebLogic | setDomainEnv.sh 또는 기동 스크립트 | JAVA_OPTIONS |
| JEUS | JEUSMain.xml · domain.xml | <command-option> · <jvm-option> |
| Jetty | start.ini 또는 기동 스크립트 | JAVA_OPTIONS |
| Resin | conf/resin.xml | <jvm-arg> |
찾는 법이 애매하면 지금 WAS 를 띄우는 스크립트나 설정 파일에서 -Xmx 처럼 이미 들어 있는
JVM 옵션을 찾으십시오. 그 옆이 에이전트 옵션을 넣을 자리입니다.
공통으로 지켜야 할 것
- 경로는 절대 경로로 적습니다. 상대 경로는 WAS 가 어느 디렉터리에서 뜨는지에 따라 달라집니다.
- 옵션은 기동 시점에만 읽힙니다. 고친 뒤 반드시 WAS 를 재기동해야 적용됩니다.
- Java 9 이상이면 추가 옵션이 더 필요합니다. 이 장 마지막의 Java 9 이상 추가 옵션을 함께 넣으십시오.
-noverify·-Xverify:none은 넣지 마십시오. 예전 안내에 있던 옵션이지만 지금은 필요 없고, 운영 중 JVM 이 비정상 종료될 수 있습니다 (6장 참고).
쓰는 제품으로 바로 가기
| 제품 | 절 | 특별히 주의할 것 |
|---|---|---|
| Spring Boot | 실행 명령 | -javaagent 를 -jar 앞에 |
| JBoss EAP 6·7 Standalone | standalone.conf | 로그 관리자 옵션 3종 필수 |
| JBoss EAP 6·7 Domain | domain.xml · host-slave.xml | 스크립트가 아니라 XML |
| WildFly 14 | standalone.conf | Java 11 은 -Xbootclasspath/a |
| JBoss EAP 5.x | run.conf | 설정이 가장 단순 |
| Tomcat | catalina.sh 또는 setenv.sh | 둘 중 하나만 — 양쪽에 넣으면 두 번 붙음 |
| WebLogic | setDomainEnv.sh | 변수가 JAVA_OPTIONS |
| JEUS 6 | JEUSMain.xml | JMX 옵션 없으면 데이터소스 안 보임 |
| JEUS 7/8 | domain.xml | 태그가 <jvm-option> |
| Jetty 9 | jetty.sh | 변수가 JAVA_OPTIONS |
| Resin 4.x | conf/resin.xml | watchdog 때문에 XML 에 |
각 절은 고칠 파일 → 주의할 점 → 예제 순서로 되어 있습니다. 예제의 경로와 설정 파일 이름은 환경에 맞게 바꾸십시오.
설정한 뒤 확인하는 법
WAS 를 재기동한 뒤 실제로 붙은 JVM 옵션을 봅니다. 파일에 적었어도 다른 스크립트가
JAVA_OPTS 를 덮어써 사라지는 일이 흔합니다.
$ ps -ef | grep java
출력에 -javaagent:…khan-agent…jar 가 보이면 붙은 것입니다. 보이지 않으면 옵션을 적은
자리가 기동 경로에서 실제로 읽히는지 확인하십시오.
옵션은 보이는데 콘솔에 안 나타나면 접속 정보 문제입니다 —
khan-agent.conf 의 khan.host·khan.port 와 방화벽을 확인하십시오
(3장 참고).
Spring Boot
고칠 파일 — 애플리케이션을 띄우는 기동 스크립트(없으면 java -jar 실행 명령).
Spring Boot 는 WAS 설정 파일이 따로 없어 실행 명령에 직접 붙입니다.
주의할 점 — -javaagent 는 반드시 -jar 앞에 와야 합니다. 뒤에 두면 JVM 옵션이 아니라
애플리케이션 인자로 넘어가 에이전트가 붙지 않습니다.
컨테이너로 띄운다면 JAVA_TOOL_OPTIONS 환경변수로 주는 방법도 있습니다 —
5장 컨테이너·쿠버네티스에 설치 참고.
KHAN_AGENT_FILE=$(ls /data/test/tomcat/servers/khan-agent/khan-agent*.jar | sort -Vr | head -n 1)
export AGENT_OPTS=" -javaagent:$KHAN_AGENT_FILE "
#export AGENT_OPTS=" -javaagent:/svc/test/khan-agent/khan-agent.jar "
export AGENT_OPTS="$AGENT_OPTS -Dkhan.config.file=khan-agent-test11.conf"
export JAVA_OPTS="$AGENT_OPTS $JAVA_OPTS"
java -jar $JAVA_OPTS openmaru-dashboard-server-5.1.0.jar
JBoss EAP 6.x, 7.x Standalone 모드
고칠 파일 — 기동 시 JVM 옵션을 읽는 자리면 어디든 됩니다. 흔한 자리는 세 곳입니다.
| 자리 | 어떤 경우에 |
|---|---|
bin/standalone.conf | JBoss 기본 구성을 그대로 쓸 때 |
env.sh 같은 자체 기동 스크립트 | 사이트에서 기동 스크립트를 따로 두고 쓸 때. 아래 예제가 이 방식입니다 |
start.sh | 위 env.sh 를 읽어 실제로 띄우는 스크립트 — 여기서 JAVA_OPTS 를 넘깁니다 |
예제는 env.sh 에 옵션을 모으고 start.sh 가 그것을 JAVA_OPTS 로 넘기는 구성입니다.
standalone.conf 하나만 쓴다면 두 예제의 내용을 그 파일에 합쳐 넣으면 됩니다.
왜 설정이 복잡한가 — JBoss 는 자체 로그 관리자(JBoss LogManager)를 쓰는데, 에이전트가
JVM 시작 시점에 먼저 로드되면서 로그 관리자보다 앞서 클래스를 건드립니다. 그대로 두면
기동 중 LogManager 오류로 멈춥니다. 그래서 아래 세 가지를 함께 넣습니다.
| 옵션 | 무엇을 하나 |
|---|---|
-Djava.util.logging.manager=…LogManager | JBoss 로그 관리자를 쓰도록 못 박습니다 |
-Xbootclasspath/p:…jboss-logmanager*.jar | 그 로그 관리자를 에이전트보다 먼저 읽게 합니다 |
-Djboss.modules.system.pkgs=… | 에이전트 패키지를 JBoss 모듈 격리에서 제외합니다 |
jboss.modules.system.pkgs 에는 com.opennaru.khan.agent 와 org.jboss.logmanager 를 함께
적어야 합니다. 하나라도 빠지면 ClassNotFoundException 이 납니다.
JBoss EAP의 경우 JBoss LogManager의 설정이 필요합니다.
jboss.modules.system.pkgs에 com.opennaru.khan.agent와 org.jboss.logmanager 패키지를 등록하여 합니다.
- env.sh (6.x)
export AGENT_OPTS=" -javaagent:/svc/test/khan-agent/khan-agent.jar "
#export AGENT_OPTS=" -javaagent:$(getKhanAgentPath :/svc/test/khan-agent) "
export AGENT_OPTS="$AGENT_OPTS -Dkhan.config.file=khan-agent-test11.conf"
export JAVA_OPTS="$JAVA_OPTS -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
export JBOSS_LOGMANAGER_DIR="$JBOSS_HOME/modules/system/layers/base/org/jboss/logmanager/main"
export JBOSS_LOGMANAGER_JAR=`cd "$JBOSS_LOGMANAGER_DIR" && ls -1 *.jar`
#export JBOSS_LOGMANAGER_JAR=$(getLogmanagerPath "$JBOSS_HOME")
export JAVA_OPTS="$JAVA_OPTS -Xbootclasspath/p:$JBOSS_LOGMANAGER_DIR/$JBOSS_LOGMANAGER_JAR"
export JAVA_OPTS=" $JAVA_OPTS -Djboss.modules.system.pkgs=org.jboss.byteman,com.opennaru.khan.agent,org.github.jamm,org.jboss.logmanager"
- env.sh (7.x)
## 아래 각 옵션 순서 중요
export AGENT_OPTS=" -javaagent:/home/icfcgw/khan-agent/khan-agent-5.1.0.jar "
export AGENT_OPTS="$AGENT_OPTS -Dkhan.config.file=khan-agent-icfcgw.conf "
## JBoss EAP가 패치된 경우 $JBOSS_HOME/modules/system/layers/base/.overlays/ 하위에서 탐색
## log4j-jboss-logmanager와 혼동하지 않도록 해야함
export JAVA_OPTS="$JAVA_OPTS -Djava.util.logging.manager=org.jboss.logmanager.LogManager "
export JBOSS_LOGMANAGER_DIR="$JBOSS_HOME/modules/system/layers/base/org/jboss/logmanager/main"
export JBOSS_LOGMANAGER_JAR=cd "$JBOSS_LOGMANAGER_DIR" && ls -1 *.jar
export JBOSS_WILDFLY_COMMON_DIR="$JBOSS_HOME/modules/system/layers/base/org/wildfly/common/main"
export JBOSS_WILDFLY_COMMON_JAR=cd "$JBOSS_WILDFLY_COMMON_DIR" && ls -1 *.jar
export JAVA_OPTS="$JAVA_OPTS -Xbootclasspath/p:$JBOSS_LOGMANAGER_DIR/$JBOSS_LOGMANAGER_JAR:$JBOSS_WILDFLY_COMMON_DIR/$JBOSS_WILDFLY_COMMON_JAR"
export JAVA_OPTS="$JAVA_OPTS -Djboss.modules.system.pkgs=org.jboss.byteman,com.opennaru.khan.agent,org.github.jamm,\
org.jboss.logmanager,org.wildfly.common.net.HostName"
## java 11이상의 경우 필수
export JAVA_OPTS=" $JAVA_OPTS -Dsun.util.logging.disableCallerCheck=true "
export JAVA_OPTS="$AGENT_OPTS $JAVA_OPTS"
※ getKhanAgentPath, getLogmanagerPath 함수 사용 할 경우 function.sh Include (하단 참조)
- start.sh
export JAVA_OPTS="$AGENT_OPTS $JAVA_OPTS"
- standalone***.xml**
<datasource jndi-name="{{ jndi_name }}" pool-name="{{ pool_name }}" enabled="true" use-ccm="true" statistics-enabled="true">
JBoss EAP 6.x, 7.x Domain 모드
고칠 파일 — domain.xml 과 host-slave.xml(또는 host.xml).
Standalone 과 다른 점 — 도메인 모드는 서버 인스턴스를 도메인 컨트롤러가 띄웁니다. 기동 스크립트에 옵션을 적어도 각 인스턴스에 전달되지 않으므로, XML 에 적어야 합니다.
| 파일 | 무엇을 적나 |
|---|---|
domain.xml | 도메인 전체에 공통인 시스템 속성(로그 관리자·모듈 격리 제외) |
host-slave.xml | 인스턴스마다 다른 값 — -javaagent 경로와 khan.config.file |
인 스턴스가 여러 개면 host-slave.xml 의 서버마다 khan.config.file 을 다르게 주어
설정 파일을 나눕니다. 그래야 콘솔에서 인스턴스가 구분됩니다.
도메인 모드를 사용할 경우 XML 파일에 시작 옵션을 설정해야 합니다.
- env.sh
export JAVA_OPTS=" $JAVA_OPTS -Djboss.modules.system.pkgs=org.jboss.byteman,com.opennaru.khan.agent,org.github.jamm,org.jboss.logmanager"
....
export JBOSS_LOGMANAGER_DIR="$JBOSS_HOME/modules/system/layers/base/org/jboss/logmanager/main"
export JBOSS_LOGMANAGER_JAR=`cd "$JBOSS_LOGMANAGER_DIR" && ls -1 *.jar`
export JAVA_OPTS=" $JAVA_OPTS -DJBOSS_LOGMANAGER=$JBOSS_LOGMANAGER_DIR/$JBOSS_LOGMANAGER_JAR "
- domain.xml
<system-properties>
{/* IPv4 is not required, but setting this helps avoid unintended use of IPv6 */}
<property name="java.net.preferIPv4Stack" value="true"/>
<property name="java.util.logging.manager" value="org.jboss.logmanager.LogManager" boot-time="true"/>
<property name="jboss.modules.system.pkgs" value="org.jboss.byteman,com.opennaru.khan.agent,org.github.jamm,org.jboss.logmanager" boot-time="true"/>
</system-properties>
...
<datasource jndi-name="{{ jndi_name }}" pool-name="{{ pool_name }}" enabled="true" use-ccm="true" statistics-enabled="true">
...
- host-slave.xml
<server name="test11" auto-start="true">
<jvm name="default">
<jvm-options>
<option value="-Xbootclasspath/p:${JBOSS_LOGMANAGER}"/>
<option value="-javaagent:/svc/test/khan-agent/khan-agent.jar"/>
<option value="-Xloggc:/svc/log/slave/test11/gclog/gc_${DATE}.log"/>
<option value="-XX:HeapDumpPath=/svc/log/slave/test11/heapdump"/>
</jvm-options>
</jvm>
<system-properties>
<property name="jboss.node.name" value="test11"/>
<property name="khan.config.file" value="khan-agent-test11.conf"/>
Wildfly 14(Java 11)
고칠 파일 — JBoss EAP Standalone 과 같습니다. 아래 예제도 env.sh + start.sh 구성이며,
standalone.conf 하나만 쓴다면 내용을 합쳐 넣으면 됩니다. 데이터소스 통계를 보려면
standalone-xxx.xml 도 함께 고칩니다.
JBoss EAP 와 다른 점 — Java 11 부터 -Xbootclasspath/p 가 없어져 -Xbootclasspath/a
를 씁니다. 또 WildFly 는 org.wildfly.common 모듈이 따로 있어 그 JAR 도 함께 지정해야 합니다.
-Dsun.util.logging.disableCallerCheck=true 를 반드시 넣으십시오. 없으면 로그 호출자를
확인하는 과정에서 기동이 크게 느려집니다.
Java 11버전을 사용하는 Wildfly 14는 경우 JBoss LogManager의 설정이 필요합니다.
jboss.modules.system.pkgs에 com.opennaru.khan.agent와 org.jboss.logmanager 패키지를 등록하여 합니다. 또, -Xbootclasspath/a 옵션을 사용하여 JBoss Logging 관련 JAR파일들을 지정하여야 하며, -Dsun.util.logging.disableCallerCheck=true 옵션을 지정합니다.
- env.sh
export AGENT_OPTS=" -javaagent:/svc/test/khan-agent/khan-agent.jar "
#export AGENT_OPTS=" -javaagent:$(getKhanAgentPath :/svc/test/khan-agent) "
export AGENT_OPTS="$AGENT_OPTS -Dkhan.config.file=khan-agent-test11.conf"
export JAVA_OPTS="$JAVA_OPTS -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
export JBOSS_LOGMANAGER_DIR="$JBOSS_HOME/modules/system/layers/base/org/jboss/logmanager/main"
export JBOSS_LOGMANAGER_JAR=`cd "$JBOSS_LOGMANAGER_DIR" && ls -1 *.jar`
export JBOSS_WILDFLY_COMMON_DIR="$JBOSS_HOME/modules/system/layers/base/org/wildfly/common/main"
export JBOSS_WILDFLY_COMMON_JAR=`cd "$JBOSS_WILDFLY_COMMON_DIR" && ls -1 *.jar`
export JAVA_OPTS=" -Xbootclasspath/a:$JBOSS_LOGMANAGER_DIR/$JBOSS_LOGMANAGER_JAR:$JBOSS_WILDFLY_COMMON_DIR/$JBOSS_WILDFLY_COMMON_JAR $JAVA_OPTS"
export JAVA_OPTS=" -Dsun.util.logging.disableCallerCheck=true $JAVA_OPTS"
export JAVA_OPTS=" $JAVA_OPTS -Djboss.modules.system.pkgs=org.jboss.byteman,com.opennaru.khan.agent,org.github.jamm,org.jboss.logmanager"
- start.sh
export JAVA_OPTS="$AGENT_OPTS $JAVA_OPTS"
- standalone-xxx.xml
<datasource jndi-name="{{ jndi_name }}" pool-name="{{ pool_name }}" enabled="true" use-ccm="true" statistics-enabled="true">
JBoss EAP 5.x
고칠 파일 — bin/run.conf 또는 기동 스크립트(아래 예제).
5.x 는 모듈 격리 구조가 없어 6.x 이후보다 설정이 단순합니다. 로그 관리자 관련 옵션도 필요 없습니다.
시작시 JAVA_OPTS에 아래 설정을 추가합니다.
JAVA_OPTS=%JAVA_OPTS% -Djboss.platform.mbeanserver
JAVA_OPTS=%JAVA_OPTS% -Djavax.management.builder.initial=org.jboss.system.server.jmx.MBeanServerBuilderImpl
JAVA_OPTS=" $JAVA_OPTS -javaagent:/svc/test/khan-agent/khan-agent.jar "
JAVA_OPTS=" $JAVA_OPTS -Dkhan.config.file=khan-agent-test11.conf"
Tomcat
고칠 파일 — bin/catalina.sh 또는 bin/setenv.sh. 둘 중 하나만 고치면 됩니다.
| 어떤 경우에 | |
|---|---|
catalina.sh 에 직접 | 지금 쓰는 방식을 그대로 두고 싶을 때. 예제가 이 방식입니다 |
setenv.sh 로 분리 | Tomcat 을 올릴 계획이 있을 때 — 업그레이드 때 catalina.sh 는 덮어써지지만 setenv.sh 는 남습니다 |
setenv.sh 는 기본으로 없는 파일이며, 만들어 두면 catalina.sh 가 기동할 때 자동으로
읽습니다. 내용은 아래 예제와 같고 파일 이름만 다릅니다.
변수 선택 — CATALINA_OPTS 를 권합니다. JAVA_OPTS 는 shutdown.sh 에도 적용되어
종료할 때 에이전트가 한 번 더 붙습니다.
catalina.sh 에 직접 넣기
catalina.sh 를 열어 맨 위 주석 블록 다음에 아래를 넣습니다. 파일 중간이나 끝에 넣으면
그 아래에서 변수를 다시 덮어쓸 수 있습니다.
export AGENT_OPTS=" -javaagent:/svc/test/khan-agent/khan-agent.jar "
#export AGENT_OPTS=" -javaagent:$(getKhanAgentPath :/svc/test/khan-agent) "
export AGENT_OPTS="$AGENT_OPTS -Dkhan.config.file=khan-agent-test11.conf"
#export AGENT_OPTS="$AGENT_OPTS -Dcom.sun.management.jmxremote"
export CATALINA_OPTS="$AGENT_OPTS $CATALINA_OPTS"