dockerrun–rm-eJAVA_OPTS=’-Xmx512m’tomcat:8
在日志中,大家可以清楚地发现设置已经生效“Commandlineargument:-Xmx512m”
02-Apr-201612:46:26.970INFO[main]org.apache.catalina.startup.VersionLoggerListener.logServerversion:ApacheTomcat/8.0.32
02-Apr-201612:46:26.974INFO[main]org.apache.catalina.startup.VersionLoggerListener.logServerbuilt:Feb2201619:34:53UTC
02-Apr-201612:46:26.975INFO[main]org.apache.catalina.startup.VersionLoggerListener.logServernumber:8.0.32.0
02-Apr-201612:46:26.975INFO[main]org.apache.catalina.startup.VersionLoggerListener.logOSName:Linux
02-Apr-201612:46:26.975INFO[main]org.apache.catalina.startup.VersionLoggerListener.logOSVersion:4.1.19-boot2docker
02-Apr-201612:46:26.975INFO[main]org.apache.catalina.startup.VersionLoggerListener.logArchitecture:amd64
02-Apr-201612:46:26.975INFO[main]org.apache.catalina.startup.VersionLoggerListener.logJavaHome:/usr/lib/jvm/java-7-openjdk-amd64/jre
02-Apr-201612:46:26.976INFO[main]org.apache.catalina.startup.VersionLoggerListener.logJVMVersion:1.7.0_95-b00
02-Apr-201612:46:26.976INFO[main]org.apache.catalina.startup.VersionLoggerListener.logJVMVendor:OracleCorporation
02-Apr-201612:46:26.977INFO[main]org.apache.catalina.startup.VersionLoggerListener.logCATALINA_BASE:/usr/local/tomcat
02-Apr-201612:46:26.977INFO[main]org.apache.catalina.startup.VersionLoggerListener.logCATALINA_HOME:/usr/local/tomcat
02-Apr-201612:46:26.978INFO[main]org.apache.catalina.startup.VersionLoggerListener.logCommandlineargument:-Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties
02-Apr-201612:46:26.978INFO[main]org.apache.catalina.startup.VersionLoggerListener.logCommandlineargument:-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
02-Apr-201612:46:26.978INFO[main]org.apache.catalina.startup.VersionLoggerListener.logCommandlineargument:-Xmx512m
…
然而在Docker集群上部署运行Java容器应用的时候,仅仅对JVM的heap参数设置是不够的,大家还需要对Docker容器的内存资源进行限制:
1.限制容器使用的内存的最大量,防止对系统或其他应用造成伤害
2.能够将Docker容器调度到拥有足够空余的内存的节点,从而保证应用的所需运行资源
关于容器的资源分配约束,Docker提供了相应的启动参数
对内存而言,最基本的就是通过-m参数来约束容器使用内存的大小
-m,–memory=””
Memorylimit(format:<number>[<unit>]).Numberisapositiveinteger.Unitcanbeoneofb,k,m,org.Minimumis4M.
那么问题就来了,为了正确设置Docker容器内存的大小,难道大家需要同时传递容器的内存限制和JAVA_OPTS环境变量吗?如下所示:
dockerrun–rm-m512m-eJAVA_OPTS=’-Xmx512m’tomcat:8
这个方法有两个问题
1.需要管理员保证容器内存和JVM内存设置匹配,否则可能引发错误
2.当对容器内存限制调整时,环境变量也需要重新设定,这就需要重建一个新的容器
是否有一个方法,可以让容器内部的JVM自动适配容器的内存限制?这样可以采用更加统一的方法来进行资源管理,简化配置工作。
大家知道Docker是通过CGroup来实现资源约束的,自从1.7版本之后,Docker把容器的localcgroups以只读方式挂载到容器内部的文件系统上,这样大家就可以在容器内部,通过cgroups信息来获取系统对当前容器的资源限制了。
偶创建了一个示例镜像registry.aliyuncs.com/denverdino/tomcat:8-autoheap
,其源代码可以从Github获得。它基于Docker官方Tomcat镜像创建,它的启动脚本会检查CGroup中内存限置,并计算JVM最大Heapsize来传递给Tomcat。其代码如下
#!/bin/bash
limit_in_bytes=$(cat/sys/fs/cgroup/memory/memory.limit_in_bytes)
#Ifnotdefaultlimit_in_bytesincgroup
if[“$limit_in_bytes”-ne”9223372036854771712″]
then
limit_in_megabytes=$(expr$limit_in_bytes\/1048576)
heap_size=$(expr$limit_in_megabytes-$RESERVED_MEGABYTES)
exportJAVA_OPTS=”-Xmx${heap_size}m$JAVA_OPTS”
echoJAVA_OPTS=$JAVA_OPTS
fi
execcatalina.shrun
说明:
为了监控,故障排查等场景,大家预留了部分内存(缺省64M),其余容器内存大家都分配给JVM的堆。
这里没有对边界情况做进一步处理。在生产系统中需要根据情况做相应的设定,比如最大的堆大小等等。
现在大家启动一个tomcat运行在512兆的容器中
dockerrun-d–nametest-m512mregistry.aliyuncs.com/denverdino/tomcat:8-autoheap
通过下列命令,从日志中大家可以检测到相应的JVM参数已经被设置成448MB(512-64)
dockerlogstest
…
02-Apr-201614:18:09.870INFO[main]org.apache.catalina.startup.VersionLoggerListener.logCommandlineargument:-Xmx448m
…
大家也可以方便的调整Java应用的内存.
Docker1.10提供了对容器资源限制的动态修改能力。但是由于JVM无法感知容器资源修改,大家依然需要重启tomcat来变更JVM的内存设置,例如,大家可以通过下面命令把容器内存限制调整到1GB
dockerupdate-m1024mtest
dockerrestarttest
再次检查日志,相应的JVMHeapSize最大值已被设置为960MB
dockerlogstest
…
02-Apr-201614:21:07.644INFO[main]org.apache.catalina.startup.VersionLoggerListener.logCommandlineargument:-Xmx960m