docker tomcat 多开 实例_Docker zabbix-agent 监控 docker tomcat 多实例
目录
监控方案概述
我们使用 zabbix-agent 的方式来监控 多个 tomcat 8.5.51 ,由于我们需要监控的是 Docker 容器里的 Tomcat ,而 zabbix 官方模板并不支持,而且官方提供的第三方方案也不支持多实例监控,所以只能参考很多互联网上的一些解决方案,最终形成了适合我们自己的应用场景的解决方案(监控虚拟机里的多个 tomcat 实例方案见文末的参考资料)。
本文详细描述了整个方案的详细过程和原理,如果只是想监控 tomcat 多个 Docker 实例,请参考:tomcat 监控实际操作
准备工作
配置 tomcat 容器的 LABEL 标签:JMX_PORT 和 JMX_MONITOR_UUID 用于定义使用的 jmx 端口和 tomcat 的 UUID 标记。
tomcat 配置 jmx,实际上 java 应用的 jmx 监控中原理都相同,开启并配置 jmx 的远程监控配置即可,这个是监控的前提条件。
tomcat 自动发现脚本
tomcat_jmx 监控数据源脚本
cmdline-jmxclient-0.10.3.jar 来监控数据
处理 zabbix-server 获取不到 zabbix-agent 收集的数据问题
处理 zabbix-agent 镜像挂载容器外的 docker 进程时候报错:permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
tomcat 容器镜像启动
拉取 tomcat 镜像
docker pull develop-harbor.geostar.com.cn/base/apache-tomcat:8.5.51-8u231
启动 tomcat 多实例
docker run -p 8088:8080 -p 10057:10057 --name tomcat-test1 -l JMX_MONITOR_UUID=bc47dcd484724fb48fe81bc9f0e3d802 -l JMX_PORT=10057 -d develop-harbor.geostar.com.cn/base/apache-tomcat:8.5.51-8u231
docker run -p 8089:8080 -p 10058:10058 --name tomcat-test2 -l JMX_MONITOR_UUID=bc47dcd484724fb48fe81bc9f0e3d803 -l JMX_PORT=10058 -d develop-harbor.geostar.com.cn/base/apache-tomcat:8.5.51-8u231
注意:这里启动了 2 个 tomcat 容器实例,第一个容器内部 8080 映射到外部为 8088,jmx使用 10057 端口,第一个容器内部 8080 映射到外部为8089,jmx 使用 10058 端口。这里定义的我们约定的标签有 JMX_PORT 和 JMX_MONITOR_UUID ,JMX_PORT 用于定义使用的 jmx 端口,JMX_MONITOR_UUID 用于定义 tomcat 实例的 UUID 标记,区分各个 tomcat实例。
定义这两个标签是为了后续使用 Docker 的 api 来获取 tomcat 的监控信息(jmx 的端口、容器内部 ip、)
进入每个tomcat容器实例内部(以tomcat-test1为例子)
docker exec -it tomcat-test1 bash
配置 jmx 监听
vi /srv/tomcat8/bin/catalina.sh
加入以下配置
CATALINA_OPTS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=10057 -Dcom.sun.management.jmxremote.rmi.port=10057 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=172.16.101.245"
其中-Djava.rmi.server.hostname=配置为当前服务器 ip,请自行修改,
-Dcom.sun.management.jmxremote.port=10057
-Dcom.sun.management.jmxremote.rmi.port=10057
这两个 jmx 的端口需要与容器启动时候用的 jmx 端口保持一致。
退出 tomcat 容器,重启 tomcat 容器
exit
docker restart tomcat-test1
测试 jmx 能否获取到数据,打开 jdk 目录下面的 jconsole 工具,输入 jmx 远程连接 ip 和 jmx 连接端口
点连接后正常连接就证明 jmx 已正常启用
在这个过程中我们发现一些主要的注意事项,请您在结合自己的监控场景的时候也一定注意:
带密码的 jmx 配置
我们在监控的时候因为会有很多个 tomcat 的 docker 实例,为了简化监控,所以使用 jmx 连接并没有设置密码,如果需要密码访问 jmx ,那么需要设置如下的:
CATALINA_OPTS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=10057 -Dcom.sun.management.jmxremote.rmi.port=10057 -Dcom.sun.management.jmxremote.authenticate=true -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=172.16.101.245
-Dcom.sun.management.jmxremote.access.file=/srv/tomcat8/conf/jmx.access
-Dcom.sun.management.jmxremote.password.file=/srv/tomcat8/conf/jmx.password"
authenticate:改为 true
access.file:设置访问权限,readonly:只能读取 MBean 的属性和接受通知。
readonly:只能读取 MBean 的属性和接受通知。
readwrite:还允许设置属性,调用方法,创建和删除 MBean。
# cat /srv/tomcat8/conf/jmx.access 如果不存在这个文件请自行创建
admin readwrite
password.file:访问密码
# cat /srv/tomcat8/conf/jmx.password 如果不存在这个文件请自行创建
admin tomcat
创建完成上述文件后,修改文件权限(这一步很关键,因为这些属于敏感信息,所以需要限制访问权限,不修改的话会在监控的时候报错)
# chmod 400 jmx.*
注意:这个时候需要重启 tomcat 容器让配置生效
端口的映射问题
采用 tomcat 的 jmx 监控有一个限制,容器对外映射 jmx 端口,容器内部 jmx 端口,配置文件里的 jmx 端口,三者必须严格保持一致,不然无法正常获取到监控数据,所以,必须是 -p 10057:10057 这种形式来启动 tomcat 容器,如果是 10058:10057这种形式会失败,或者在 dockerfile 里用 expose 10057,外部映射随机端口,同样会失败,这个坑一定要注意。虽然 oracle 的工程师通过别的解决方案解决了这个问题,但是会引入 oracle 的一些商业软件进来,规避了这个问题本身,所以不采取他们的方案:http://thegridman.com/coherence/oracle-coherence-on-docker/#jmx
ps ef | grep tomcat 过滤 tomcat jmx 端口方案
相对于用 docker api 的方式获取 tomcat 容器 jmx 端口的方案,还有另外一种方案,仅供参考。
jmx_tomcat_discovery.sh,执行下面这个脚本就可以获取 tomcat jmx 监控的端口号,如果是在 docker 版的 zabbix-agent 容器内执行,还需要在启动这个 agent 容器的时候加上 --pid=host 这个启动参数。
#!/bin/bash
# this is the server ip
serverip=127.0.0.1
# serverObj example:"{#SERVER_IP}": "172.16.101.181", "{#TOMCAT_NAME}": "tomcat_10053"
serverObj=""
# this cmd returns the jmx port the tomcat instances using
tomcat_jxm_ports_res=`ps -aux | grep "tomcat" | awk '{for(i=1;i<=NF;i++){print $i;}}' | grep jmxremote.port | cut -d'=' -f 2`
for tomcat_jmx_port in $tomcat_jxm_ports_res
do
tmp=\{\"{#SERVER_IP}\":\"$serverip\",\"{#TOMCAT_NAME}\":\"tomcat_$tomcat_jmx_port\",\"{#TOMCAT_PORT}\":\"$tomcat_jmx_port\"\},
serverObj="$serverObj$tmp"
done
# subString the last comma of the serverObj string
if [ $serverObj ] ; then
serverObj=${serverObj:0:-1}
fi
# the jsonResult is like {"data": [{"{#SERVER_IP}": "172.16.101.181", "{#TOMCAT_NAME}": "tomcat_10053", "{#TOMCAT_PORT}": "10053"}, {"{#SERVER_IP}": "172.16.101.181", "{#TOMCAT_NAME}": "tomcat_10053", "{#TOMCAT_PORT}": "10054"}]}
if [ $serverObj ] ; then
jsonResult=\{\"data\":[$serverObj]\}
echo $jsonResult
else
echo ""
fi
验证是否能获取 jmx 监控数据
除了用 jconsole 的本地方式连接测试外,更推荐一种在 zabbix-server上通过 cmdline-jmxclient 验证的方式,因为这样能确保服务端可以连接上客户端。
服务端下载 cmdline-jmxclient
wget http://crawler.archive.org/cmdline-jmxclient/cmdline-jmxclient-0.10.3.jar
测试
[root@host-172-16-102-253 ~]# java -jar cmdline-jmxclient-0.10.3.jar - 172.16.101.245:10057 java.lang:type=Memory NonHeapMemoryUsage
05/04/2020 14:53:19 +0800 org.archive.jmx.Client NonHeapMemoryUsage:
committed: 36372480
init: 2555904
max: -1
used: 33912184
注意:如果是有用户名/密码的 jmx 监控,那么需要把 ip 前面的 - 替换为我们设置的 admin:tomcat
tomcat自动发现脚本
获取 tomcat 多个容器实例的 容器 ip、tomcat JMX 端口,uuid,输出为 json 格式提供给 zabbix-server 获取使用(没办法,只能自己写脚本咯,:)。
jmx_tomcat_discovery.py
#!/usr/bin/python
# -*- encoding: utf-8 -*-
import urllib
import xml.etree.ElementTree as ET
import json
import os
import commands
import subprocess
def main():
data = []
(status, docker_ps_output) = commands.getstatusoutput('docker ps -q')
docker_ps_output_text = docker_ps_output.decode('utf-8')
if docker_ps_output_text:
container_id_list=docker_ps_output_text.split('\n')
for container_id in container_id_list:
out_bytes = subprocess.check_output(['docker','inspect',container_id])
out_text = out_bytes.decode('utf-8')
result=json.loads(out_text)
jmx=result[0]['Config']['Labels']
if('JMX_PORT' in jmx):
jmx_port=result[0]['Config']['Labels']['JMX_PORT']
jmx_monitor_uuid=result[0]['Config']['Labels']['JMX_MONITOR_UUID']
ip=result[0]['NetworkSettings']['Networks']['bridge']['IPAddress']
tomcat_instance={"{#CONTAINER_IP}":ip,"{#JMX_PORT}":jmx_port,"{#JMX_MONITOR_UUID}":jmx_monitor_uuid}
data.append(tomcat_instance)
print json.dumps({"data": data})
else:
print "empty result of docker ps -q"
if __name__ == "__main__":
main()
这个脚本我们直接放到了自制的 zabbix-agent 容器镜像内,供我们的自定义 UserParameter 来调用。你也可以根据你的情况放到你认为合适的位置。
tomcat_jmx监控数据源脚本
监控模板参考zabbix监控自动发现监控tomcat(V1)修改而来,定义了我需要的CONTAINER_IP,JMX_PORT,JMX_MONITOR_UUID 三个自定义占位符。
tomcat_monitor.sh,这个脚本跟上面的 python 脚本一样放到 zabbix-agent 的容器镜像里,供我们的自定义 UserParameter 来调用。这里我针对自己的环境和需要的东西做了优化,跟你环境不合适的位置请自行修改。
#!/bin/bash
source /etc/profile
[ $# -ne 3 ] && echo 'The scripts need 3 parameters' && exit 1
CONTAINER_IP=$1
JMX_PORT=$2
ITEM=$3
authenticate="-"
# if no authenticate,use "-",otherwise,add authenticate jmx user and password code here
# jmx_user="akiya"
# jmx_password="akiya_password"
# if [ -n "$jmx_user" ] && [ -n "$jmx_password" ]; then
# authenticate="$jmx_user:$jmx_password"
# fi
# The PORT means the tomcat service default port in the server.xml
PORT=8080
# The cmd means the directory of cmdline-jmxclient jar
cmd=/etc/zabbix/scripts/tomcat/cmdline-jmxclient-0.10.3.jar
#logdir=/tmp/zabbix_tmp
#[ ! -d "$logdir" ] && mkdir -p $logdir && chmod 644 $logdir
#cd $logdir
LOGDIR=/etc/zabbix/scripts/tomcat/logs
function HeapMemoryUsage() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT java.lang:type=Memory HeapMemoryUsage 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
function EdenSpaceUsage() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT java.lang:type=MemoryPool,name=PS\ Eden\ Space Usage 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
function SurvivorSpaceUsage() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT java.lang:type=MemoryPool,name=PS\ Survivor\ Space Usage 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
function TenuredGenUsage() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT java.lang:type=MemoryPool,name=PS\ Old\ Gen Usage 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
function NonHeapMemoryUsage() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT java.lang:type=Memory NonHeapMemoryUsage 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
function MetaspaceUsage() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT java.lang:type=MemoryPool,name=Metaspace Usage 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
function CodeCacheUsage() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT java.lang:type=MemoryPool,name=Code\ Cache Usage 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
function CompressedClassSpaceUsage() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT java.lang:type=MemoryPool,name=Compressed\ Class\ Space Usage 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
function TotalLoadedClassCount() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT java.lang:type=ClassLoading TotalLoadedClassCount 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
function LoadedClassCount() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT java.lang:type=ClassLoading LoadedClassCount 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
function UnloadedClassCount() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT java.lang:type=ClassLoading UnloadedClassCount 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
function TotalStartedThreadCount() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT java.lang:type=Threading TotalStartedThreadCount 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
function ThreadCount() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT java.lang:type=Threading ThreadCount 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
function PeakThreadCount() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT java.lang:type=Threading PeakThreadCount 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
function maxThreads() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT Catalina:name=\"http-nio-$PORT\",type=ThreadPool maxThreads 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
function currentThreadCount() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT Catalina:name=\"http-nio-$PORT\",type=ThreadPool currentThreadCount 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
function currentThreadsBusy() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT Catalina:name=\"http-nio-$PORT\",type=ThreadPool currentThreadsBusy 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
function GlobalRequestProcessor_bytesReceived() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT Catalina:name=\"http-nio-$PORT\",type=GlobalRequestProcessor bytesReceived 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
function GlobalRequestProcessor_bytesSent() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT Catalina:name=\"http-nio-$PORT\",type=GlobalRequestProcessor bytesSent 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
function requestCount() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT Catalina:name=\"http-nio-$PORT\",type=GlobalRequestProcessor requestCount 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
function errorCount() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT Catalina:name=\"http-nio-$PORT\",type=GlobalRequestProcessor errorCount 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
function jvmUptime() {
java -jar $cmd $authenticate $CONTAINER_IP:$JMX_PORT java.lang:type=Runtime Uptime 2>$LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
}
case $ITEM in
HeapMemoryUsage.max)
HeapMemoryUsage
sed -n '4p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
HeapMemoryUsage.used)
HeapMemoryUsage
sed -n '5p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
HeapMemoryUsage.committed)
HeapMemoryUsage
sed -n '2p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
EdenSpaceUsage.max)
EdenSpaceUsage
sed -n '4p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
EdenSpaceUsage.used)
EdenSpaceUsage
sed -n '5p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
EdenSpaceUsage.committed)
EdenSpaceUsage
sed -n '2p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
SurvivorSpaceUsage.max)
SurvivorSpaceUsage
sed -n '4p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
SurvivorSpaceUsage.used)
SurvivorSpaceUsage
sed -n '5p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
SurvivorSpaceUsage.committed)
SurvivorSpaceUsage
sed -n '2p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
TenuredGenUsage.max)
TenuredGenUsage
sed -n '4p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
TenuredGenUsage.used)
TenuredGenUsage
sed -n '5p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
TenuredGenUsage.committed)
TenuredGenUsage
sed -n '2p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
NonHeapMemoryUsage.used)
NonHeapMemoryUsage
sed -n '5p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
NonHeapMemoryUsage.committed)
NonHeapMemoryUsage
sed -n '2p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
MetaspaceUsage.used)
MetaspaceUsage
sed -n '5p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
MetaspaceUsage.committed)
MetaspaceUsage
sed -n '2p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
CodeCacheUsage.max)
CodeCacheUsage
sed -n '4p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
CodeCacheUsage.used)
CodeCacheUsage
sed -n '5p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
CodeCacheUsage.committed)
CodeCacheUsage
sed -n '2p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
CompressedClassSpaceUsage.max)
CompressedClassSpaceUsage
sed -n '4p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
CompressedClassSpaceUsage.used)
CompressedClassSpaceUsage
sed -n '5p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
CompressedClassSpaceUsage.committed)
CompressedClassSpaceUsage
sed -n '2p' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT | awk '{print $2}'
;;
ClassLoading.TotalLoadedClassCount)
TotalLoadedClassCount
awk '{print $6}' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
;;
ClassLoading.LoadedClassCount)
LoadedClassCount
awk '{print $6}' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
;;
ClassLoading.UnloadedClassCount)
UnloadedClassCount
awk '{print $6}' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
;;
Threading.TotalStartedThreadCount)
TotalStartedThreadCount
awk '{print $6}' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
;;
ThreadCount)
ThreadCount
awk '{print $6}' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
;;
PeakThreadCount)
PeakThreadCount
awk '{print $6}' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
;;
maxThreads)
maxThreads
awk '{print $6}' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
;;
currentThreadCount)
currentThreadCount
awk '{print $6}' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
;;
currentThreadsBusy)
currentThreadsBusy
awk '{print $6}' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
;;
bytesReceived)
GlobalRequestProcessor_bytesReceived
awk '{print $6}' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
;;
bytesSent)
GlobalRequestProcessor_bytesSent
awk '{print $6}' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
;;
requestCount)
requestCount
awk '{print $6}' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
;;
errorCount)
errorCount
awk '{print $6}' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT
;;
jvmUptime)
jvmUptime
[ $? -eq 0 ] && awk '{print $6/1000}' $LOGDIR/$CONTAINER_IP.$ITEM.$JMX_PORT || echo 0
;;
esac
我们的 userparameter_tomcat.conf 里配置如下:
UserParameter=tomcat.discovery,/usr/bin/python /etc/zabbix/scripts/tomcat/jmx_tomcat_discovery.py
UserParameter=tomcat.status[*],/bin/bash /etc/zabbix/scripts/tomcat/tomcat_monitor.sh $1 $2 $3
处理 zabbix-server 获取不到 zabbix-agent 收集的数据问题
在 zabbix_server 端上使用 zabbix_get 测试的时候,会出现权限错误无数据,这个时候应该修改 zabbix-agent 容器里这些脚本的所属用户。
chown -R zabbix:zabbix /etc/zabbix/scripts/tomcat
chmod 775 /etc/zabbix/scripts/tomcat/cmdline-jmxclient-0.10.3.jar /etc/zabbix/scripts/tomcat/jmx_tomcat_discovery.py /etc/zabbix/scripts/tomcat/tomcat_monitor.sh
zabbix-agent 镜像挂载容器外的 docker 进程时候报错
因为,我们的脚本里用到 docker ps 、 docker inspect 等命令,所以需要在 zabbix-agent 容器里挂载宿主的 docker 进程,即 -v /usr/bin/docker:/usr/bin/docker -v /var/run/docker.sock:/var/run/docker.sock 这个挂载参数,会出现这个错误:
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
这个时候需要修改权限解决,在容器启动的时候修改权限(这个已经预制到我的 zabbix-agent 镜像里了)
chmod 777 /var/run/docker.sock
测试
在 zabbix-server 可以用下面的命令来测试 jmx 的所有 Bean(只到 ip:port部分,不包括后面部分) 和 Bean 的值(包括具体的 Bean 名字和属性)
# java -jar cmdline-jmxclient-0.10.3.jar - 172.16.101.245:10057
# java -jar cmdline-jmxclient-0.10.3.jar - 172.16.101.245:10057 java.lang:type=Memory NonHeapMemoryUsage
在 zabbix-server 的容器镜像内,可以使用下面的命令来获取用户自定义参数 UserParameter 对应的 key 的值执行后获取的结果,比如:下面的例子会执行 jmx_tomcat_discovery.py 脚本,获取返回值。
# zabbix_get -s 172.16.102.96 -k tomcat.discovery
UserParameter=tomcat.discovery,/usr/bin/python /etc/zabbix/scripts/tomcat/jmx_tomcat_discovery.py
tomcat 监控
zabbix 主机管理页面关联 Templates App Tomcat 模版即可获得多个 tomcat 的 docker 实例的监控数据
监控到的数据
监控原理
现在,是时候总结下 多个 docker 的 tomcat 实例监控的原理了。
开启 tomcat 容器镜像的 jmx 监控配置并配置对外映射端口
用我们的自定义用户脚本,执行 jmx_tomcat_discovery.py 获取到多个 tomcat 容器的端口号,ip 地址, uuid 等信息,供 zabbix-server 端的自动发现规则使用
我们用发现出来的 ip ,port ,uuid 填充我们监控模板中的键,这样就保证了监控的每一个 key 都不一致(这个限制由 zabbix 本身决定了,也是为什么很多方案做不到监控多实例的原因),通过这个 key 去请求我们的 tomcat_monitor.sh 脚本,获取到监控项的值。
主要参考资料
docker tomcat 多开 实例_Docker zabbix-agent 监控 docker tomcat 多实例相关推荐
- ZABBIX Agent2监控docker
首先我们先来看一下zabbix agent2监控docker插件的实现原理,其实就是通过调用docker的API来获取数据,插件目录位于zabbix-agent2/src/go/plugins/doc ...
- zabbix企业应用之监控docker容器资源情况
关于docker的监控,无论开源的CAdvisor.Data Dog还是我自己写的监控(http://dl528888.blog.51cto.com/2382721/1635951),不是通过dock ...
- linux下构建Zabbix网络监控平台
linux下构建Zabbix网络监控平台 由于图片过多,本人不想一张一张上传,请下载我的详细文章: linux下构建zabbix网络监控平台[技术文档](河南-清小小)-下载地址: http://do ...
- zabbix常用监控项解读
CPU来源模板:Template Module Linux CPU by Zabbix agent 内存(memory)来源模板:Template Module Linux memory by Zab ...
- zabbix日志监控:操作系统、业务系统、文件大小、多行日志
zabbix日志监控:操作系统.业务系统.文件大小.多行日志 目录 1 监控操作系统日志 2 监控业务系统日志 具体要求: 分析: 操作: 3 监控日志文件大小 (1)在被管主机当中安装agent ( ...
- docker tomcat 多开 实例_给妈妈讲什么是docker
上周对象突然心血来潮说想养个小宠物,我问想养啥她又说随便,你看着办!!!这我真的比较难办啊!但是咱们程序员能有个对象就不错了,还不赶紧宠着,我只能照办咯! 我去到了一家宠物店,半天也没有找到合适的 ...
- 使用docker安装部署Spark集群来训练CNN(含Python实例)
使用docker安装部署Spark集群来训练CNN(含Python实例) 本博客仅为作者记录笔记之用,不免有很多细节不对之处. 还望各位看官能够见谅,欢迎批评指正. 博客虽水,然亦博主之苦劳也. 如需 ...
- CentOS 7.5基于Docker部署4.2 版本的zabbix监控平台
两台VMware 虚拟机 一台充当zabbix server(安装docker)ip:192.168.73.133 一台充当zabbix agent(安装docker)ip:192.168.73.13 ...
- docker history显示完整信息_Docker使用
背景 docker是什么? docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱 ...
最新文章
- 输入命令导出oracle
- 创建型设计模式对比总结 设计模式(八)
- matlab寻找函数对应的工具箱
- SAP WebClient UI drop down list(下拉列表)的一个故障和解决方法
- 从键盘上录入学生人数和每个学生的分数,按分数降序输出所有的分数,java冒泡排序应用
- ADO Entities Framework不对多表查询进行优化?
- win系统mysql找回密码
- MySql数据类型分析(银行家舍入法) Part3
- 加动画喽。。有一次我设定动画的时间不管用。就把设置时间的代码位置调整到最开始。然后就好了。...
- IT 工作者如何写交接文档
- 03.NopCommerce功能与特点介绍
- Access violation at address 77106D4E in module 'ntdll.dll'. Write of address 004051A5.
- sip php 来电,php - 如何在Twilio上传递原来的来电显示? (Sip域语音URL配置) - SO中文参考 - www.soinside.com...
- python中怎么统计英文字符的个数_Python之每日一练统计英文文本单词出现的个数、行数、字符数...
- SQL:查找某个班级的人数并按班级人数多少进行排列,查找各班年龄最小的女生的班级号,学号,姓名,出生日期并按班级号升序排列
- 北京铁警的春运日记本:“手机、爷爷、救护车”
- 【机器学习】一张机器学习算法的思维导图
- bugku 细心的大象
- REST API 最佳实践 – REST 端点设计示例
- 怎么把桌面计算机放到快速启动栏,如何设置电脑快速启动?
热门文章
- 去哪编辑html5页面,h5页面 判断网页在哪打开
- 安装 PyCharm
- 用faster-rcnn训练自己的数据集(VOC2007格式,python版)
- 行为型模式:中介者模式
- SQLServer之创建唯一聚集索引
- Emscripten教程之入门指导
- 《Windows Server 2012 Hyper-V虚拟化管理实践》——3.2 Hyper-V主机日常管理
- 搭建Python+Eclipse开发环境
- Javascript基础系列之(五)条件语句(比较操作符)
- Windows Server 2012:服务器虚拟化 学习笔记