Apache ManifoldCF 2.31 Docker Compose 部署指南

使用 Docker Compose 在单机一键部署 Apache ManifoldCF 2.31,自建 OpenJDK 25 基础镜像、持久化 HSQLDB 数据与日志、配置文件外置、up/down 数据留存验证与端口/凭据自检,全部命令与回显实测

Apache ManifoldCFApache ManifoldCF2026/10/11

Apache ManifoldCF 2.31 Docker Compose 部署指南

目标:在一台装有 Docker 与 Docker Compose 的主机上,以容器方式一键部署 Apache ManifoldCF 2.31,实现配置外置、HSQLDB 数据与日志持久化,并通过 down/up 循环验证数据留存。文内 Dockerfile、docker-compose.yml、构建与运行回显、登录与数据持久化验证均逐条实测。

一、环境信息

项目值
宿主机Ubuntu 22.04(x86_64)
Docker Engine29.8.0
Docker Composev5.5.1(docker compose 插件)
基础镜像ubuntu:22.04
Apache ManifoldCF2.31(官方 binary 发行版,444,303,809 字节)
JDKopenjdk-25-jdk-headless(镜像内 apt 安装)
对外端口8345(爬虫 UI / API)
部署目录/opt/data/quzuo/mcf-compose

💡 本篇为容器化部署教程,命令均在 Docker 容器内实测执行;如需在物理服务器直接安装,见《Ubuntu 22.04 安装 Apache ManifoldCF 2.31 指南》。

二、前置条件

安装 Docker 与 Compose 插件后确认版本:

docker info --format '{{.ServerVersion}}'
docker compose version

回显:

29.8.0
Docker Compose version v5.5.1

准备部署目录并下载发行包(推荐清华镜像;官方 dlcdn 直连实测仅约 100KB/s):

mkdir -p /opt/data/quzuo/mcf-compose/conf
cd /opt/data/quzuo/mcf-compose
wget -O apache-manifoldcf-2.31-bin.tar.gz \
  https://mirrors.tuna.tsinghua.edu.cn/apache/manifoldcf/apache-manifoldcf-2.31/apache-manifoldcf-2.31-bin.tar.gz

下载校验文件并核对 sha512(清华镜像不提供 .sha512,实测 404;从 dlcdn 获取):

wget https://dlcdn.apache.org/manifoldcf/apache-manifoldcf-2.31/apache-manifoldcf-2.31-bin.tar.gz.sha512
cat apache-manifoldcf-2.31-bin.tar.gz.sha512
sha512sum apache-manifoldcf-2.31-bin.tar.gz

回显:

apache-manifoldcf-2.31-bin.tar.gz: 6975EA2C 5243E485 21B2259E 3B17297B 93B49CB1
                                   EEAE0E87 24B3BAC6 1A2E1FEF E1038E47 5A3CDE19
                                   0925E883 FBF5172D 327CB7E4 295C30B4 C542958F
                                   ED260B28
6975ea2c5243e48521b2259e3b17297b93b49cb1eeae0e8724b3bac61a2e1fefe1038e475a3cde190925e883fbf5172d327cb7e4295c30b4c542958fed260b28  apache-manifoldcf-2.31-bin.tar.gz

校验一致后,目录最终结构:

/opt/data/quzuo/mcf-compose/
├── apache-manifoldcf-2.31-bin.tar.gz    # 444303809 字节
├── Dockerfile
├── docker-compose.yml
├── conf/
│   └── properties.xml                   # 外置配置(挂载进容器)
├── data/                                # HSQLDB 数据(运行时生成)
└── logs/                                # 运行日志(运行时生成)

💡 Docker Hub 直连被拒的环境需先配置镜像加速(实测回显:dial tcp 205.186.152.122:443: connect: connection refused)。在 /etc/docker/daemon.json 写入:

{"registry-mirrors":["https://docker.1ms.run","https://docker.m.daocloud.io"]}

然后重启 Docker 服务使配置生效。

三、准备镜像构建文件

3.1 Dockerfile

创建 /opt/data/quzuo/mcf-compose/Dockerfile:

FROM ubuntu:22.04

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update \
    && apt-get install -y --no-install-recommends openjdk-25-jdk-headless \
    && rm -rf /var/lib/apt/lists/*

COPY apache-manifoldcf-2.31-bin.tar.gz /opt/

RUN cd /opt \
    && tar xzf apache-manifoldcf-2.31-bin.tar.gz \
    && mv apache-manifoldcf-2.31 manifoldcf-2.31 \
    && rm -f apache-manifoldcf-2.31-bin.tar.gz \
    && find /opt/manifoldcf-2.31 -name "*.sh" -exec chmod +x {} \; \
    && mkdir -p /var/lib/manifoldcf

ENV JAVA_HOME=/usr/lib/jvm/java-25-openjdk-amd64

WORKDIR /opt/manifoldcf-2.31/example

EXPOSE 8345

CMD ["./start-combined.sh"]

要点:

  • ManifoldCF 2.31 class 文件版本 69.0,必须安装 OpenJDK 25,Java 11 启动会报 UnsupportedClassVersionError。
  • find ... -exec chmod +x 修复官方包内 .sh 无执行权限的问题(实测不加会 Permission denied)。
  • WORKDIR 必须是 example/:properties.xml、jetty.xml、启动脚本均按相对路径定位。
  • start-combined.sh 前台启动单个 JVM(UI + authority + API + agents 一体),默认堆 512MB,符合容器内存限制要求。

3.2 外置 properties.xml

创建 /opt/data/quzuo/mcf-compose/conf/properties.xml(在发行包 example/properties.xml 基础上做两处修改:HSQLDB 数据路径指向挂载目录、写入管理员凭据):

<?xml version="1.0" encoding="UTF-8" ?>

<configuration>
  <!-- Version string for UI -->
  <property name="org.apache.manifoldcf.versionstring" value="2.31"/>
  <!-- Point to the wars and configure Jetty -->
  <property name="org.apache.manifoldcf.crawleruiwarpath" value="../web/war/mcf-crawler-ui.war"/>
  <property name="org.apache.manifoldcf.authorityservicewarpath" value="../web/war/mcf-authority-service.war"/>
  <property name="org.apache.manifoldcf.apiservicewarpath" value="../web/war/mcf-api-service.war"/>
  <property name="org.apache.manifoldcf.usejettyparentclassloader" value="true"/>
  <property name="org.apache.manifoldcf.jettyconfigfile" value="./jetty.xml"/>
  <!-- Point to the combined war in case we start the single-process example that way -->
  <property name="org.apache.manifoldcf.combinedwarpath" value="../web/war/mcf-combined-service.war"/>
  <!-- Select HSQLDB as the database implementation, and specify where the database will be stored -->
  <property name="org.apache.manifoldcf.databaseimplementationclass" value="org.apache.manifoldcf.core.database.DBInterfaceHSQLDB"/>
  <property name="org.apache.manifoldcf.hsqldbdatabasepath" value="/var/lib/manifoldcf"/>
  <property name="org.apache.manifoldcf.database.maxhandles" value="100"/>
  <property name="org.apache.manifoldcf.crawler.threads" value="50"/>
  <property name="org.apache.manifoldcf.crawler.historycleanupinterval" value="2592000000"/>
  <!-- Point to a specific logging file -->
  <property name="org.apache.manifoldcf.logconfigfile" value="./logging.xml"/>
  <!-- Specify the connectors to be loaded -->
  <property name="org.apache.manifoldcf.connectorsconfigurationfile" value="../connectors.xml"/>
  <!-- Specify the path to the file resources directory -->
  <property name="org.apache.manifoldcf.fileresources" value="../file-resources"/>
  <!-- Tell MCF where to find the connector jars -->
  <libdir path="../connector-lib"/>
  <libdir path="../connector-common-lib"/>
  <libdir path="../connector-lib-proprietary"/>
  <!-- Login credentials for crawler UI and API -->
  <property name="org.apache.manifoldcf.login.name" value="admin"/>
  <property name="org.apache.manifoldcf.login.password" value="q1w2e3r4"/>
  <property name="org.apache.manifoldcf.apilogin.name" value="admin"/>
  <property name="org.apache.manifoldcf.apilogin.password" value="q1w2e3r4"/>
  <!-- Any additional properties go here -->
</configuration>

与原版相比的修改点:

修改原值新值目的
org.apache.manifoldcf.hsqldbdatabasepath./var/lib/manifoldcf数据落到挂载卷,容器重建不丢
org.apache.manifoldcf.login.name/passwordadmin/admin(默认)admin/q1w2e3r4修改默认 UI 凭据
org.apache.manifoldcf.apilogin.name/password空/空(默认)admin/q1w2e3r4修改默认 API 凭据

3.3 docker-compose.yml

创建 /opt/data/quzuo/mcf-compose/docker-compose.yml:

services:
  manifoldcf:
    build: .
    image: manifoldcf-2.31:latest
    container_name: manifoldcf-231
    restart: unless-stopped
    ports:
      - "8345:8345"
    environment:
      JAVA_HOME: /usr/lib/jvm/java-25-openjdk-amd64
    volumes:
      - ./conf/properties.xml:/opt/manifoldcf-2.31/example/properties.xml
      - ./data:/var/lib/manifoldcf
      - ./logs:/opt/manifoldcf-2.31/example/logs

设计说明:

  • ports 映射 8345,宿主机直接访问 http://<宿主IP>:8345/mcf/。
  • 三条挂载:properties.xml 外置(改配置不用重建镜像)、HSQLDB 数据持久化到 ./data、日志持久化到 ./logs。
  • restart: unless-stopped 保证宿主机重启后服务自动拉起。

四、构建与启动

4.1 构建镜像

cd /opt/data/quzuo/mcf-compose
docker compose build

真实回显(尾部):

#11 unpacking to docker.io/library/manifoldcf-2.31:latest 24.5s done
#12 resolving provenance for metadata file
 Image manifoldcf-2.31:latest Built

查看镜像:

docker images manifoldcf-2.31

回显:

IMAGE                    ID             DISK USAGE   CONTENT SIZE
manifoldcf-2.31:latest   6a989d54616d       2.49GB          1.1GB

4.2 启动服务

docker compose up -d

回显:

 Container manifoldcf-231 Created
 Container manifoldcf-231 Starting
 Container manifoldcf-231 Started

4.3 状态与日志

docker compose ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}"
docker compose logs manifoldcf | tail -3

回显:

NAME             STATUS          PORTS
manifoldcf-231   Up 45 seconds   0.0.0.0:8345->8345/tcp, [::]:8345->8345/tcp
Successfully registered notification connector 'org.apache.manifoldcf.crawler.notifications.rocketchat.RocketChatConnector'
Successfully registered notification connector 'org.apache.manifoldcf.crawler.notifications.email.EmailConnector'
Jetty started.

启动约需 30-40 秒(注册全部连接器),以日志出现 Jetty started. 为就绪标志。

五、验证

5.1 Web 入口与登录

curl -s -o /dev/null -w "%{http_code} -> %{redirect_url}\n" http://localhost:8345/mcf/

回显:

302 -> http://localhost:8345/mcf/login.jsp

使用外置凭据登录(POST 到登录处理页 setupAdminProfile.jsp):

curl -s -c /tmp/cj -o /dev/null -w "login(q1w2e3r4): %{http_code} -> %{redirect_url}\n" \
  -d "userID=admin&password=q1w2e3r4" http://localhost:8345/mcf/setupAdminProfile.jsp
curl -s -o /dev/null -w "login(admin): %{http_code} -> %{redirect_url}\n" \
  -d "userID=admin&password=admin" http://localhost:8345/mcf/setupAdminProfile.jsp

回显:

login(q1w2e3r4): 302 -> http://localhost:8345/mcf/index.jsp
login(admin): 302 -> http://localhost:8345/mcf/login.jsp?loginfailed=true

新凭据登录成功跳转管理台;发行包默认的 admin/admin 被拒绝(进入镜像的 properties.xml 已被挂载替换生效)。

浏览器访问 http://<宿主IP>:8345/mcf/,输入 admin / q1w2e3r4 进入爬虫管理界面。

5.2 持久化目录检查

宿主机查看挂载产物:

ls data/
ls logs/

回显:

dbname.data  dbname.lck  dbname.log  dbname.properties  dbname.script  dbname.tmp
manifoldcf.log

HSQLDB 数据文件与运行日志均已落在宿主目录。

5.3 数据留存端到端验证(down → up)

先通过 API 创建一个输出连接作为"存量数据":

D=http://localhost:8345/mcf/api
curl -s -c /tmp/ac -X POST -H "Content-Type: application/json" \
  -d '{"userID":"admin","password":"q1w2e3r4"}' $D/json/LOGIN
echo
curl -s -b /tmp/ac -X PUT -H "Content-Type: application/json" \
  -d '{"outputconnection":{"description":"Persistence test","configuration":{},"class_name":"org.apache.manifoldcf.agents.output.filesystem.FileOutputConnector","name":"PersistedOutput","max_connections":"100"}}' \
  $D/json/outputconnections/PersistedOutput
echo
curl -s -b /tmp/ac $D/json/outputconnections | head -c 200

回显:

{}
{}
{"outputconnection":{"_children_":[{"_type_":"isnew","_value_":"false"},{"_type_":"name","_value_":"PersistedOutput"},{"_type_":"class_name","_value_":"org.apache.manifoldcf.agents.output.filesystem.FileOutputConnector"},{"_type_":"max_connections","_value_":"100"},{"_type_":"description","_value_":"Persistence test"},{"_type_":"configuration"}]}}

销毁并重建容器:

docker compose down

回显:

 Network mcf-compose_default Removing
 Network mcf-compose_default Removed

确认数据目录未受影响:

ls data/

回显:

dbname.data
dbname.lck
dbname.log
dbname.properties
dbname.script
dbname.tmp

再次启动:

docker compose up -d

回显:

 Container manifoldcf-231 Starting
 Container manifoldcf-231 Started

等待约 40 秒后重新登录并查询:

D=http://localhost:8345/mcf/api
curl -s -c /tmp/ad -X POST -H "Content-Type: application/json" \
  -d '{"userID":"admin","password":"q1w2e3r4"}' $D/json/LOGIN
curl -s -b /tmp/ad $D/json/outputconnections | head -c 300

回显:

{}
{"outputconnection":{"_children_":[{"_type_":"isnew","_value_":"false"},{"_type_":"name","_value_":"PersistedOutput"},{"_type_":"class_name","_value_":"org.apache.manifoldcf.agents.output.filesystem.FileOutputConnector"},{"_type_":"max_connections","_value_":"100"},{"_type_":"description","_value_":"Persistence test"},

PersistedOutput 在容器销毁重建后依然存在(isnew=false),持久化验证通过。容器状态:

docker compose ps --format "{{.Name}} {{.Status}}"

回显:

manifoldcf-231 Up 42 seconds

六、运行维护

  • 启动/停止/重启:docker compose start | stop | restart;配置文件(properties.xml)修改后执行 docker compose restart 生效。
  • 日志:docker compose logs -f manifoldcf 跟踪标准输出;落盘日志在 ./logs/manifoldcf.log。
  • 进入容器排查:docker compose exec manifoldcf bash。
  • 数据备份:直接备份宿主机 ./data/ 目录(HSQLDB 文件),建议先 docker compose stop 再打包。
  • 升级:替换构建上下文中的发行包(如 apache-manifoldcf-2.32-bin.tar.gz)、修改 Dockerfile 与 properties.xml 中版本相关字段后 docker compose build && docker compose up -d,数据因挂载保留。
  • 内存:combined 默认堆 512MB(Dockerfile 内 options 文件未改动),可进入容器修改 example/combined-options.env.unix 后重启生效。

七、常见问题(FAQ)

Q1:docker compose build 报拉取镜像失败?

现象(实测):

failed to resolve source metadata for docker.io/library/ubuntu:22.04:
dial tcp 205.186.152.122:443: connect: connection refused

解决:在 /etc/docker/daemon.json 配置 registry-mirrors(见第二章)并重启 Docker 后重试。

Q2:容器反复重启,日志报 UnsupportedClassVersionError?

基础镜像 JDK 版本低于 25 所致。确保 Dockerfile 使用 openjdk-25-jdk-headless(ManifoldCF 2.31 class 文件版本 69.0),重新 docker compose build。

Q3:start-combined.sh: Permission denied 且容器退出?

官方包内 .sh 无执行位。确认 Dockerfile 中包含:

RUN find /opt/manifoldcf-2.31 -name "*.sh" -exec chmod +x {} \;

Q4:数据没有持久化,down 后配置的连接丢失?

检查 docker-compose.yml 挂载是否齐全:./data:/var/lib/manifoldcf 与外置 conf/properties.xml(其中 hsqldbdatabasepath 必须指向 /var/lib/manifoldcf)。两处任一缺失都会导致数据落在容器可写层而被销毁。

Q5:访问 8345 端口 404?

combined 模式入口是 http://<IP>:8345/mcf/(不是 /mcf-crawler-ui/)。实测:

# curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8345/mcf-crawler-ui/
404
# curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8345/mcf/
302

Q6:启动后立即访问 503/连接被拒?

连接器注册需 30-40 秒,以 docker compose logs 出现 Jetty started. 为准再访问。

八、卸载与清理

cd /opt/data/quzuo/mcf-compose
docker compose down --rmi local

回显(尾部):

 Container manifoldcf-231 Stopping
 Container manifoldcf-231 Stopped
 Container manifoldcf-231 Removing
 Container manifoldcf-231 Removed

如确认不再需要数据,删除数据目录与构建上下文:

rm -rf /opt/data/quzuo/mcf-compose/data /opt/data/quzuo/mcf-compose/logs

九、参考链接