拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ARM64上制作OpenOffice Docker镜像包:QEMU跨架构实践

ARM64上制作OpenOffice Docker镜像包:QEMU跨架构实践 简介面向ARM64aarch64架构国产化环境下的办公套件容器化需求这份资源提供了以LibreOffice替代OpenOffice的Docker镜像制作文件。由于OpenOffice缺乏对ARM64的适配而LibreOffice在该架构下运行稳定且启动方式与OpenOffice一致因此这套文件适合在信创或国产化服务器上搭建文档转换、预览等基础服务的开发者使用。包体共15个文件压缩后约644MB涵盖7个ttf字体与4个ttc字体用于中文显示、Dockerfile-arm构建脚本、一键打包的bat批处理、启动用的sh脚本以及打包好的LibreOffice tar镜像。字体文件解决了中文乱码问题脚本则简化了arm64镜像的构建与启动流程。已有1177人学习下载文件结构清晰解压后即可参照构建也可按需调整Dockerfile或替换字体快速产出适配ARM64的LibreOffice容器服务减少国产化适配中的踩坑成本。1. 为什么OpenOffice在ARM64上这么别扭官方没有原生包在ARM64服务器鲲鹏920、飞腾FT-2000这类上跑OpenOffice做文档转换第一反应是去官网下载Linux DEB包结果安装时直接被dpkg呛回来package architecture (amd64) does not match system (arm64)。这个坑我踩过。Apache OpenOffice的Linux版本至今只发布x86_64的rpm和deb没有aarch64安装包所以“下载-安装”这条原生路线根本走不通。标题里的“docker镜像包制作文件”真正难啃的其实不是Dockerfile怎么写而是怎么让x86_64的OpenOffice在一个arm64的容器引擎里老老实实跑起来。本文给出一条可交付的路径用QEMU用户态模拟在arm64主机上运行amd64的OpenOffice镜像再用docker save把镜像沉淀成tar包拿到目标环境docker load。适合的是国产化环境离线交付、文档转换服务封装或者树莓派和Apple Silicon上跑headless转换的场景。2. 让arm64主机先具备运行x86二进制的能力2.1 为什么绕过官方包OpenOffice没有aarch64安装包先算一笔账。Apache OpenOffice 4.1.x官方只给amd64的Linux二进制源码里那些老构建依赖在ARM64上交叉编译非常痛苦光libmspack、icu4j的版本匹配就能把人磨到怀疑人生。我一般不建议碰源码编译那东西像一个黑匣子耗一天可能还在配置环境。更省事的做法是让内核替你“翻译”指令QEMU用户态模拟。你可能听过qemu模拟arm64比如在x86开发机上跑arm64容器。反过来完全同样成立在arm64主机上注册QEMU的x86_64解释器内核加载ELF文件时发现架构是x86_64就自动交给qemu-x86_64去执行。容器里的进程自己感觉不到被翻译了它以为自己在x86_64机器上正常跑。Docker不参与翻译本身它只负责拉取镜像、创建沙箱真正跨架构工作是binfmt_misc完成的。为什么这套方案比其他方式可靠因为OpenOffice本身没有被改成ARM64但它的x86_64二进制在两三层抽象下依然能出结果。对于headless文档转换这种“进去一个docx出来一个pdf”的场景QEMU的性能损耗完全可以接受。换源码编译的代价则大得多而且维护一个自编译分支后续换版本还要重新编译交付周期拉得太长。2.2 安装qemu-user-static并注册binfmt在目标是arm64的Ubuntu/Debian主机上先装包再用社区通用的容器注册一次sudo apt-get update sudo apt-get install -y qemu-user-static sudo docker run --rm --privileged multiarch/qemu-user-static --reset -p yes第一行是把静态编译的QEMU解释器装到宿主机。第二行的multiarch/qemu-user-static容器是常见做法--privileged是因为它要写/proc/sys/fs/binfmt_misc/这个内核接口--reset会清掉之前注册的旧规则避免同一个内核上残留不同架构的冲突条目-p yes表示持久注册重启后规则依然在不用每次重来。注册完之后检查一下是否真的生效ls /proc/sys/fs/binfmt_misc/ | grep qemu输出里能看到qemu-x86_64说明内核已经把x86_64的ELF魔数记录在册。如果你不想通过容器注册也可以手动往binfmt_misc写规则但magic字节和掩码一旦写错后面运行跨架构容器会报各种莫名其妙的问题不推荐手搓。2.3 用一条命令验证模拟是否生效注册完不要急着构建OpenOffice先用一个最小的amd64镜像确认翻译层通了docker run --rm --platform linux/amd64 debian:bullseye uname -m如果输出x86_64说明Docker已经把amd64镜像拉下来容器里执行的uname是x86_64二进制宿主内核正确调用了qemu-x86_64。如果报exec format error别怀疑镜像先去查binfmt注册状态多半是第2.2节的第二步没跑成功。在macOS用Docker Desktop或Windows WSL2里这个平台翻译由Docker Desktop内置的Virtualization框架自动处理不需要手动注册。但真正的ARM64 Linux服务器必须做这一步而且不能跳过。很多人拿Apple Silicon上的经验跑到Linux服务器上然后被exec format error卡半天这就是环境差异的坑。验证通过以后arm64主机就具备了运行amd64容器的基础能力。基于这个能力我们再去看OpenOffice镜像怎么做。3. 编写OpenOffice镜像的Dockerfile从x86 deb包到可运行镜像3.1 选基础镜像和OpenOffice包构建这个镜像的最终产物是amd64架构基础镜像必须锁定成debian:bullseye这类amd64镜像不要用arm64的arm64v8/debian然后在里面硬塞x86_64的deb包。dpkg的架构校验过不去硬装会得到一堆“wrong architecture”的错误。如果使用buildx在x86构建机交叉构建也记得在FROM里写上--platformlinux/amd64否则BuildKit会按照宿主架构去解析基础镜像出来一个arm64容器后面一样白搭。OpenOffice的Debian包从官方下载文件名有规律Apache_OpenOffice_4.1.x_Linux_x86-64_install-deb_语言.tar.gz。解压后有一个DEBS目录里面是core、writer、calc、impress等十几个deb。这个包是Apache 2.0协议下的二进制可以直接分发和封装但如果你要把镜像包公开给别人License文件最好一并保留这是基本的合规习惯。3.2 Dockerfile完整内容下面是我经过几轮改版后稳定能用的Dockerfile放在与deb包同一目录下构建# 固定amd64架构在arm64主机上通过qemu翻译运行 FROM --platformlinux/amd64 debian:bullseye ENV DEBIAN_FRONTENDnoninteractive \ LANGC.UTF-8 \ HOME/tmp \ PATH/opt/openoffice4/program:$PATH RUN apt-get update apt-get install -y --no-install-recommends \ openjdk-11-jre-headless \ fontconfig \ fonts-dejavu-core \ fonts-noto-cjk \ wget \ ca-certificates \ rm -rf /var/lib/apt/lists/* COPY Apache_OpenOffice_*_Linux_x86-64_install-deb_*.tar.gz /tmp/oosetup.tar.gz RUN mkdir -p /tmp/oosetup tar -xzf /tmp/oosetup.tar.gz -C /tmp/oosetup --strip-components1 \ apt-get install -y /tmp/oosetup/DEBS/*.deb \ rm -rf /tmp/oosetup /tmp/oosetup.tar.gz逻辑说明第一段apt-get安装的是OpenOffice运行时的硬依赖。openjdk-11-jre-headless给宏和某些转换流程提供Java环境fontconfig和两个字体包解决文档排版与中文渲染其中fonts-noto-cjk是后文中文乱码问题的正解。第二段把下载好的tar包复制进容器解压然后直接让apt-get安装本地deb目录。这里刻意不用dpkg -i而是用apt-get install -y ./DEBS/*.deb让apt自动解析deb包之间的依赖和系统依赖省掉后续apt-get -f的补救。参数说明--platformlinux/amd64是关键保证基础镜像永远拉amd64层--no-install-recommends避免把桌面版不需要的X11组件也装进来镜像能小一截传输也更快。PATH写到/opt/openoffice4/program这是OpenOffice deb包默认安装目录容器里直接敲soffice就能用。如果你拿到的包安装路径不同先用dpkg -L openoffice查一下真实路径再改ENV。3.3 两种构建姿势本机构建与buildx构建在x86_64的构建机上直接跑docker build -t openoffice:4.1 .在arm64主机上想构建amd64镜像或者你只有一台Apple Silicon笔记本用buildx交叉构建docker buildx create --name oobuild --use docker buildx build --platform linux/amd64 -t openoffice:4.1 --load .--load会把构建出的amd64镜像导入当前Docker的本地镜像列表--push则推到仓库buildx create只在第一次需要后面可以复用。构建过程中BuildKit会在arm64主机上启动amd64的构建容器里面每条RUN指令都通过QEMU执行所以第2章的binfmt注册是整个构建的前置条件忘了的话会卡在第一步。构建完成后可以用docker image inspect openoffice:4.1 | grep Architecture确认镜像架构是amd64。如果你在arm64机器上构建这一条尤其重要因为你不看的话很可能得到一个“架构不对但构建成功”的镜像原因后面我们会细说。4. 把镜像包做好docker save、离线传输与load4.1 命名与导出交付镜像包最看重的是“到目标机器上一定能起来”。镜像在哪个平台构建不重要运行时的--platform才重要。建议文件名直接带上架构比如openoffice-amd64-4.1.tar.gz避免两个月后自己都分不清手里这个包是给谁的。导出命令docker save openoffice:4.1 | gzip openoffice-amd64-4.1.tar.gzdocker save会把镜像所有层和元数据打包成tar管道接gzip压缩能省不少网络传输时间。不要用docker export它只导出容器文件系统丢掉了镜像的CMD、ENV、EXPOSE等元数据load回来的可能是一个没有入口的裸文件系统到时候再想起来就只剩后悔药了。4.2 目标arm64主机上的导入与运行拷到目标机器后导入并验证docker load -i openoffice-amd64-4.1.tar.gz docker run --rm --platform linux/amd64 openoffice:4.1 soffice --headless --versiondocker load会自动识别gzip不一定要先解压。运行命令里带--platform linux/amd64即使目标机Docker默认平台是arm64也会优先执行amd64镜像。如果soffice --version打印出OpenOffice 4.1.x的版本号就说明整个链路通了。日常跑转换我会再包一层docker run --platform linux/amd64 \ -v $(pwd)/docs:/docs \ openoffice:4.1 \ soffice --headless -env:UserInstallationfile:///tmp/lo_profile \ --convert-to pdf --outdir /docs /docs/report.docx挂载目录用了$(pwd)/docs方便把目标文档传进去。-env:UserInstallation指定独立配置文件目录避免多个容器同时跑时写同一个$HOME/.config把配置锁搞坏。这个参数在并发转换场景下是救命级的后面第5章还会展开。4.3 一套完整的制作与交付脚本把常见两步写进脚本防止手工拼命令拼错#!/usr/bin/env bash # 在x86构建机上执行得到镜像包 set -euo pipefail docker buildx create --name oobuild --use 2/dev/null || true docker buildx build --platform linux/amd64 -t openoffice:4.1 --load . docker save openoffice:4.1 | gzip openoffice-amd64-4.1.tar.gz echo 镜像包已生成#!/usr/bin/env bash # 在arm64目标机上执行导入镜像并验证架构翻译 set -euo pipefail docker load -i openoffice-amd64-4.1.tar.gz docker run --rm --platform linux/amd64 openoffice:4.1 uname -m第一份脚本里buildx create后带|| true因为如果已存在同名builder命令会报错但不影响后续使用。第二份脚本刻意用uname -m而不是soffice --version做冒烟因为uname更轻能快速暴露是QEMU没注册还是镜像本身损坏。确认输出x86_64后再去跑真实转换验证。4.4 离线环境把QEMU解释器也塞进交付物很多arm64目标机是内网连apt源都访问不了第2章的multiarch/qemu-user-static容器也拉不下来。那就得把QEMU解释器直接打在交付包里。在x86构建机上执行cp /usr/bin/qemu-x86_64-static ./deliver/把qemu-x86_64-static这个唯一文件放到和tar包同级目录然后在目标机上以root执行sudo chmod x /usr/local/bin/qemu-x86_64-static sudo sh -c echo :qemu-x86_64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-x86_64-static:F /proc/sys/fs/binfmt_misc/register这段写入用的是binfmt_misc的标准注册格式M表示对应可执行格式后面是ELF魔数再后面是掩码最后是解释器路径。魔数里的\x02\x00\x3e\x00就是x86_64的e_machine。目标环境如果是arm64 v8a内核看到这样的elf header就会自动到你指定的解释器路径找qemu。Ubuntu、Debian、Kylin V10默认都开启了binfmt_misc离线交付时这招非常稳。5. 避坑/常见问题/排查OpenOffice在arm64容器里的五座山5.1 exec format errorQEMU没注册或注册被清掉现象docker run直接报exec format error容器起不来。原因目标机没有注册x86_64的binfmt或者注册被系统重启清掉了。Docker本身不提供翻译没有内核binfmt配合它拿到amd64镜像只会因为架构不匹配拒绝执行。解决回到第2.2节重新跑一遍docker run --rm --privileged multiarch/qemu-user-static --reset -p yes。重启后要检查/proc/sys/fs/binfmt_misc/qemu-x86_64是否存在。如果目标机离线用第4.4节的方式手动注册。这个坑在所有踩坑里排第一因为它决定了后面所有步骤能不能进行。5.2 中文文档转成PDF后全是方框现象PDF能生成但中文全部变成方框或空格日志还不报错。原因镜像里没有中文字体fontconfig匹配不到任何可用的CJK字体于是只能渲染空白格子。解决在Dockerfile里加fonts-noto-cjk构建时让fontconfig做一次缓存。如果不想重新构建也可以在run时挂载宿主字体目录-v /usr/share/fonts:/usr/share/fonts:ro。但交付环境不一定有宿主字体所以Dockerfile里装字体才是治本。这个坑很容易漏因为转换命令完全正常退出码是0但打开PDF全是方框属于最隐蔽的翻车方式。5.3 soffice --headless 一转换就退出返回码4现象命令执行了但瞬间退出生成的PDF不存在退出码是4。原因OpenOffice进程使用同一个UserInstallation目录时配置文件被锁或者HOME指向的目录不可写。在多个容器并发跑同一个镜像时两个进程抢同一个profile目录直接秒退。解决给每个进程一个独立的UserInstallation。典型用法soffice --headless -env:UserInstallationfile:///tmp/oo_profile_$$ --convert-to pdf --outdir /out /in.docx$$是Shell的PID基本保证唯一如果容器内的Shell不是bash用$RANDOM也行。这个坑在做并发转换服务时几乎必踩我最初用固定profile跑定时任务一天崩好几次改成独立目录后再没出过问题。5.4 OpenOffice deb包依赖与新系统库冲突现象apt-get install本地deb包时报依赖不满足比如缺libmspack0或libdbus-glib-1-2。原因官方deb包基于较老的Ubuntu系编译对Debian 11/12的依赖库版本变化不兼容。解决不要硬性dpkg -i坚持用apt-get install -y /tmp/oosetup/DEBS/*.deb让apt自动从当前源里拉兼容版本的依赖。如果某个依赖在新系统里已被废弃可以把基础镜像从debian:bullseye换成ubuntu:20.04那里面对老依赖的兼容性更好。我第一次在Debian 12上构建就是死在libmspack上后来把基础镜像降到bullseye就安静了。5.5 QEMU模拟下性能慢或容器被OOM杀掉现象转换一个20页docx要好几分钟或日志里出现Killed、OutOfMemory。原因QEMU翻译执行本身有开销OpenOffice启动还要初始化Java进程如果容器内存limit设太小Java进程直接OOM。解决给容器加--memory2g并用环境变量限制JVM堆内存docker run --rm --platform linux/amd64 \ -e JAVA_TOOL_OPTIONS-Xmx512m \ --memory2g \ openoffice:4.1 \ soffice --headless --convert-to pdf --outdir /out /docs/a.docxJAVA_TOOL_OPTIONS是JVM启动时的标准环境变量OpenOffice嵌入的JVM也会读取它。把堆限制到512m能有效降低QEMU翻译层的压力。如果目标机本身内存很小减少并发数比增加内存更现实。6. 跑起来以后验证一次真实转换确认能交付6.1 用一次真实转换做冒烟验证先用一张接近真实业务的docx验证转换而不是只验证OpenOffice能启动。我的习惯是docker run --rm --platform linux/amd64 \ -e JAVA_TOOL_OPTIONS-Xmx512m \ -v $PWD/example:/docs \ openoffice:4.1 \ soffice --headless -env:UserInstallationfile:///tmp/oo_verify \ --convert-to pdf --outdir /docs /docs/example.docx检查顺序先说清楚先看容器退出码是否为0再确认example.pdf存在最后用file example.pdf确认它不是文本乱码或零字节文件。只有这三项都过了我才会把这套镜像拿去给团队用。6.2 性能不满意时的原生替代方案如果QEMU的性能实在不可接受还有一个兼容备选把OpenOffice换成LibreOffice的arm64原生包。LibreOffice继承自OpenOffice代码库soffice命令行接口几乎一样转换脚本基本可以无缝迁移。在arm64的apt源里就是原生二进制不需要QEMU性能是实打实的。我自己的习惯是先拿样例文档跑通一条真实转换再决定用哪种方案避免包装了半天的镜像包在第一个真实文档上翻车。如果只是给内部做个文档转换服务LibreOffice原生方案通常省心得多如果业务绑定了OpenOffice的UNO API那还是老实留在QEMU这条路上把内存上限和并发数都压好希望帮到你。本文还有配套的精品资源点击获取
返回列表