简介在ARM64/aarch64架构下OpenOffice一直缺少可直接运行的发行版LibreOffice则可较好地适配国产化环境这份资源面向需要在Docker容器中部署办公软件的开发或运维人员整理了完整的ARM镜像制作素材包括Dockerfile-arm、启动与构建脚本解压后即可按类似OpenOffice的方式启动服务。压缩包共15个文件、约644MB主要包含ttf/ttc中文字体、dockerfile-arm、sh/bat脚本及tar归档包中文字体用于保障界面和文档渲染脚本支持一键构建与启停tar包提供镜像或程序归档。已有1177人浏览学习。借助这套文件使用者无需从零编写Dockerfile也不需自行寻找ARM版OpenOffice可在Linux服务器上快速构建LibreOffice容器降低国产化办公迁移门槛对于熟悉Docker但缺少ARM基础镜像经验的团队其中打包好的字体与构建配置也能节省大量适配时间。配套参考文档链接给出便于对照构建和排错。1. 为什么有人要自己动手做 OpenOffice 的 ARM64 镜像如果你手上是树莓派 5、华为鲲鹏服务器或者 Apple Silicon Mac 这类 ARM64 设备想在上面跑一个文档转换服务第一反应肯定是docker pull一个现成的 OpenOffice 镜像。可实际搜一圈你会发现官方并没有发布arm64标签的 OpenOffice 镜像Docker Hub 上那些热门镜像要么只支持amd64要么是好几年没人维护的老古董。在 ARM64 机器上直接跑 x86 镜像Docker 会甩给你一句no matching manifest for linux/arm64这就是这篇笔记要解决的第一个痛点。我最初是为了给内网一个文档预览服务做底包需要在一个 Ubuntu ARM64 容器里稳定跑soffice --headless --convert-to pdf折腾了两天最后把整套制作文件Dockerfile、转换脚本、依赖清单整理成了一个可复用的模板。这篇笔记把这套东西拆开讲清楚包括架构选型、deb 包处理、Dockerfile 编写、验证方法和五个高频坑。适合两类人一类是刚接触 Docker 的 ARM 设备用户能照着步骤把镜像跑起来另一类是已经在 x86 上做过 OpenOffice 转换服务、想迁移到 ARM64 的开发者可以直接抄作业并避开我已经踩过的坑。2. 理解 ARM64 上跑 OpenOffice 的三条路径动手之前先花两分钟搞清楚方向因为 ARM64 上跑 OpenOffice 有完全不同的三条路选错路后面全是无用功。2.1 三条路线的本质区别模拟、伪原生、真原生第一条路线是整体模拟镜像本身声明linux/amd64架构在 ARM64 主机上用 QEMU 用户态模拟binfmt_misc来执行 x86 指令。Docker Desktop 在 Apple Silicon 上就是这么干的docker build --platform linux/amd64配好之后能直接构建和运行。好处是完全不用改 OpenOffice 的安装方式官方 deb 包拿来就用坏处是每条指令都要经过一层翻译性能损耗明显CPU 密集型的 PDF 转换任务能慢 30% 到 50%。第二条路线是伪原生镜像架构声明为linux/arm64但容器里装的 OpenOffice 仍然是 x86 二进制只是通过修改 deb 包的Architecture字段、替换依赖列表让dpkg愿意在 ARM64 系统上把它装进去。实际执行时 x86 指令还是靠 QEMU 翻译但因为只有 OpenOffice 本体在模拟环境里跑系统库和 JRE 都是 ARM64 原生的性能比整体模拟好一些而且镜像架构标识是arm64在集群调度和docker pull时不会出现架构不匹配的问题。第三条路线是真原生用源码在 ARM64 上编译 OpenOffice这是理论上最完美的方案但 OpenOffice 编译依赖极度复杂需要交叉编译工具链、几百个构建依赖还要处理 LibreOffice 源码仓库里大量硬编码的 x86 汇编优化。我在鲲鹏服务器上试过一次光处理依赖就花了一天最后放弃了。不是做不到是不划算。2.2 我为什么推荐第二条路线如果你只是偶尔在 ARM64 机器上跑一次转换任务第一条路线整体模拟最省事docker compose里把platform指到linux/amd64就行。但如果你要做一个长期运行的服务或者需要把镜像分发到多台 ARM64 设备上我更推荐第二条路线。原因有三个。一是镜像的Architecture字段是arm64在 Harbor 这类私有仓库里做多架构管理时不会混乱部署到 K3s 或者 K8s 集群时调度器能正确匹配节点。二是系统依赖比如字体库、libc6、Java 运行时全部走 ARM64 原生包实际测试中转换一个 50 页的 PPT第二条路线比第一条快约 20%。三是调试体验好进入容器后uname -m输出的是aarch64系统层面不会出现 x86 路径的兼容性问题只有 OpenOffice 进程本身是模拟的排错范围被大大缩小。不过要泼一盆冷水第二条路线有个前提条件是你得能把 OpenOffice 的 x86 deb 包装进 ARM64 系统里依赖冲突是最大的拦路虎。接下来详细拆解这个处理过程。3. 准备安装包解决 deb 包架构不匹配的问题OpenOffice 官方只发布x86_64的 deb 包要在 ARM64 系统里安装核心思路是“先骗过 dpkg再补齐依赖”。这个过程分三步下载正确的 deb 包、改写控制信息、预处理依赖关系。3.1 获取 OpenOffice 的 deb 包官方下载页面会根据操作系统自动推荐但我们需要的是纯 Linux x86_64 版本不要选带内置 JRE 的版本因为内置 JRE 是 x86 的后面替换成 ARM64 的 OpenJDK 会更干净。下载后用归档工具解包deb本质上是一个ar归档里面有三个文件debian-binary # 版本信息固定为 2.0 control.tar.xz # 控制信息包含 Architecture、Depends 等字段 data.tar.xz # 实际文件内容OpenOffice 的程序、库、配置都在这里在 Linux 下用dpkg-deb -R可以递归解包到临时目录mkdir -p /tmp/oo_tmp dpkg-deb -R openoffice_4.1.15_x86_64.deb /tmp/oo_tmp解包后重点看/tmp/oo_tmp/DEBIAN/control文件你会看到里面写着Architecture: amd64还有一串依赖列表包括libc6、libstdc6、libxinerama1、libgl1等。这几行内容就是后面需要动手术的地方。3.2 修改 control 文件的核心操作修改control文件不能简单地把amd64改成arm64就完事因为 OpenOffice 的二进制在运行时依赖一些 x86 版本的共享库如果直接改架构字段dpkg会把依赖解析成 ARM64 版本的库实际加载时指令集不匹配会直接Illegal instruction崩溃。我试过两种策略。策略一是把所有依赖都改成arm64但把 OpenOffice 自带的 .so 库保留 x86 版本不动让 OpenOffice 进程自己使用私有目录里的库不走系统路径。这个方案的问题在于 OpenOffice 的 JNI 桥接库会动态加载libX11.so、libcups.so这类系统库只要有一个加载失败整个启动就失败。策略二是尽量把系统依赖留在 x86 版本上也就是通过dpkg --add-architecture amd64让系统同时支持两种架构再用apt-get install libc6:amd64 libstdc6:amd64安装 OpenOffice 实际依赖的 x86 库。实际验证下来策略二更稳定但镜像体积会明显膨胀。下面这段脚本是我目前用的预处理流程#!/bin/bash # openoffice-arm64-prep.sh # 作用将 x86_64 的 OpenOffice deb 包转换为可在 arm64 容器内安装的形式 INPUT_DEB$1 WORK_DIR/tmp/ooffice mkdir -p $WORK_DIR dpkg-deb -R $INPUT_DEB $WORK_DIR # 修改控制文件中的架构字段 sed -i s/^Architecture: .*/Architecture: arm64/ $WORK_DIR/DEBIAN/control # 将架构相关的依赖改为多架构版本保留 :amd64 后缀 sed -i s/Depends: /Depends: /; s/\(lib[^,]*\)/\1:amd64/g $WORK_DIR/DEBIAN/control # 重新打包 dpkg-deb -b $WORK_DIR openoffice_arm64_repack.deb这里有个细节需要注意sed替换依赖时不能盲目给所有包加:amd64后缀纯文档包、shell 脚本类依赖比如bash、procps应该保持默认架构。一个更稳妥的做法是手动编辑control文件只在lib开头的包后面加:amd64。因为 OpenOffice 真正硬依赖的是图形界面库和系统 C 库这些在容器里如果走 x86 版本恰好和主程序一致不会出现混架构调用。3.3 解决 Java 运行时依赖OpenOffice 的 UNO 组件、宏功能和某些过滤器依赖 Java。在 ARM64 容器里通常已经装了 ARM64 的 OpenJDK但 OpenOffice 判断 Java 环境时会检查soffice启动脚本里的JAVA_HOME它不会对 Java 本身做架构检查只要路径能找到java可执行文件就能识别。不过实际运行时x86 的 OpenOffice 通过 JNI 调用 ARM64 的 JVM 会出现Cannot load 64-bit JVM from 32-bit process之类的错误准确的说是java.library.path找不到匹配的本地库。这个问题没有完美的解决方案。我采用的是让 OpenOffice 完全不使用内置 Java 功能只做纯文本格式转换。禁用 Java 可以在启动参数里加-env:UserInstallationfile:///tmp/lo_profile强制使用临时用户配置再在配置文件里关掉 Java。这样损失的是宏功能和部分 DOC 加密文件的处理能力但绝大多数文档转换场景根本用不到。如果你确实需要 Java 功能唯一可行的路线是arm64容器里再套一层 x86 的 OpenJDK也就是用多架构方式安装openjdk-8-jre:amd64然后把它的路径指给 OpenOffice。# 安装 x86 版本 Java需要系统已启用 multiarch dpkg --add-architecture amd64 apt-get update apt-get install -y openjdk-8-jre:amd64 # 让 OpenOffice 使用 x86 Java sed -i s/JAVA_HOME.*/JAVA_HOME\/usr\/lib\/jvm\/java-8-openjdk-amd64/ /opt/openoffice4/program/soffice注意openjdk-8在 Ubuntu 20.04 之后需要从第三方源安装实际操作中我建议先测试纯headless转换是否需要 Java大多数 PDF 转换、TXT 转 DOC 都不需要能省掉这一层麻烦。4. 编写 Dockerfile 与构建部署安装包准备好之后镜像构建就简单多了但还是有几个细节要处理否则构建出来的镜像会有体积膨胀、权限问题和时区问题。下面是一份实际能构建通过的 Dockerfile。4.1 Dockerfile 的完整结构# 基于 ARM64 的 Ubuntu 20.04镜像架构本身就是 arm64 FROM arm64v8/ubuntu:20.04 # 预装多架构支持和 OpenOffice 依赖的 x86 库 RUN dpkg --add-architecture amd64 \ apt-get update \ apt-get install -y \ libc6:amd64 \ libstdc6:amd64 \ libxinerama1:amd64 \ libgl1:amd64 \ libcups2:amd64 \ libx11-6:amd64 \ libxext6:amd64 \ libfreetype6:amd64 \ fontconfig \ fonts-noto-cjk \ zip \ unzip \ curl # 拷贝预处理好的 OpenOffice deb 包并安装 COPY openoffice_arm64_repack.deb /tmp/ RUN dpkg -i /tmp/openoffice_arm64_repack.deb || apt-get -f install -y # 创建普通用户避免以 root 运行 OpenOfficeroot 运行会导致配置文件权限混乱 RUN useradd -m -s /bin/bash converter # 设置时区和临时目录 ENV TZAsia/Shanghai \ HOME/home/converter \ OO_SYSTEM_DIR/opt/openoffice4 # 转换脚本入口 COPY convert.sh /usr/local/bin/ RUN chmod x /usr/local/bin/convert.sh USER converter WORKDIR /data ENTRYPOINT [convert.sh]这份 Dockerfile 有几个关键决策。第一是基镜像用arm64v8/ubuntu:20.04而不是ubuntu:latest因为 22.04 之后部分 x86 库的依赖链变化较大libc6:amd64的安装容易碰到冲突。第二是预装libcups2:amd64和libx11-6:amd64这两个库是 OpenOffice 启动时动态探测的缺了会在soffice.bin启动早期就崩溃报错信息却是不明确的Segmentation fault。第三是.deb安装失败后调用apt-get -f install -y这个命令会自动解决未满足的依赖代价是它可能把部分:amd64依赖替换成非多架构版本所以必须在第一步把所有:amd64库装扎实。4.2 convert.sh 脚本的边界处理转换脚本是整个镜像的入口表面上是调用soffice --headless但有几个参数必须显式设置否则会在实际使用中翻车。#!/bin/bash # convert.sh容器内文档转换入口 # 用法docker run --rm -v $(pwd):/data converter-image input.docx output.pdf INPUT_FILE$1 OUTPUT_FILE${2:-${INPUT_FILE%.*}.pdf} # 创建用户配置目录OpenOffice 第一次启动如果没有家目录配置会卡死 mkdir -p /home/converter/.config chown -R converter:converter /home/converter # 设置 UNO 使用的临时目录避免容器内 /tmp 权限问题 export TMPDIR/home/converter/tmp mkdir -p $TMPDIR exec soffice --headless \ --norestore \ --invisible \ --nodefault \ --nolockcheck \ --nologo \ -env:UserInstallationfile:///home/converter/lo_profile \ --convert-to pdf --outdir /data /data/$INPUT_FILE--nolockcheck是必须的因为容器内多实例并发转换时OpenOffice 默认会在用户配置目录下创建.lock文件第二次启动就会报 “The OpenOffice UserInstallation appears to be already in use”。--nodefault的意思是跳过启动时的默认模板加载加快冷启动速度。-env:UserInstallation用来指向独立的配置目录避免每次启动都重新初始化。另外注意脚本里--convert-to pdf --outdir /data /data/$INPUT_FILE输入输出路径全部用绝对路径挂在/data下。如果你只把输入文件挂载进去输出文件生成在容器内退出容器后文件就丢了这是新手最容易犯的错误。4.3 构建与使用命令构建命令没有特别之处但在 ARM64 设备上构建时请确认 Docker 的 buildx 已经正常初始化# 构建镜像指定 linux/arm64 平台 docker buildx build --platform linux/arm64 -t openoffice-arm64:v1 . # 查看镜像架构信息 docker inspect openoffice-arm64:v1 --format{{.Architecture}} # 挂载当前目录执行转换 docker run --rm -v $(pwd):/data openoffice-arm64:v1 test.docx test.pdf关于 QEMU 需要多说一句在 x86 开发机上交叉构建 ARM64 镜像时需要先注册模拟器docker run --rm --privileged multiarch/qemu-user-static --reset -p yes这个命令会在宿主机注册各架构的用户态模拟器。如果你直接在自己电脑上docker buildx build --platform linux/arm64没做这一步会报exec format error。在 ARM64 设备本地构建则不需要模拟器。构建验证的核心点在于docker inspect输出的Architecture必须是arm64然后进入容器用file命令看 OpenOffice 二进制确实是 x86 格式两个信息要同时存在这才说明“伪原生”方案生效了。如果Architecture显示amd64说明镜像整体的 QEMU 模拟路径被启用了与预期不符。5. 常见问题与避坑清单这部分是把我在整个过程中踩过的五个高频问题整理出来每条都按现象、原因、解决方式展开。5.1 “Segmentation fault” 启动即崩溃现象运行soffice --headless --convert-to pdf时进程启动不到两秒就静默退出dmesg里能看到soffice.bin[pid]: segfault。原因OpenOffice 主程序是 x86 二进制启动时会通过dlopen动态加载系统库。如果系统库是 ARM64 版本加载时指令解码失败会直接段错误。另一个原因是缺libcups2:amd64这个库跟打印模块绑在一起headless模式下 OpenOffice 依然会做初始化探测。解决第一步先确认/opt/openoffice4/program/soffice.bin的架构用file命令检查输出里必须是x86-64。第二步检查容器内ldd /opt/openoffice4/program/soffice.bin输出里凡是标记not found的库都要用apt-get install 包名:amd64补上。尤其注意libcups2和libxinerama1这两个最容易缺。排查顺序是先ldd后strace# 非交互调试查看动态库加载情况 ldd /opt/openoffice4/program/soffice.bin | grep not found # 跟踪启动后的系统调用找到崩溃前最后一个库加载动作 strace -f -e traceopenat soffice --headless --convert-to pdf test.docx 21 | tail -405.2 转换 PDF 中文乱码现象文档转换成功PDF 也能打开但所有中文字符显示成方块或者乱码。原因容器内没有中文字体。OpenOffice 在 Linux 下字体回退逻辑很弱找不到SimSun、Noto Sans CJK就直接用系统默认字体渲染而 Ubuntu 基础镜像不包含任何中文字体。解决在 Dockerfile 里安装fonts-noto-cjk并刷新字体缓存apt-get install -y fonts-noto-cjk fc-cache -f -v这里要特别注意fc-cache必须在安装完字体后执行否则 OpenOffice 扫描字体目录可能拿到空的字体缓存。如果你挂载了自定义字体目录需要在convert.sh启动前也执行一次fc-cache否则新挂载的字体不会被识别。5.3 镜像体积高达 2GB现象构建完的镜像docker images显示大小超过 2GB拉取和部署成本都很高。原因同时安装了多架构的 C 库、OpenOffice 本体约 400MB、JRE如果安装了再加上apt缓存没有清理。多架构的libc6:amd64和libc6:arm64会并存两份动态库体积确实大。解决第一个是构建结尾清理apt缓存RUN apt-get clean rm -rf /var/lib/apt/lists/*第二个是如果不需要 Java 功能就不要装 OpenOffice 带 JRE 的版本用无 JRE 的普通包能省约 150MB。第三个是用--squash对镜像进行层压缩docker buildx build --squash --platform linux/arm64 -t openoffice-arm64:v1 .5.4 并发转换任务卡死现象脚本里循环调用多个soffice --convert-to任务跑到第二个或者第三个时进程挂起或者报 “ActiveSockets” 错误。原因OpenOffice 的soffice.bin在同一用户配置目录下只允许一个实例后续调用会尝试连接已有实例的 IPC socket 而不是新建进程而headless模式下的 socket 通信经常因为配置目录损坏而阻塞。解决每个转换任务都用独立的 UserInstallation 目录或者在每次转换结束后强制杀掉所有残留的soffice.bin进程# 每次转换完成后清理进程 pkill -f soffice.bin || true sleep 2 # 或者使用独立配置目录 -env:UserInstallationfile:///home/converter/lo_profile_$RANDOM生产环境我建议加一个简单的任务队列串行执行转换不要指望 OpenOffice 自己支持并发。并发性能优化方向是启动多个容器实例而不是在单容器内并发。5.5 挂载的输入文件提示权限不够现象docker run --rm -v /tmp/x:/data ...后容器内ls -l /data显示文件用户 ID 是 1000而容器内的用户是converterUID 1001读取时报Permission denied。原因容器内外用户 UID 不一致文件挂载进容器后属主不会被自动映射。converter用户没有权限读取宿主用户的文件。解决把容器内converter用户的 UID 固定为 1000这样与大多数 Linux 桌面的第一个用户一致RUN useradd -m -u 1000 -s /bin/bash converter如果宿主 UID 不确定可以在运行时动态传入 UID# 运行前创建与宿主相同 UID 的用户 docker run --rm -e CONVERTER_UID$(id -u) -v $(pwd):/data openoffice-arm64:v1 ...脚本里加一行根据CONVERTER_UID重新调整用户 UID 的逻辑但注意要保证/home/converter下所有文件属主同步变更否则配置文件目录会出现所有权混乱反而触发 5.1 里的崩溃。6. 进阶验证与性能调优镜像能跑起来只是第一步确认性能和稳定性需要做几轮验证。这里先给一个拿来就能用的压力测试脚本再讲两个提升转换吞吐量的技巧。6.1 验证转换正确性验证不止是看 PDF 是否生成还要检查内容是否完整。我的验证方式是用pdftotext提取 PDF 文本对比源文档里的关键字段# 循环转换 50 个不同格式的文档样本 for f in /data/samples/*.docx; do docker run --rm \ -v $(pwd)/samples:/data \ openoffice-arm64:v1 \ $(basename $f) ${f%.docx}_out.pdf done # 检查输出 PDF 的文本内容 pdftotext samples/sample1_out.pdf - | grep 关键字段建议样本覆盖 DOCX、PPTX、XLSX、TXT 四种格式分别验证文本、表格、图片和页脚渲染是否正确。第一次验证时最容易发现字体缺失问题也就是 5.2 里说的那个坑。6.2 冷启动延迟优化OpenOffice 冷启动是指进程从启动到监听 UNO socket 的耗时。在 ARM64 模拟的环境下这个时间可能长达 10 到 15 秒比原生 x86 慢一倍以上。优化的常规做法是用unoconv的持久监听模式让 OpenOffice 常驻后台后续转换通过 UNO 协议快速调用# 启动持久监听服务 soffice --headless --invisible --norestore \ -env:UserInstallationfile:///home/converter/lo_profile \ --acceptsocket,hostlocalhost,port2002;urp; # 发送转换请求 python3 - PY import uno # 使用 unoconv 库或者直接调用 UNO API from unoconv import Unoconv u Unoconv() u.convert(/data/input.docx, /data/output.pdf) PY但需要注意持久监听模式下 OpenOffice 进程会一直在容器内运行你需要把容器的启动命令从convert.sh改成持久监听命令再用 HTTP 接口对接转换请求。这种架构更适合做企业内部的文件转换微服务吞吐量比每次新起进程高 3 到 5 倍。6.3 镜像瘦身与构建缓存最后说一个构建技巧。如果arm64v8/ubuntu:20.04基础镜像需要每次都从远程拉取构建速度会很慢。可以在 ARM64 设备上先把基础镜像打一层本地标签docker pull arm64v8/ubuntu:20.04 docker tag arm64v8/ubuntu:20.04 ubuntu-local:arm64Dockerfile 里把FROM arm64v8/ubuntu:20.04改成FROM ubuntu-local:arm64离线构建时就不需要重新拉取。另外apt-get install的依赖列表建议拆成两次安装第一层安装多架构库和基础依赖第二层安装 OpenOffice这样修改 OpenOffice 相关配置时不会重新跑一遍多架构库安装加快构建迭代速度。这套制作文件我已经更新到第三个版本踩过最深的坑是 QEMU 模拟环境下 OpenOffice 崩溃时的错误信息极具迷惑性几乎不会告诉你真实的指令集不匹配问题。从那以后我每次调整依赖都会强制做一遍ldd检查和真实样本转换验证不再相信 “安装成功就等于能用”。希望这套流程和避坑清单能帮你少走两天弯路。本文还有配套的精品资源点击获取