Apache Roller Docker Compose 部署指南

使用 Docker Compose 编排 Apache Roller 6.1.3 与 MariaDB 10.6 双服务,基于 tomcat:9-jre11 自建镜像注入 JDBC 配置与 JavaMail 包,MariaDB 初始化自动建表,端口映射与数据持久化,docker compose 全流程命令与回显均实测

Apache RollerApache Roller2026/10/12

Apache Roller Docker Compose 部署指南

目标:使用 Docker Compose 一键编排 Apache Roller 6.1.3(Tomcat 9 + 自建镜像)与 MariaDB 10.6 双服务,数据库初始化自动导入建表脚本,Roller 首页 200 可访问、可注册登录,实现从零到一的容器化博客部署。全程命令与回显均为实际执行结果(Docker Compose v5.5.1 实测)。

一、环境信息

  • Docker:24.x(本指南实测环境)
  • Docker Compose:v5.5.1(docker compose 子命令)
  • Roller 镜像:自建 roller-webapp:6.1.3(基于 tomcat:9-jre11,内含 Roller 6.1.3 + MySQL Connector/J 8.0.33 + JavaMail 1.6.2)
  • 数据库镜像:mariadb:10.6(实测启动版本 10.6.28-MariaDB-ubu2204)
  • 服务名:roller、db;容器名:roller-tomcat、roller-mariadb
  • 映射端口:宿主机 8081 → roller 服务内 8080(若宿主 8080 空闲可直接用 8080:8080)
  • 数据目录:./data/db → MariaDB 数据、./data/roller → /roller-data(索引与媒体文件)
  • 配置目录:./conf/createdb.sql → MariaDB 首次初始化自动建表
  • 站长账号:admin / q1w2e3r4

二、镜像选型说明

镜像说明
tomcat:9-jre11 + 自建本指南采用。官方 Tomcat 基础镜像,Dockerfile 内下载 Roller 发行包并补齐 JDBC 驱动、JavaMail,可控且离线可复现
mariadb:10.6官方 MariaDB 镜像,兼容 MySQL 5.7 协议,支持 docker-entrypoint-initdb.d 首次初始化自动执行 SQL
apache/roller(Docker Hub 社区镜像)无官方维护镜像,社区镜像版本陈旧且配置方式各异,不推荐生产使用

💡 Roller 发行包只有 WAR:JDBC 驱动与 JavaMail 都不在包内,无论哪种镜像方案都必须补齐这两个依赖,否则应用无法连库或菜单页报 ClassNotFoundException: javax.mail。

三、前置条件

  • 装有 Docker 与 Docker Compose v2+ 的服务器,root 权限。
  • 构建镜像阶段需要访问 archive.apache.org(Roller 发行包约 56MB)与 Maven 中央仓库(3 个 jar)。
  • 宿主机 8080/8081 端口未被占用(被占用时改映射,见 4.3 节说明)。

四、部署步骤

4.1 创建目录结构

mkdir -p roller-compose/conf roller-compose/data/db roller-compose/data/roller
cd roller-compose

4.2 编写自建镜像的 Dockerfile

cat > Dockerfile <<'EOF'
FROM tomcat:9-jre11

# 安装下载工具
RUN apt-get update -qq && apt-get install -y -qq unzip curl && rm -rf /var/lib/apt/lists/*

# 下载并解压 Apache Roller 6.1.3,WAR 部署到 webapps
RUN cd /tmp \
    && curl -fSL -o roller.zip https://archive.apache.org/dist/roller/roller-6.1/v6.1.3/apache-roller-6.1.3-binary.zip \
    && unzip -q roller.zip \
    && cp apache-roller-6.1.3/webapp/roller.war /usr/local/tomcat/webapps/roller.war \
    && rm -rf roller.zip apache-roller-6.1.3

# JDBC 驱动与 JavaMail(Roller WAR 未捆绑,需放入 Tomcat 共享 lib)
RUN cd /usr/local/tomcat/lib \
    && curl -fSL -o mysql-connector-j-8.0.33.jar https://repo1.maven.org/maven2/com/mysql/mysql-connector-j/8.0.33/mysql-connector-j-8.0.33.jar \
    && curl -fSL -o javax.mail-1.6.2.jar https://repo1.maven.org/maven2/com/sun/mail/javax.mail/1.6.2/javax.mail-1.6.2.jar \
    && curl -fSL -o javax.activation-1.2.0.jar https://repo1.maven.org/maven2/com/sun/activation/javax.activation/1.2.0/javax.activation-1.2.0.jar

# Roller 自定义配置(JDBC 指向 compose 服务名 db)与数据目录
COPY roller-custom.properties /usr/local/tomcat/lib/roller-custom.properties
RUN mkdir -p /roller-data/search-index /roller-data/mediafiles

EXPOSE 8080
EOF

💡 /usr/local/tomcat/lib 是官方 Tomcat 镜像的共享类路径(等价于 Ubuntu 的 /var/lib/tomcat9/lib),roller-custom.properties 与 3 个 jar 放这里即可被 Roller 读到。

4.3 编写 roller-custom.properties

cat > roller-custom.properties <<'EOF'
database.configurationType=jdbc
database.jdbc.driverClass=com.mysql.cj.jdbc.Driver
database.jdbc.connectionURL=jdbc:mysql://db:3306/rollerdb?autoReconnect=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC
database.jdbc.username=roller
database.jdbc.password=q1w2e3r4
hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
search.index.dir=/roller-data/search-index
mediafile.storage.dir=/roller-data/mediafiles
EOF

connectionURL 中主机名 db 是 compose 服务名,由 compose 内置 DNS 解析,不要写死 IP。

4.4 编写 docker-compose.yml

cat > docker-compose.yml <<'EOF'
version: '3.8'

services:
  db:
    image: mariadb:10.6
    container_name: roller-mariadb
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: q1w2e3r4
      MYSQL_DATABASE: rollerdb
      MYSQL_USER: roller
      MYSQL_PASSWORD: q1w2e3r4
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
      - ./data/db:/var/lib/mysql
      - ./conf/createdb.sql:/docker-entrypoint-initdb.d/createdb.sql:ro

  roller:
    build: .
    image: roller-webapp:6.1.3
    container_name: roller-tomcat
    restart: unless-stopped
    depends_on:
      - db
    ports:
      - "8081:8080"
    environment:
      JAVA_OPTS: "-Xms256m -Xmx512m"
    volumes:
      - ./data/roller:/roller-data
EOF
配置项说明
db.environment首次启动自动建库 rollerdb、授权 roller 账号
db.volumes: ./conf/createdb.sql:/docker-entrypoint-initdb.d/createdb.sqlMariaDB 首次初始化自动导入 Roller 建表脚本(从 roller.war 内 WEB-INF/classes/dbscripts/mysql/createdb.sql 解出,共 33 张业务表)
command: --character-set-server=utf8mb4 ...与 Roller 建库字符集一致,避免中文乱码
roller.build: .用 4.2 节 Dockerfile 构建 roller-webapp:6.1.3
roller.ports: 8081:8080宿主机 8081 映射 8080;宿主 8080 空闲可改 8080:8080(实测宿主 8080 被占用故映射 8081)
roller.environment: JAVA_OPTSJVM 堆限定 256-512MB
roller.volumes: ./data/roller:/roller-data搜索索引与媒体文件落盘宿主机
depends_on先起 db 再起 roller(仅启动顺序,不含就绪探测)

💡 createdb.sql 从 WAR 解出:unzip -o -q roller.war "WEB-INF/classes/dbscripts/mysql/*" 后取 WEB-INF/classes/dbscripts/mysql/createdb.sql 放到 ./conf/。它只在数据目录为空(首次初始化)时执行,重建栈需清空 ./data/db 才会重新导入。

4.5 启动服务

docker compose up -d --build

实测回显:

 Container roller-mariadb Creating
 Container roller-mariadb Created
 Container roller-tomcat Creating
 Container roller-tomcat Created
 Container roller-mariadb Starting
 Container roller-mariadb Started
 Container roller-tomcat Starting
 Container roller-tomcat Started

4.6 查看状态

docker compose ps

实测回显:

NAME             IMAGE                 COMMAND                   SERVICE   CREATED          STATUS          PORTS
roller-mariadb   mariadb:10.6          "docker-entrypoint.s…"   db        15 seconds ago   Up 14 seconds   3306/tcp
roller-tomcat    roller-webapp:6.1.3   "catalina.sh run"         roller    6 seconds ago    Up 5 seconds    0.0.0.0:8081->8080/tcp, [::]:8081->8080/tcp

4.7 验证服务

Roller 启动约需 10-90 秒(连接数据库并初始化),轮询探测:

for i in $(seq 1 24); do CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8081/roller/ 2>/dev/null); if [ "$CODE" = "200" ]; then echo "READY HTTP=$CODE"; break; fi; sleep 10; done
curl -s http://localhost:8081/roller/ | grep -oE "<title>[^<]+</title>"

实测回显:

READY HTTP=200
<title>Front Page: Welcome to Roller!</title>

JVM 堆参数与依赖 jar 核验:

docker exec roller-tomcat bash -c 'ps -ef | grep "[j]ava" | grep -oE "\-Xms[0-9]+m \-Xmx[0-9]+m"; ls /usr/local/tomcat/lib/ | grep -E "mysql|mail|activation"; ls /roller-data/'

实测回显:

-Xms256m -Xmx512m
javax.activation-1.2.0.jar
javax.mail-1.6.2.jar
mysql-connector-j-8.0.33.jar
search-index

4.8 初始化站长账号(curl 完成)

与常规安装一致,初始化向导三步可直接用 curl 走完(宿主机端口换成 8081):

# 1) 注册 admin 用户(先 GET 表单取会话 salt,再 POST;salt 值以实际页面返回为准)
curl -s -c /tmp/ccj.txt http://localhost:8081/roller/roller-ui/register.rol -o /tmp/creg.html
SALT=$(grep -oE "name=\"salt\" value=\"[^\"]+\"" /tmp/creg.html | sed "s/.*value=\"\([^\"]*\)\".*/\1/")
curl -s -b /tmp/ccj.txt -X POST "http://localhost:8081/roller/roller-ui/register!save.rol" \
  --data-urlencode "salt=$SALT" --data-urlencode "bean.id=" \
  --data-urlencode "bean.userName=admin" --data-urlencode "bean.screenName=admin" \
  --data-urlencode "bean.fullName=Site Admin" --data-urlencode "bean.emailAddress=admin@example.com" \
  --data-urlencode "bean.passwordText=q1w2e3r4" --data-urlencode "bean.passwordConfirm=q1w2e3r4" \
  --data-urlencode "bean.locale=en_US" --data-urlencode "bean.timeZone=America/New_York" \
  --data-urlencode "userRegister.button.save=Sign Up" -o /dev/null -w "register=%{http_code}\n"

实测回显:

register=200

数据库核验与登录验证:

docker exec roller-mariadb mariadb -uroot -pq1w2e3r4 rollerdb -e "SELECT username,fullname FROM roller_user;"
curl -s -b /tmp/ccj.txt -c /tmp/ccj.txt -X POST "http://localhost:8081/roller/roller_j_security_check" \
  -d "j_username=admin&j_password=q1w2e3r4" -o /dev/null -w "login=%{http_code}\n"
curl -s -b /tmp/ccj.txt -L http://localhost:8081/roller/roller-ui/menu.rol | grep -oE "<title>[^<]+</title>"

实测回显:

username        fullname
admin   Site Admin
login=302
<title>Front Page: Your Weblogs</title>

💡 建博客与指定前台首页两步同理:createWeblog!save.rol 提交 bean.handle=adminblog 等,随后 setup!save.rol 提交 frontpageBlog=adminblog;流程与《Apache Roller 安装指南》初始化一节完全一致,仅端口不同。

五、数据持久化说明

  • ./data/db 挂载到 MariaDB 的 /var/lib/mysql,博客文章、用户、评论等全部数据落盘宿主机;
  • ./data/roller 挂载到 /roller-data,存放搜索索引 search-index/ 与媒体文件 mediafiles/;
  • ./conf/createdb.sql 建表脚本随项目目录保存,重建环境可直接复用;
  • docker compose down 删除的是容器与网络,上述宿主目录不受影响;重启后数据完好。实测 docker compose restart roller 后再次登录会话仍有效:
 Container roller-tomcat Started
after_restart=200
menu_after_restart=200

⚠️ 若要彻底重建数据库(重新导入建表脚本),必须 docker compose down 后清空 ./data/db,否则 MariaDB 数据目录非空会跳过初始化脚本。

六、常用环境变量表

环境变量服务说明本指南值
MYSQL_ROOT_PASSWORDdbroot 密码q1w2e3r4
MYSQL_DATABASEdb首次初始化创建的库名rollerdb
MYSQL_USER / MYSQL_PASSWORDdb业务账号与密码roller / q1w2e3r4
JAVA_OPTSrollerJVM 参数(堆 256-512MB)-Xms256m -Xmx512m

💡 Roller 自身的连接参数不走环境变量,而是读取类路径的 roller-custom.properties(见 4.3 节);改连接串需改该文件并重新构建或挂载覆盖。

七、常用配置参数说明(command)

db.command 覆盖 MariaDB 默认启动参数,常用追加项:

command 追加参数说明
--character-set-server=utf8mb4服务端默认字符集,与 Roller utf8mb4 建库对齐
--collation-server=utf8mb4_unicode_ci服务端默认排序规则
--skip-name-resolve跳过域名反查,容器环境建议加上以加速连接

roller 服务默认 command 为镜像自带 catalina.sh run(前台运行,日志进入 docker compose logs),不建议改成 catalina.sh start(后台化后容器会立刻退出)。

八、配置文件持久化(conf 挂载)

需要把 Roller 配置也放宿主机统一管理时,把 roller-custom.properties 改为挂载方式而非打进镜像:

  roller:
    build: .
    image: roller-webapp:6.1.3
    volumes:
      - ./data/roller:/roller-data
      - ./conf/roller-custom.properties:/usr/local/tomcat/lib/roller-custom.properties:ro

修改宿主机 ./conf/roller-custom.properties 后 docker compose restart roller 生效,无需重新 build 镜像。

九、等价 docker run 运行方式

不写 compose 文件时的等价命令(先自建网络与数据库):

docker network create roller-net

docker run -d --name roller-mariadb --network roller-net \
  -e MYSQL_ROOT_PASSWORD=q1w2e3r4 \
  -e MYSQL_DATABASE=rollerdb \
  -e MYSQL_USER=roller -e MYSQL_PASSWORD=q1w2e3r4 \
  -v "$PWD/data/db:/var/lib/mysql" \
  -v "$PWD/conf/createdb.sql:/docker-entrypoint-initdb.d/createdb.sql:ro" \
  mariadb:10.6 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

docker run -d --name roller-tomcat --network roller-net \
  -p 8081:8080 \
  -e JAVA_OPTS='-Xms256m -Xmx512m' \
  -v "$PWD/data/roller:/roller-data" \
  roller-webapp:6.1.3

十、常用运维命令

docker compose up -d            # 启动(栈不存在时)
docker compose up -d --build    # 重新构建镜像并启动(改 Dockerfile/配置后)
docker compose ps               # 查看两服务状态
docker compose logs -f roller   # 跟踪 Roller 日志(catalina + roller 合流输出)
docker compose logs --tail 3 db # 查看 MariaDB 日志末尾
docker compose restart roller   # 重启 Roller(配置变更后)
docker compose restart db       # 重启数据库
docker compose down             # 停止并删除容器与网络(保留 ./data 与 ./conf)
docker compose down -v          # 额外删除命名卷(本栈未用命名卷,数据仍在 bind 目录)

docker compose logs --tail 3 db 实测回显:

roller-mariadb  | 2026-10-12  0:59:31 0 [Note] mariadbd: ready for connections.
roller-mariadb  | Version: '10.6.28-MariaDB-ubu2204'  socket: '/run/mysqld/mysqld.sock'  port: 3306  mariadb.org binary distribution
roller-mariadb  | 2026-10-12  0:59:31 0 [Note] InnoDB: Buffer pool(s) load completed at 261012  0:59:31

十一、常见问题(FAQ)

11.1:启动报宿主端口占用

实测回显:

Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint roller-tomcat (...): failed to bind host port 0.0.0.0:8080/tcp: address already in use

解决:把 ports 改为其他宿主端口(如 8081:8080)后 docker compose up -d 重建。

11.2:首页一直 404 或 500

排查:docker compose logs -f roller 看应用日志;常见两类原因——

  • 数据库未就绪时 Roller 启动失败:depends_on 只保证顺序,MariaDB 初始化需十几秒,重启 roller 即可(docker compose restart roller);
  • createdb.sql 未导入:确认 ./data/db 在启动前为空目录(首次初始化才会执行 initdb 脚本),必要时清空后重建。

11.3:日志报 ClassNotFoundException: javax.mail

原因:镜像内缺少 JavaMail 包。Roller WAR 不捆绑 javax.mail,登录后菜单页会 500。 解决:确认 Dockerfile 中三个 jar 的下载步骤存在且成功(docker exec roller-tomcat ls /usr/local/tomcat/lib/ 应见 mysql-connector-j、javax.mail、javax.activation),缺则补齐后重建镜像。

排查:确认 roller-custom.properties 的 connectionURL 主机名为服务名 db 而非 localhost(roller 服务内 localhost 指向自身);docker compose exec db mariadb -uroot -pq1w2e3r4 -e "SHOW DATABASES;" 确认 rollerdb 已创建。

11.5:中文内容乱码

解决:保留 command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci,且建库/建表脚本用 utf8mb4;已乱码的旧数据需重新导入。

十二、参考链接