概述
很多生产环境都非常需要以下特性:在无需关闭或重启整个容器的情况下,部署新的 Web 应用或者取消对现有应用的部署。或者,即便在 Tomcat 服务器配置文件中没有指定 reloadable 的情况下,也可以请求重新加载现有应用。
Tomcat 中的 Web 应用 Manager 就是来解决这些问题的,它默认安装在上下文路径:/manager 中,支持以下功能:
用已上传的 WAR 文件内容部署新的 Web 应用。
在服务器文件系统中指定上下文路径处部署新的 Web 应用。
列出当前已部署的 Web 应用,以及这些应用目前的活跃会话。
重新加载现有的 Web 应用,以便响应
/WEB-INF/classes
或/WEB-INF/lib
中内容的更改。列出操作系统及 JVM 的属性值。
列出可用的全局 JNDI 资源,它们将用于预备
<ResourceLink>
元素的部署工具中。<ResourceLink>
元素内嵌于<Context>
部署描述中。开启一个已停止的 Web 应用,从而使其再次可用。
停止一个现有的 Web 应用,从而使其不可用,但并不取消对它的部署。
取消对一个已部署 Web 应用的部署,删除它的文档库目录(除非它是从文件系统中部署的)。
Tomcat 默认安装已经包含了 Manager。 将一个 Manager 应用实例的 Context 添加到一个新的主机中,manager.xml 上下文配置文件应放在 $CATALINA_BASE/conf/[enginename]/[hostname] 文件夹中。如下所示:
<Context privileged="true" antiResourceLocking="false" docBase="${catalina.home}/webapps/manager"> <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="127\.0\.0\.1" /> </Context>
如果将 Tomcat 配置成能够支持多个虚拟主机(网站),则需要对每个虚拟主机配置一个 Manager。
Manager 应用的使用方式有以下三种:
作为带有用户界面的应用,在浏览器中运行。在随后这个范例 URL 中,你可以将
localhost
替换为你的网站主机名称:http://localhost:8080/manager/html
。只使用 HTTP 请求的一个功能最少的版本。它适合系统管理员通过创建脚本来进行使用。将命令指定在请求的 URI 中,响应是简单格式的文本(易于解析与处理)。详情查看 利用 Ant 执行 Manager 命令。
配置 Manager 应用访问
下文的描述将使用变量名 $CATALINA_BASE 来指代工作目录。如果你还没有为多个 Tomcat 实例设置 CATALINA_BASE 目录,那么 $CATALINA_BASE 就将被设置为 $CATALINA_HOME(Tomcat 的安装目录)的值。
Tomcat 以默认值运行是非常危险的,因为这能让互联网上的任何人都可以在你的服务器上执行 Manager 应用。因此,Manager 应用要求任何用户在使用前必须验证自己的身份,提供自己的用户名和密码,以及相应配置的 manager-** 角色(角色名称根据所需的功能而定)。另外,默认用户文件($CATALINA_BASE/conf/tomcat-users.xml)中的用户名称都没有指定角色名称,所以默认是不能访问 Manager 应用的。
这些角色名称位于 Manager 应用的 web.xml 文件中。可用的角色包括:
manager-gui 能够访问 HTML 界面。
manager-status 只能访问“服务器状态”(Server Status)页面。
manager-script 能够访问文档中描述的适用于工具的纯文本界面,以及“服务器状态”页面。
manager-jmx 能够访问 JMX 代理界面以及“服务器状态”(Server Status)页面。
HTML 界面不会遭受 CSRF(Cross-Site Request Forgery,跨站请求伪造)攻击,但纯文本界面及 JMX 界面却有可能无法幸免。这意味着,如果用户能够访问纯文本界面及 JMX 界面,那么在利用 Web 浏览器去访问 Manager 应用时,必须要万分谨慎。要想保持对 CSRF 免疫,则必须:
在使用 Web 浏览器访问 Manager 应用时,假如用户具有 manager-script 或 manager-jmx 角色(比如为了测试纯文本界面或 JMX 界面),那么必须关闭所有的浏览器窗口,终止会话。如果不关闭浏览器,访问了其他站点,就可能会遭受 CSRF 攻击。
建议永远不要将 manager-script 或 manager-jmx 角色授予那些拥有 manager-gui 角色的用户。
注意 JMX 代理界面是 Tomcat 中非常高效的底层、类似于根级别的管理界面。如果用户知道了该调用的命令,就能实现大量行为,所以一定不要轻易授予用户 manager-jmx 角色。
为了能够访问 Manager 应用,必须创建一个新的用户名/密码组合,并为之授予一种 manager-** 角色,或者把一种 manager-** 角色授予现有的用户名/密码组合。因为本文档的大部分内容都在描述纯文本界面的命令,所以为了将来讨论实例方便起见,把角色名称定为 manager-script。而涉及到具体如何配置用户名及密码,则是跟你所使用的Realm 实现有关:
UserDatabaseRealm 加上 MemoryUserDatabase 或 MemoryRealm——UserDatabaseRealm 和 MemoryUserDatabase 配置在默认的
$CATALINA_BASE/conf/server.xml
文件中。MemoryUserDatabase 和 MemoryRealm 都会读取储存在CATALINA_BASE/conf/tomcat-users.xml
里的 XML 格式文件,它可以用任何文本编辑器进行编辑。该文件会为每个用户定义一个 XML 格式的<user>
,如下所示:<user username="craigmcc" password="secret" roles="standard,manager-script" />
它定义了用户登录时所用的用户名和密码,以及他或她采用的角色名称。你可以把 manager-script 角色添加到由逗号分隔的
roles
属性中,从而将该角色赋予一个或多个用户,也可以利用指定角色来创建新的用户。DataSourceRealm 或 JDBCRealm——用户和角色信息都存储在一个经由 JDBC 访问的数据库中。按照当前环境的标准流程,将 manager-script 角色赋予一个或多个用户,或者利用该角色创建一个或多个新用户。
JNDIRealm——你的用户和角色信息被存储在经由 LDAP 访问的一个目录服务器中。按照当前环境的标准流程,为一个或更多的现有用户添加 manager-script 角色,和(/或)利用指定角色创建一个或更多的新用户。
在下一节,当你第一次尝试使用 Manager 的一个命令时,将会使用基本验证进行登录。用户名和密码的具体内容并不重要,只要它们能够证明,用户数据库中拥有 manager-script 角色的用户是有效用户,我们的目的就达到了。
除了密码限制访问之外,Manager 还可以配置 RemoteAddrValve 和 RemoteHostValve 这两个参数,分别通过 远程 IP 地址 或远程主机名来进行限制访问。详情可查看 Valve 文档。下列范例是通过 IP 地址来限制访问本地主机:
<Context privileged="true"> <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="127\.0\.0\.1"/> </Context>
易用的 HTML 界面
Manager 应用易用的 HTML 界面位于:
http://{host}:{port}/manager/html
正像前面讲过的那样,需要被授予 manager-gui 角色才能访问它。关于这个界面,还有一个独立的文档,请访问以下页面:
HTML 界面可免受 CSRF(跨站请求伪造)攻击。对 HTML 页面的每次访问都会生成一个随机令牌,存储在会话中,包含在页面的所有链接中。如果你的下一个操作没有正确的令牌值,操作就会被拒绝。如果令牌过期,可以从主页或者 Manager 的 List Applications(列出的应用)页面重新开始。
Manager 支持的命令
Manager 应用能够处理的命令都是通过下面这样的请求 URL 来指定的:
http://{host}:{port}/manager/text/{command}?{parameters}
{host} 和 {port} 分别代表运行 Tomcat 服务器所在的主机名和端口号。{command} 代表所要执行的 Manager 命令。{parameters} 代表该命令所专有的查询参数。在后面的实例中,可以为你的安装自定义适当的主机和端口。
这些命令通常是被 HTTP GET 请求执行的。/deploy 命令有一种能够被 HTTP PUT 请求所执行的形式。
常见参数
多数 Manager 命令都能够接受一个或多个查询参数,这些查询参数如下所示:
path 要处理的 Web 应用的上下文路径(包含前面的斜杠)。要想选择 ROOT Web 应用,指定
/
即可。注意:无法对 Manager 应用自身执行管理命令。version StoreConfigLifecycleListener来配置。
如果命令不能成功执行,响应将以
FAIL
开头,并包含一个错误消息。服务器状态
可从下面这些链接中观察有关服务器的状态信息。任何一个 manager-** 角色都能访问这一页面。
http://localhost:8080/manager/status
http://localhost:8080/manager/status/all上面是用 HTML 格式显示服务器状态信息的命令。
http://localhost:8080/manager/status?XML=true
http://localhost:8080/manager/status/all?XML=true上面是用 XML 格式显示服务器状态信息的命令。
首先,显示的是服务器和 JVM 的版本号、JVM 提供者、操作系统的名称及其版本号,然后还显示了系统体系架构类型。
其次,显示的是关于 JVM 的内存使用信息。
最后,显示的是关于 Tomcat AJP 和 HTTP 连接器的信息。对两者来说,这些信息都很有用:
使用
/status/all
命令可查看每一个已配置 Web 应用的额外信息。使用 JMX 代理 Servlet
什么是 JMX 代理 Servlet
JMX 代理 Servlet 是一款轻量级的代理。它的用途对用户来说并不是特别友好,但是其 UI 却非常有助于整合命令行脚本,从便于监控和改变 Tomcat 的内部运行。通过这个代理,我们可以获取和设置信息。要想真正了解 JMX 代理 Servlet,首先应该大概了解 JMX。如果不知道 JMX 的基本原理,那有些内容就很难理解了。
JMX 查询命令
JMX 的查询命令格式如下所示:
http://webserver/manager/jmxproxy/?qry=STUFF
STUFF
是所要执行的 JMX 查询。比如,可以执行以下这些查询:需要实际地试验一下才能真正理解这些功能。如果没有提供
qry
参数,则将显示全部的 MBean。我们强烈建议你去阅读 Tomcat 源代码,真正了解 JMX 规范,更好地掌握所有能够执行的查询。JMX 的
get
命令JMXProxyServlet 还支持一种
get
命令来获取特定 MBean的属性值。该命令的一般格式如下所示:http://webserver/manager/jmxproxy/?get=BEANNAME&att=MYATTRIBUTE&key=MYKEY
必须提供如下参数:
如果命令成功执行,则一切正常,否则就会返回一个出错消息。举两个例子,比如当希望获取当前的堆内存数据时,可以采用如下命令:
http://webserver/manager/jmxproxy/?get=java.lang:type=Memory&att=HeapMemoryUsage
再或者,如果只希望获取“用过的”键,可以采用如下命令:
http://webserver/manager/jmxproxy/?get=java.lang:type=Memory&att=HeapMemoryUsage&key=used
JMX 的
set
命令上面介绍了如何查询一个 MBean。下面来看看 Tomcat 的内部运行吧!
set
命令的一般格式为:http://webserver/manager/jmxproxy/?set=BEANNAME&att=MYATTRIBUTE&val=NEWVALUE
需要提供三个请求参数:
如果命令成功执行,则一切正常,否则就会返回一个出错消息。比如,假如想为
ErrorReportValve
进行立即调试,可以将属性debug
设为 10:http://localhost:8080/manager/jmxproxy/
?set=Catalina%3Atype%3DValve%2Cname%3DErrorReportValve%2Chost%3Dlocalhost
&att=debug&val=10所得结果如下(你的有可能不同):
Result: ok
下面来看看如果传入一个不恰当数值时的情况,比如使用一个URL,并试图将属性 debug 设置为 'cow'。
http://localhost:8080/manager/jmxproxy/
?set=Catalina%3Atype%3DValve%2Cname%3DErrorReportValve%2Chost%3Dlocalhost
&att=debug&val=cow运行结果如下:
Error: java.lang.NumberFormatException: For input string: "cow"
JMX 的
invoke
命令使用
invoke
命令,我们就可以在 MBean 中调用方法。该命令的一般格式为:http://webserver/manager/jmxproxy/
?invoke=BEANNAME&op=METHODNAME&ps=COMMASEPARATEDPARAMETERS比如,使用如下方式来调用 Service 的
findConnectors()
方法:http://localhost:8080/manager/jmxproxy/
?invoke=Catalina%3Atype%3DService&op=findConnectors&ps=利用 Ant 执行 Manager 的命令
上面的文档介绍了如何利用 HTTP 请求来执行 Manager 的命令。除此之外,Tomcat 还专为 Ant(1.4 版或更新版本)构建工具准备了一套方便的任务定义。为了使用这些命令,必须执行下面这些操作:
为了在 Ant 中使用自定义任务,必须首先用
<taskdef>
元素来声明它们,因而build.xml
文件应类似如下这样:<project name="My Application" default="compile" basedir=".">
<!-- Configure the directory into which the web application is built -->
<property name="build" value="${basedir}/build"/>
<!-- Configure the context path for this application -->
<property name="path" value="/myapp"/>
<!-- Configure properties to access the Manager application -->
<property name="url" value="http://localhost:8080/manager/text"/>
<property name="username" value="myusername"/>
<property name="password" value="mypassword"/>
<!-- Configure the custom Ant tasks for the Manager application -->
<taskdef name="list" classname="org.apache.catalina.ant.ListTask"/>
<taskdef name="deploy" classname="org.apache.catalina.ant.DeployTask"/>
<taskdef name="start" classname="org.apache.catalina.ant.StartTask"/>
<taskdef name="reload" classname="org.apache.catalina.ant.ReloadTask"/>
<taskdef name="stop" classname="org.apache.catalina.ant.StopTask"/>
<taskdef name="undeploy" classname="org.apache.catalina.ant.UndeployTask"/>
<taskdef name="resources" classname="org.apache.catalina.ant.ResourcesTask"/>
<typedef name="sessions" classname="org.apache.catalina.ant.SessionsTask"/>
<taskdef name="findleaks" classname="org.apache.catalina.ant.FindLeaksTask"/>
<typedef name="vminfo" classname="org.apache.catalina.ant.VminfoTask"/>
<typedef name="threaddump" classname="org.apache.catalina.ant.ThreaddumpTask"/>
<typedef name="sslConnectorCiphers" classname="org.apache.catalina.ant.SslConnectorCiphersTask"/>
<!-- Executable Targets -->
<target name="compile" description="Compile web application">
<!-- ... construct web application in ${build} subdirectory, and
generated a ${path}.war ... -->
</target>
<target name="deploy" description="Install web application"
depends="compile">
<deploy url="${url}" username="${username}" password="${password}"
path="${path}" war="file:${build}${path}.war"/>
</target>
<target name="reload" description="Reload web application"
depends="compile">
<reload url="${url}" username="${username}" password="${password}"
path="${path}"/>
</target>
<target name="undeploy" description="Remove web application">
<undeploy url="${url}" username="${username}" password="${password}"
path="${path}"/>
</target>
</project>注意:上面的资源任务定义将覆盖 Ant 1.7 中所添加的资源数据类型。如果你希望使用这些资源数据类型,需要使用 Ant 命名空间支持,将 Tomcat 的任务分配到它们自己的命名空间中。
现在,可以执行类似
ant deploy
这样的命令将应用部署到 Tomcat 的一个运行实例上,或者利用ant reload
通知 Tomcat 重新加载应用。另外还需注意的是,在这个build.xml
文件中,多数比较有价值的属性值都是可以被可替换的,因而可以利用命令行方式来重写这些值。比如,考虑到在build.xml
文件中包含真正的管理员密码是非常危险的,可以通过一些命令来忽略密码属性,如下所示:ant -Dpassword=secret deploy
下载 Ant 二进制分发包,地址为:http://ant.apache.org。必须使用 1.4 版本或更新版本。
将分发包安装到合适的目录中(下面将把它叫做 ANT_HOME)。
将文件
server/lib/catalina-ant.jar
从 Tomcat 安装目录中复制到 Ant 的库目录($ANT_HOME/lib
)。将
$ANT_HOME/bin
目录添加到环境变量PATH
中。在 Tomcat 用户数据库中,至少配置一个拥有
manager-script
角色的用户名/密码组合数据。set
:完整的 bean 名称。att
:想要改变的属性。val
:新的属性值。qry=*%3Atype%3DRequestProcessor%2C* --> type=RequestProcessor
定位所有能够处理请求并汇报各自状态的 Worker。qry=*%3Aj2eeType=Servlet%2c* --> j2eeType=Servlet
查询返回所有加载的 Servlet。qry=Catalina%3Atype%3DEnvironment%2Cresourcetype%3DGlobal%2Cname%3DsimpleValue --> Catalina:type=Environment,resourcetype=Global,name=simpleValue
按照指定名称查找 MBean。解析及准备请求 将对请求报头进行解析,或进行必要的准备,以便读取请求主体(如果指定了传输编码)。
服务 线程处理请求并生成响应。该阶段中至少有一个线程(可查看服务器状态页)。
完成 请求处理结束。所有仍在输出缓冲区中的剩余响应都被传送至客户端。如果有必要保持连接活跃,则下一个阶段是“持续活跃”阶段,否则接下来直接进入“就绪”阶段。
持续活跃 当客户端发送另一请求时,线程能使连接对客户端保持开放。如果接收到另一请求,下一阶段就将是“解析及准备请求”阶段。如果持续活跃超时结束,仍没有接收到请求,则连接关闭,进入下一阶段“就绪”阶段。
就绪 线程空闲,等待再此被使用。
线程信息:最大线程数、最少及最多的空闲线程数、当前线程数量以及当前繁忙线程。
请求信息:最长及最短的处理时间、请求和错误的数量,以及接受和发送的字节数量。
一张完整显示线程阶段、时间、发送字节数、接受字节数、客户端、虚拟主机及请求的表。它将列出所有现有线程。下面列出了所有可能的线程阶段:
get
:MBean 的完整名称。att
:希望获取的属性。key
:(可选参数)CompositeData MBean 的属性中的键。
任务输出捕获
使用 Ant 1.6.2 版或更新版本,Catalina 任务提供选项,利用属性或外部文件捕获输出。它们直接支持 <redirector> 类型属性的子集:
属性 | 属性说明 | 是否必需 |
---|---|---|
output | 输出文件名。如果错误流没有重定向到一个文件或属性上,它将出现在输出中。 | 否 |
error | 命令的标准错误应该被重定向到的文件。 | 否 |
logError | 用于在 Ant 日志中显示错误输出,将输出重定向至某个文件或属性。错误输出不会包含在输出文件或属性中。如果利用 error 或 errorProperty 属性重定向错误,则没有任何效果。 | 否 |
append | 输出和错误文件是否应该附加或覆盖。默认为 false 。 | 否 |
createemptyfiles | 是否应该创建输出和错误文件,哪怕是空的文件。默认为 true 。 | 否 |
outputproperty | 用于保存命令输出的属性名。除非错误流被重定向至单独的文件或流,否则这一属性将包含错误输出。 | 否 |
errorproperty | 用于保存命令标准错误的属性名。 | 否 |
还可以指定其他一些额外属性:
属性 | 属性说明 | 是否必需 |
---|---|---|
alwaysLog | 该属性用于查看捕获的输出,这个输出也出现在 Ant 日志中。除非捕获任务输出,否则千万不要使用它。默认为 false 。Ant 1.6.3 通过 <redirector> 直接支持该属性。 | 否 |
failonerror | 用于避免因为 manager 命令处理中错误而导致 Ant 执行终止情况的发生。默认为 true 。如果希望捕获错误输出,则必须设为false ,否则 Ant 执行将有可能在未捕获任何输出前就被终止。该属性只用于 manager 命令的执行上,任何错误的或丢失的命令属性仍然会导致 Ant 执行终止。 | 否 |
它们还支持内嵌的 <redirector> 元素,你可以在这些元素中指定全套的属性。但对于input、inputstring、inputencoding,即使接收,也无法使用,因为在这种上下文中它们没有任何意义。详情可参考 Ant 手册以了解 <redirector> 元素的各个属性。
下面这个范例摘录了一段构建文件,展示了这种对输出重定向的支持是如何运作的。
<target name="manager.deploy" depends="context.status" if="context.notInstalled"> <deploy url="${mgr.url}" username="${mgr.username}" password="${mgr.password}" path="${mgr.context.path}" config="${mgr.context.descriptor}"/> </target> <target name="manager.deploy.war" depends="context.status" if="context.deployable"> <deploy url="${mgr.url}" username="${mgr.username}" password="${mgr.password}" update="${mgr.update}" path="${mgr.context.path}" war="${mgr.war.file}"/> </target> <target name="context.status"> <property name="running" value="${mgr.context.path}:running"/> <property name="stopped" value="${mgr.context.path}:stopped"/> <list url="${mgr.url}" outputproperty="ctx.status" username="${mgr.username}" password="${mgr.password}"> </list> <condition property="context.running"> <contains string="${ctx.status}" substring="${running}"/> </condition> <condition property="context.stopped"> <contains string="${ctx.status}" substring="${stopped}"/> </condition> <condition property="context.notInstalled"> <and> <isfalse value="${context.running}"/> <isfalse value="${context.stopped}"/> </and> </condition> <condition property="context.deployable"> <or> <istrue value="${context.notInstalled}"/> <and> <istrue value="${context.running}"/> <istrue value="${mgr.update}"/> </and> <and> <istrue value="${context.stopped}"/> <istrue value="${mgr.update}"/> </and> </or> </condition> <condition property="context.undeployable"> <or> <istrue value="${context.running}"/> <istrue value="${context.stopped}"/> </or> </condition> </target>
警告:多次调用 Catalina 任务往往并不是一个好主意,退一步说这样做的意义也不是很大。如果 Ant 任务依赖链设定糟糕的话,即使本意并非如此,也会导致在一次 Ant 运行中多次运行任务。必须提前对你稍加警告,因为有可能当你从任务中捕获输出时,会出现一些意想不到的情况:
当用属性捕获时,你将只能从其中找到最初调用的输出,因为 Ant 属性是不变的,一旦设定就无法改变。
当用文件捕获时,你将只能从其中找到最后调用的输出,除非使用 append = "true" 属性——在这种情况下,你将看到附加在文件内容末尾的每一个任务调用的相关输出。
感觉本站内容不错,读后有收获?小额赞助,鼓励网站分享出更好的教程