远程调试 tomcat 上的 java web 程序

tomcat / java / web

本文是远程调试 CentOS 系统自带的 tomcat 服务器的第三部分, 这篇文章中我们来配置服务器来远程调试我们的程序

1 前言

很多人可能已经习惯了自己下载安装 tomcat,使用 tomcat 自带的 catalina 查看输出, 在本地调试 tomcat 服务器,但是如果你是在远程服务器上,使用 yum 自带的 tomcat, 这时需要如何调试呢,我们已经搭建好了一台 tomcat 服务器并且部署好了代码,现在让我们来远程调试我们的程序

本文是远程调试 CentOS 系统自带的 tomcat 服务器的第三部分

  1. 安装和配置 tomcat 服务器
  2. 向 tomcat 部署 java web 项目
  3. 远程调试 tomcat 上的 java web 程序

2 使用到的软件

  • VirtualBox 6.0: 用来创建虚拟机
  • Terminal: 这里使用系统自带的 terminal, windows 用户可能需要 xshell, putty 之类的工具
  • IDEA: 用来编写 java web 项目,也可以使用其他 IDE 或编辑器

3 配置

3.1 为 idea 添加远程调试的配置

  • 注意我们这里填的服务器地址是 localhost,因为我们需要用本地的端口映射来转发到服务器地址,如果你的服务器可以直接访问,请填入你的服务器地址
  • 最后鼠标指向的那行配置,后面我们需要作为 jvm 参数配置到服务器

3.2 为虚拟机添加端口转发规则

前面已说明,我们的服务器在 NAT 后,所以需要在 VirtualBox 配置端口转发,把本地 5005 端口,指向虚拟机的 5005 端口,如果你对配置有疑问,请参考本文的第一部分

3.3 修改 tomcat 的 jvm 配置

在第一部分时 我们修改过 tomcat 的 jvm 配置,现在我们要增加调试参数,修改 /usr/share/tomcat/tomcat.conf ,注释之前新增的参数后再增加一行

# 注释第一部分设定的参数
# JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom -Djava.awt.headless=true -Xmx512m -XX:MaxPermSize=256m -XX:+UseConcMarkSweepGC"
# 本次添加的参数,复制之前的参数,然后加入 idea 提示的参数
JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom -Djava.awt.headless=true -Xmx512m -XX:MaxPermSize=256m -XX:+UseConcMarkSweepGC -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"

这样之后如果不需要再加入调试参数,只需要注释掉这次插入的这行配置然后还原原来的配置

3.4 重启 tomcat 时遇到的问题

启用 jvm 的新配置需要重启 tomcat,不过这时如果你尝试重启 tomcat 你会发现 tomcat 再也启动不起来了

tomcat 正常运行时,我们可以这样查看 tomcat 的状态

sudo systemctl status tomcat

正常运行的 tomcat 是 active 的状态

但是如果我们重启 tomcat 后

sudo systemctl restart tomcat

再检查 tomcat 的状态,就会看到 failed 的红字,注意看是绑定端口失败

这是因为 selinux 阻挡了 tomcat 的启动,如果我们的服务器只是用来开发调试使用,那么我们可以用以下命令禁用 selinux ,这样重启 tomcat 就不会有问题

sudo setenforce 0

我们这里采取更合理一些的方案:审计安全规则

3.5 修改安全规则

首先用以下命令安装相关工具

sudo yum install policycoreutils-python -y

使用以下命令来查看 selinux 阻止的内容

sudo audit2allow -w -a

我们可以找到跟 tomcat 绑定 5005 端口的相关内容

由于我们只有一条安全审核记录,所以可以方便地生成规则来允许 tomcat 运行,如果你有很多审核记录,那么你可以指定时间来缩小范围

  • 简单生成规则

    sudo audit2allow -a -M tomcat-rule
    
  • 时间范围内的规则

    ausearch -m AVC --start 01/05/2019 19:52:00 --end 01/05/2019 19:52:59 | audit2allow -a -M tomcat-rule
    

这时会生成两个文件 tomcat-rule.pp 和 tomcat-rule.te,pp 文件是需要导入的规则,te 文件是我们看得懂的格式,所以我们检查一下 te 的内容

cat tomcat-rule.te

module tomcat-rule 1.0;

require {
	type tomcat_t;
	type rtp_media_port_t;
	class tcp_socket name_bind;
}

#============= tomcat_t ==============
allow tomcat_t rtp_media_port_t:tcp_socket name_bind;

看上去只与 tomcat 绑定端口有关,我们可以放心导入

sudo semodule -i tomcat-rule.pp

然后重启 tomcat,tomcat 就可以正确运行了

3.6 放行 5005 端口

我们现在还是不能远程调试,因为 CentOS 防火墙默认不开放所有端口,所以我们需要给 5005 添加例外,这一步跟之前第一部分添加 8080 端口相同

4 调试

现在终于可以调试了,我们用 idea 附加到 tomcat 服务器试一下

有提示成功连上 vm,这样就可以远程调试代码了

5 命令行输出

我们有时候也会使用 System.out.println 这种格式输出到命令行来做简单的跟踪,那么在远程服务器上,我们可以用以下命令来查看

journal -u tomcat

Shift-G 拉到最下面,就找到我们输出的内容啦

6 总结

现在我们终于完成了远程调试 java web 代码的所有工作,内容很多,但是也让我们了解到了在运维部署程序时的基本流程,另外如果你的运行环境恰好也是 CentOS 7 的 tomcat,我觉得构建一个远程调试的开发环境还是有必要的,这样我们调试的环境会更贴合运行的环境