自用 OpenGrok 部署

2024年4月14日 · 910 字 · 5 分钟

最近, 在家有时候需要阅读一下 kernel 的源码.

每次用 VS Code 打开,需要加载好一会儿,还是有点麻烦.

刚好有一台闲置的云服务器, 于是想着部署一套自用的 OpenGrok , 要用的时候也方便.

先网上搜了一下, 大概的部署步骤,看着不是很复杂,估计大概一两个小时能搞完.

先是找了这篇中文的文档,看着比较详细, 估计坑会少一些. 准备参照这篇文章的步骤部署.

https://cloud.tencent.com/developer/article/2069913

OpenGrok_Deploy_Easy_to_Understand

刚开始便发现, 在 Debian 10 上,这个 tomcat8、openjdk8 都没法直接使用 apt 工具安装, apt 默认支持的已经是 tomcat 9 了.

这文档有点老旧了, 估计不太适用. 于是直接找了官方文档.

https://github.com/oracle/opengrok/wiki/How-to-setup-OpenGrok

How-to-setup-OpenGrok

文档开头直接列出了安装条件和要求, 需要特别注意.

  • Java 11 及以上
  • 下载 OpenGrok 的二进制包
  • 安装 universal-ctags
  • Tomcat 10.0 或者更高版本
  • Python 3.9 或者更高版本 (可选项, 仅当需要使用 Python 脚本同步代码库才需要)

我们按照文档, 一步一步来.

Java 11 环境安装

这个 Java 11 的环境, 在我的 Debian 10 上, 直接通过 apt 安装就好:

sudo apt install openjdk-11-jdk

安装完成后, 检查一下版本信息, 确认是 Java 11 .

java-version-check

universal-ctags 安装

安装 ctags . 作用主要是扫描指定的源文件,找出其中所包含的语法元素,并将找到的相关内容记录下来。

必须是 universal—ctags,否则后面建立索引的时候会报错:

严重:Exception running indexer 2
org.opengrok.indexer.index.IndexerException: Didn't find Universal Ctags 3
at org.opengrok.indexer.index.Indexer.prepareIndexer(Indexer.java:888) 4
at org.opengrok.indexer,index.Indexer.main(Indexer.java:298)

一般通过 apt 安装的都是 exuberant-ctags,要注意:

sudo apt-get install tags[TAB]
exuberant-ctags             geany-plugin-ctags             libparse-exuberantctags-perl

如果有 exuberant ctags,则需要先卸载掉,因为这个已经不再维护,后面在进行相关操作会报错。

卸载命令:sudo apt-remove exuberant ctags

源码编译安装 universal-ctags 的命令:

# prepare
sudo apt remove ctags
sudo apt autoremove
sudo apt install autoconf
sudo apt install automake

git clone https://github.com/universal-ctags/ctags.git
cd ctags
./autogen.sh
./configure

make
sudo make install

安装完成后, 使用 ctags –version 查看版本信息

ctags_version

同时使用 whereis ctags 查看安装路径, 后续在建立索引的时候会用到.

可以看到, 我这边是安装到了 /usr/local/bin/ctags 这个路径下了.

ctags-path

Tomcat 安装配置

这部分, 主要参考了这篇文章: https://www.digitalocean.com/community/tutorials/how-to-install-apache-tomcat-10-on-ubuntu-20-04

创建运行 Tomcat 的独立用户

sudo useradd -m -d /opt/tomcat -U -s /bin/false tomcat

  • JDK 环境我们在前面已经安装好了, 这一步可以直接跳过.

下载安装 Tomcat

# 下载安装包
wget https://dlcdn.apache.org/tomcat/tomcat-10/v10.0.20/bin/apache-tomcat-10.0.20.tar.gz

# 解压提取
sudo tar xzvf apache-tomcat-10*tar.gz -C /opt/tomcat --strip-components=1

# 配置文件权限
sudo chown -R tomcat:tomcat /opt/tomcat/
sudo chmod -R u+x /opt/tomcat/bin

创建 systemd 服务

现在创建的 systemd服务,是为了保持 Tomcat 一直在后台运行. 即使是期间出错或者服务器重启了, systemd服务也能自动的拉起 Tomcat.

Tomcat 其实是一个 Java 的应用,所以需要 Java 运行时环境的支持, 就是上面我们安装的 JDK .

在我们创建 systemd服务之前, 我们需要知道 Java 安装到哪个路径了.

用这个命令查询一下:

sudo update-java-alternatives -l

我这台服务器上查到的是

Java-path

接下来, 我们来创建 systeamd 服务.

首先我们把 Tomcat 服务配置, 写到 /etc/systemd/system 目录下一个叫 tomcat.service 的文件

sudo nano /etc/systemd/system/tomcat.service

文件内容如下:

[Unit]
Description=Tomcat
After=network.target

[Service]
Type=forking

User=tomcat
Group=tomcat

Environment="JAVA_HOME=/usr/lib/jvm/java-1.11.0-openjdk-amd64"
Environment="JAVA_OPTS=-Djava.security.egd=file:///dev/urandom"
Environment="CATALINA_BASE=/opt/tomcat"
Environment="CATALINA_HOME=/opt/tomcat"
Environment="CATALINA_PID=/opt/tomcat/temp/tomcat.pid"
Environment="CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC"

ExecStart=/opt/tomcat/bin/startup.sh
ExecStop=/opt/tomcat/bin/shutdown.sh

RestartSec=10
Restart=always

[Install]
WantedBy=multi-user.target

JAVA_HOME 的路径, 设置成先前查询到的路径.

这里, 我们配置的服务, 会通过执行 startup 和 shutdown 脚本, 运行 Tomcat.

这里面还配置了一些环境变量, 包括定义 home 目录( /opt/tomcat 我们安装 tomcat 时候指定的安装路径), CATALINA_OPTS 里面限制 Java 虚拟机的内存占用大小.

一旦出现 fail, Tomcat 服务会自动重启.

配置好之后, 保存并关闭.

重新加载 systemd 守护进程, 以便感知到我们刚刚创建的服务:

sudo systemctl daemon-reload

启动 Tomcat 服务的命令:

sudo systemctl start tomcat

查看 Tomcat 运行状态, 确保服务运行正常:

sudo systemctl status tomcat

这条命令的输出大概是这个样子:

● tomcat.service - Tomcat
   Loaded: loaded (/etc/systemd/system/tomcat.service; enabled; vendor preset: enabled)
   Active: active (running) since Sun 2024-04-14 15:47:57 CST; 2h 52min ago
 Main PID: 4421 (java)
    Tasks: 39 (limit: 2260)
   Memory: 610.7M
   CGroup: /system.slice/tomcat.service
           └─4421 /usr/lib/jvm/java-1.11.0-openjdk-amd64/bin/java -Djava.util.logging.config.file=/opt/tomcat/conf/

q 键退出命令.

最后, 为了确保 Tomcat 服务开机启动, 执行下面这条命令:

sudo systemctl enable tomcat

经过这些步骤, 我们完成了 systemd 服务配置, 使得 Tomcat 可以在后台持续运行.

现在我们可以通过浏览器, 访问我们的 Tomcat 了.

浏览器访问 Tomcat

现在 Tomcat 已经在服务器上运行起来了, 我们再配置防火墙规则, 这样就可以通过 PC 上的浏览器访问了.

Tomcat 默认使用 8080 端口, 接收 HTTP 服务请求.

服务器上执行这条命令, 放通 8080 端口:

sudo ufw allow 8080

注: 如果提示 -bash: ufw: command not found , 大概率是服务器上没有 ufw 防火墙, 直接跳过这一步即可.

在 PC 浏览器上, 我们可以通过 IP+端口 访问 Tomcat:

http://your_server_ip:8080

默认的主页如下:

Tomcat-homepage

注意: 如果上述配置完成之后, PC 浏览器上访问, 提示 “访问被拒绝”或者 404 , 需要检查云服务的安全组规则, 创建一条允许 8080 端口的入方向规则(出方向一般是默认允许所以流量).

security-rule-8080

OpenGrok 安装配置

下载安装包及配置文件目录

https://github.com/oracle/opengrok/releases 下载最新的安装包.

为了保持目录整洁, 我们把所有的文件都保存到 /opengrok 文件夹底下.

我们在这个文件夹底下,创建需要的文件目录:

mkdir /opengrok/{src,data,dist,etc,log}

解压安装包

tar -C /opengrok/dist --strip-components=1 -xzf opengrok-X.Y.Z.tar.gz

log 配置

拷贝 log 配置

cp /opengrok/dist/doc/logging.properties /opengrok/etc

对默认的配置, 做一些修改. 根据我们的目录安排, 我们把所有的 log 都保存到 /opengrok/logs 下.

修改之后, 大概长这样:

handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler

java.util.logging.FileHandler.pattern = /opengrok/log/opengrok%g.%u.log
java.util.logging.FileHandler.append = false
java.util.logging.FileHandler.limit = 0
java.util.logging.FileHandler.count = 30
java.util.logging.FileHandler.level = ALL
java.util.logging.FileHandler.formatter = org.opengrok.indexer.logger.formatter.SimpleFileLogFormatter

java.util.logging.ConsoleHandler.level = WARNING
java.util.logging.ConsoleHandler.formatter = org.opengrok.indexer.logger.formatter.SimpleFileLogFormatter

org.opengrok.level = FINE

这个文件主要是配置了控制台只打印 WARNING 或者更高级别的报错信息, 日志文件只保存 FINE 及以上级别的报错信息.

检查文件权限

现在,需要确保 web 应用程序和索引程序可以读写这些目录.

索引程序需要写入数据到 root 目录( 当前配置下, 即/opengrok/{data,log}), web 应用程序需要从源码根目录, 配置目录, 数据文件目录 (当前配置下, 即 /opengrok/{src,etc,data}) 读取数据.

通常情况, 只有当索引程序与 web 应用程序运行在不同的用户下, 导致创建的数据无法正常互相读取.

同时, web 应用程序需要能写入 data 目录下的 suggester ,(/opengrok/data/suggester 当前配置下), 否则 suggester 没法工作.

创建索引

Step.0 - 放置源码文件

源码文件需要放置到 OpenGrok 本地, 因为索引的过程 I/O 相当大.

源码无需做任何修改就可以索引. 如果代码是 CVS 或者 SVN 管理的, 需要先切到对应的分支.

索引程序假定源码文件的编码为 UTF-8 encoding (ASCII 码也没问题).

我这边直接给放了一个 linux kernel 2.6.12 的代码.

Step.1 - 部署 web 应用程序

Web 应用打包成 WAR 格式分发, 默认名字为 source.war .

WAR 文件是 OpenGrok 安装包的一部分, 位于 lib 目录下. 为了部署 web 应用, 需要把 .war 文件拷贝到 Web 服务应用程序(当前配置下, 即 Tomcat )的指定目录下, 以便服务器程序部署发布 web 应用.

服务器程序通常能检测到目录下的新的文件(即使先前版本 web 应用已经在运行), 并解压发布新的 web 应用. 这通常是 web 服务器程序自动完成的,并不需要手动去解包.

这个服务器程序的指定目录,通常因程序而异. 例如, 在当前的 Tomcat 10 上, 这个目录可能是 /opt/tomcat/webapps/, 然而这个在不同的操作系统上可能有差异.

以当前操作系统上的 Tomcat 10 为例, 需要把 OpenGrok /opt/opengrok/dist/lib/source.war 拷贝到 /opt/tomcat/webapps/ 目录下. 服务器程序会自动解压, 并提取 war 到内容到 /opt/tomcat/webapps/source 目录.

之后, 我们便可以通过 http://ADDRESS:PORT/source/ 访问这个 web 应用, 比如 http://localhost:8080/source.

URI 中的 source 是 WAR 文件的名字, 如果把名为 FooBar.war 的文件拷贝到这个目录, 那么对应的访问入口便是 http://localhost:8080/FooBar/ .

当前访问, 因为索引程序还没有运行建立索引,所以访问 source 应用将会报错, 提示找不到配置文件. 这是在预期之中的, 因为配置文件还没有被索引程序生成.

服务器应用程序解压 WAR 包之后, 它会检索 WEB-INF/web.xml 文件. 举例来说,当前配置下 Debian 10 的 Tomcat, 这个文件路径是 /opt/tomcat/webapps/source/WEB-INF/web.xml

XML 文件中, 有一个参数名为 CONFIGURATION, 在 XML 里面大概是这个位置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app
  xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
         http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  version="3.1"
>
  <display-name>OpenGrok</display-name>
  <description>A wicked fast source browser</description>
  <context-param>
    <description
      >Full path to the configuration file where OpenGrok can read its
      configuration</description
    >
    <param-name>CONFIGURATION</param-name>
    <param-value>/opengrok/etc/configuration.xml</param-value>
  </context-param>
  ...</web-app
>

这里指定了 web 服务器程序读取配置文件的位置.默认的值是 /opengrok/etc/configuration.xml .

这个配置文件, 是由索引程序指定 -W 的时候生成的. web 应用在启动的时候会去读取这个文件, 这就是保持配置文件持久化的方法.

需要注意, web 应用需要能够访问数据目录和源码根目录, 确保文件权限级别配置合理(特别是运行在 SELinux 或者类似环境下的时候).

另外需要注意的是, 为了显出历史视图(例如, 修改的 diff, 显示注释等等), web 应用程序需要能运行代码管理命令, 例如 git , 就像索引程序生成历史 cache 一样. 因此, 服务器应用程序也需要能获取到这些权限和环境变量.

除了 WEB-INF/web.xml 文件之外, 不要修改已经部署或解压的 WAR 包底下的任何文件, 这有可能会中断应用部署.

web 应用程序更多的配置, 可参考 https://github.com/oracle/opengrok/wiki/Webapp-configuration .

Step.2 - 索引

这一步包含的操作如下:

  • 建立索引

  • 让索引程序生成配置文件

  • 通知 web 应用程序新的索引已经生成

用于建立索引的文件目录, 我们已经在之前的步骤中创建好了.

第一次进行索引, 可能会需要花比较多时间, 尤其是那些大型代码库(既指代码量, 也包括代码历史记录), 或许要几个小时.后续的索引将会快很多, 因为是增量操作.

为了运行索引程序, 我们需要安装包中的 opengrok.jar 文件, 以及其目录底下其他库文件的支持.

索引程序可以直接通过下面的命令执行(Universtal ctags 安装到了 /usr/local/bin/ctags ):

java \
    -Djava.util.logging.config.file=/opengrok/etc/logging.properties \
    -jar /opengrok/dist/lib/opengrok.jar \
    -c /usr/local/bin/ctags \
    -s /opengrok/src -d /opengrok/data -H -P -S -G \
    -W /opengrok/etc/configuration.xml -U http://localhost:8080/source

上面的命令, 使用 /opengrok/src 作为源码根目录, /opengrok/data 作为数据根目录. 生成的索引文件将会写入到 /opengrok/etc/configuration.xml 并在索引结束后, 在 web 应用中生效(通过 -U 选项传递的 URL). 命令中配置文件的路径,需要跟 web.xml 中的保持一致 (参考上面部署 web 应用小节).

在索引结束后, 索引程序将自动尝试上传新生成的配置文件到 web 应用. 在此之前, web 应用将展示旧的内容.

索引程序需要知道向哪里上传新的内容, 这便是 -U 选项的作用. 这个选项提供的 URI, 需要与 web 应用部署的位置匹配.举个例子, War 文件的名字是 source.war, 那么 URI 应该是 http://localhost:PORT_NUMBER/source.

下面的命令, 带上 -h 可以获取到更多的选项信息.

java -jar /opengrok/dist/lib/opengrok.jar -h

此外, 在 -h 的基础上, 带上 --detailed 可以得到更多额外的详细帮助信息, 包括一些样例.

索引结束之后, 我们可以用 PC 浏览器打开, http://YOUR_WEBAPP_SERVER:WEBAPPSRV_PORT/source, 便可以舒舒服服 地浏览代码了.

最终的效果如下:

My_OpenGrok

更多的索引选项, 可以参考 https://github.com/oracle/opengrok/wiki/Indexer-configuration.

(End)

Reference