Gotenberg Docker Compose 部署实战

Gotenberg v8.39.0 Docker Compose 从零部署实战:镜像三变体选型、compose.yaml 编排与健康检查、/health 探活回显、字体目录挂载中文渲染、Basic 认证实测、数据持久化说明与运维命令。

GotenbergGotenbergPDF 处理文档转换2026/10/28

Gotenberg Docker Compose 部署实战

目标:本文以官方镜像为唯一载体,在 Ubuntu 22.04 服务器上从零完成 Gotenberg v8.39.0 的 Docker Compose 单机部署,覆盖镜像变体选型、compose.yaml 编排、健康检查探活、数据持久化说明、字体目录挂载、Basic 认证开启与运维命令,全部步骤均已实测通过;配置参数的逐项详解与 API 调用实操见 《Gotenberg 配置参数详解》 与 《Gotenberg 常用命令与运维实战(核心篇)》。

一、环境信息

本章列出本次部署实测的服务器环境与版本组合,读者在相同或相近环境下可完全复现。

  • 操作系统:Ubuntu 22.04(x86_64,内核 5.15+ 均可)
  • Docker Engine:29.x(含 Docker Compose v2 插件,docker compose 子命令可用)
  • Gotenberg 版本:v8.39.0(官方主标签 gotenberg/gotenberg:8,2026-10-28 实查时 8 标签即指向 8.39.0)
  • API 端口规划:宿主机 8130 → 服务 3000(Gotenberg 默认监听 3000 端口)
  • 编排网络:自定义 bridge 网络 gotenberg-net,显式网段 10.89.57.0/24
  • Compose 项目名:gotenberg-8-stack(在 compose.yaml 中显式声明,避免多项目同名互相干扰)
  • 配置目录:/opt/gotenberg/(compose.yaml 与字体目录均放此处)

⚠️ 注意:Gotenberg 官方明确建议不要把服务直接暴露到公网(来源:官方安装文档),生产环境应部署在内网,仅对内网应用开放端口。

二、镜像选型说明

本节说明官方镜像的三种变体差异与标签选择策略,这是部署前最重要的决策点之一。

Gotenberg 官方提供三种镜像变体(来源:官方安装文档,2026-10-28 查询):

镜像标签体积包含能力适用场景
gotenberg/gotenberg:8完整体积(约 2.5GB 磁盘占用,实测)Chromium + LibreOffice + 全部 PDF 引擎网页/HTML/Markdown/Office 全功能转换
gotenberg/gotenberg:8-chromium约小 30%Chromium + PDF 引擎,无 Office 转换只转网页/HTML,不需要 Office
gotenberg/gotenberg:8-libreoffice约小 40%LibreOffice + PDF 引擎,无 URL/HTML/Markdown 转换与截图只转 Office 文档与 PDF 后处理

三种变体均包含 PDF 引擎全套能力(合并、拆分、加密、水印、元数据、书签、附件、PDF/A 等)。请求了变体不支持的特性会直接返回错误。

标签策略:gotenberg/gotenberg:8 是跟随 8.x 最新稳定版的滚动标签,本次部署实测拉取到的就是 8.39.0。若要锁定版本,可用精确标签 gotenberg/gotenberg:8.39.0。官方另有 Cloud Run 与 AWS Lambda 专用变体(8-cloudrun、8-aws-lambda 后缀),仅对应云平台托管场景需要。

本次部署选择 full 变体 gotenberg/gotenberg:8:实测场景需要同时覆盖 Chromium 渲染与 Office 转换两条线,功能矩阵最全,代价是体积最大。如果业务只有单一路径,选对应精简变体可节省约三至四成磁盘与内存开销。

💡 说明:镜像以非 root 用户 gotenberg(UID/GID 1001)运行,自 8.21.0 起还支持 OpenShift 的任意 UID 模式(来源:官方安装文档)。无需在 compose.yaml 里额外配置 user:,开箱即是降权运行。

三、前置条件

部署前需确认服务器满足以下条件,逐项核对可避免绝大多数启动失败。

  1. Docker 与 Compose 插件就绪:
# 检查 Docker 版本与 Compose 插件是否可用
docker --version && docker compose version

实测回显:

Docker version 29.8.1, build 61a5167
Docker Compose version v2.39.4
  1. 磁盘余量充足:full 镜像解压后磁盘占用约 2.5GB,建议预留 5GB 以上。
# 确认磁盘余量
df -h / | tail -1

实测回显:

/dev/sda2      443G  147G  278G  35% /
  1. 目标端口未被占用:本文用宿主机 8130 端口,确认其空闲。
# 检查端口占用(无输出即空闲)
ss -ltn | grep 8130

实测回显(空闲状态,grep 无命中后以退出码确认):

(无输出,端口空闲)
  1. 镜像拉取网络可达:官方镜像发布在 Docker Hub。国内网络拉取缓慢时可配置镜像加速器或代理;本次实测环境 Docker 守护进程已配置代理 192.168.1.62:7897,直接拉取成功。若拉取超时,在 /etc/docker/daemon.json 配置 registry-mirrors 或 HTTP 代理后重启 Docker 再试。

四、部署步骤

本章从建目录、写编排文件到启动、探活,给出完整的 0→1 部署主线,每一步都附实测回显。

4.1 创建部署目录

# 创建部署目录与字体挂载目录
mkdir -p /opt/gotenberg/fonts
cd /opt/gotenberg

目录用途:compose.yaml 放部署定义;fonts/ 用于向服务内挂载自定义字体(见第八章),本次实测放入了一份中文字体 DroidSansFallbackFull.ttf。

4.2 编写 compose.yaml

在 /opt/gotenberg/compose.yaml 写入以下内容(与本次实测文件一致):

name: gotenberg-8-stack

services:
  gotenberg:
    image: gotenberg/gotenberg:8
    container_name: gotenberg-8-api
    hostname: gotenberg.local
    ports:
      - "8130:3000"
    networks:
      gotenberg-net:
        ipv4_address: 10.89.57.10
    volumes:
      - /opt/gotenberg/fonts:/usr/local/share/fonts/custom:ro
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "--fail", "http://localhost:3000/health"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 10s

networks:
  gotenberg-net:
    driver: bridge
    ipam:
      config:
        - subnet: 10.89.57.0/24

逐项说明:

  • name: gotenberg-8-stack:显式指定 Compose 项目名。多套服务共存于一台宿主机时,显式项目名可避免同名项目 down 时误删其他服务的资源;
  • image: gotenberg/gotenberg:8:官方 full 变体,跟随 8.x 最新稳定版;
  • ports: "8130:3000":宿主机 8130 映射到服务默认监听的 3000 端口,宿主机端口可按实际规划调整;
  • networks + ipam:自定义 bridge 网络并固定网段与地址,便于同网络内其他服务按固定 IP 或容器名访问;网段需避开宿主机已有网段(10.89.57.0/24 为本次实测选用,无冲突即可);
  • volumes:把宿主机字体目录只读挂载到 /usr/local/share/fonts/custom(挂载点说明见第八章);
  • restart: unless-stopped:异常退出自动拉起,人工停止后不自动重启;
  • healthcheck:用 curl --fail 请求自身 /health 路由,30 秒一次、失败 3 次判为 unhealthy,启动后给 10 秒宽限期。

⚠️ 注意:Gotenberg 的配置不写在 compose.yaml 的自定义配置文件里,而是通过 environment 环境变量或覆盖启动 command 传参(见第七章)。切勿试图挂载一个「gotenberg.conf」——它没有配置文件。

4.3 拉取镜像并启动

# 在部署目录内拉取镜像并后台启动
docker compose up -d

实测回显:

[+] Running 2/2
 ✔ Network gotenberg-8-stack_gotenberg-net  Created
 ✔ Container gotenberg-8-api                Started

首次执行会先拉取镜像(full 变体约 2.5GB,视带宽需数分钟);回显中网络与实例一次性创建即说明编排无语法问题。

4.4 确认运行状态与健康检查

# 查看编排状态,等待 healthcheck 通过
docker compose ps

实测回显(启动约 20 秒后):

NAME               IMAGE                     COMMAND                  SERVICE      CREATED          STATUS                     PORTS
gotenberg-8-api    gotenberg/gotenberg:8     "gotenberg"              gotenberg    28 seconds ago   Up 26 seconds (healthy)    0.0.0.0:8130->3000/tcp, [::]:8130->3000/tcp

STATUS 列出现 (healthy) 即健康检查已通过。

# 查看启动日志确认模块加载
docker compose logs gotenberg | head -12

实测回显:


  _____     __           __
 / ___/__  / /____ ___  / /  ___ _______ _
/ (_ / _ \/ __/ -_) _ \/ _ \/ -_) __/ _ '/
\___/\___/\__/\__/_//_/_.__/\__/_/  \_, /
                                   /___/

A Docker-based API for converting documents to PDF.
Version: 8.39.0
-------------------------------------------------------
[SYSTEM] modules: api chromium exiftool libreoffice libreoffice-api libreoffice-pdfengine pdfcpu pdfengines pdftk prometheus qpdf webhook
[SYSTEM] chromium: Chromium ready to start

日志确认三点:版本 8.39.0、全部模块(api/chromium/exiftool/libreoffice/pdfcpu/pdfengines/pdftk/prometheus/qpdf/webhook)已加载、Chromium 就绪待启动(默认首次转换时才拉起)。

4.5 API 探活验证

# 健康检查路由探活
curl -s http://localhost:8130/health

实测回显:

{"status":"up","details":{"chromium":{"status":"up","timestamp":"2026-10-28T05:08:50.01821323Z"},"libreoffice":{"status":"up","timestamp":"2026-10-28T05:08:50.018209691Z"}}}
# 版本路由与根路由状态码
curl -s http://localhost:8130/version; echo
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8130/

实测回显:

8.39.0
200

三连探活全部符合预期:/health 返回整体 up 且 Chromium、LibreOffice 两个引擎均 up;/version 返回与镜像一致的版本号;根路由返回 200。

💡 说明:/health 详情里 Chromium/LibreOffice 状态为 up 表示引擎进程可正常拉起。若某引擎异常,对应条目会变为其他状态,此时应先查 docker compose logs 中的启动报错。

五、数据持久化说明

本节解释 Gotenberg 的无状态设计与持久化需求,避免读者在存储规划上走弯路。

Gotenberg 不需要数据卷做业务持久化:它是无状态转换服务,每个请求的输入文件与输出 PDF 都在请求生命周期内处理完毕,临时文件存放在服务内部临时目录并在请求结束后清理。没有数据库、没有索引、没有需要跨重启保留的状态——down 再 up 服务即恢复如初。

实际需要挂载宿主机目录的只有三类场景:

  1. 自定义字体(只读挂载,见第八章)——解决中文等语言字体缺失问题;
  2. TLS 证书(只读挂载)——启用 HTTPS 时把证书与私钥文件传入,配合 API_TLS_CERT_FILE/API_TLS_KEY_FILE 使用;
  3. 核心转储调试(可选)——LibreOffice 异常崩溃排查时官方建议开启 core dump 目录挂载,常规部署无需。

因此本文 compose.yaml 中唯一的业务性挂载就是字体目录。日志输出到标准输出,由 Docker 日志驱动统一管理(docker compose logs 查看),也不需要单独落盘。

💡 说明:正因为无状态,Gotenberg 的水平扩展非常简单——把 compose.yaml 里的服务在多台服务器各起一份,前面挂任意负载均衡即可,实例之间零协调。这也是它与「自带存储的有状态服务」在部署上最大的区别。

六、环境变量表

Gotenberg 的所有配置项都有「命令行参数」与「环境变量」两种等价写法,在 Compose 中首选环境变量。本节列出部署阶段最常用的环境变量子集(完整参数体系见 《Gotenberg 配置参数详解》)。

环境变量命名规则:命令行参数 --api-port 对应环境变量 API_PORT——把参数名的连字符去掉、转大写即可。仅 Basic 认证的用户名密码两个变量带 GOTENBERG_ 前缀。

环境变量默认值说明
API_PORT3000API 监听端口,改端口时需同步调整 ports 映射
API_BIND_IP0.0.0.0监听绑定的 IP 地址
API_TIMEOUT30s单请求处理时限,超时返回 503
API_START_TIMEOUT30s服务自身启动时限
API_BODY_LIMIT无限制multipart 请求体上限,如 50MB
API_ENABLE_BASIC_AUTHfalse开启 Basic 认证开关
GOTENBERG_API_BASIC_AUTH_USERNAME无Basic 认证用户名(认证开启时必填)
GOTENBERG_API_BASIC_AUTH_PASSWORD无Basic 认证密码(认证开启时必填)
API_ENABLE_DEBUG_ROUTEfalse开启 /debug 运行时配置导出路由
LOG_LEVELinfo日志级别(debug/info/warn/error)
CHROMIUM_AUTO_STARTfalse服务启动即预热 Chromium(默认首次转换时启动)
LIBREOFFICE_AUTO_STARTfalse服务启动即预热 LibreOffice
WEBHOOK_ENABLE—Webhook 特性默认启用,置 WEBHOOK_DISABLE=true 可整体关闭

表格解读:常规内网部署通常只需要动两处——API_TIMEOUT(业务转换耗时大于 30 秒时调大)与认证三件套(API_ENABLE_BASIC_AUTH + 用户名 + 密码)。其余项保持默认即可。

七、配置参数说明

本节演示「改配置 → 重启 → 验证生效」的完整闭环。以两个最常用的配置项为例:请求体上限与 Basic 认证。

示例一:开启 Basic 认证(实测)

在 compose.yaml 的 gotenberg 服务下加入 environment 段:

    environment:
      API_ENABLE_BASIC_AUTH: "true"
      GOTENBERG_API_BASIC_AUTH_USERNAME: admin
      GOTENBERG_API_BASIC_AUTH_PASSWORD: q1w2e3r4
# 应用配置并滚动重建
docker compose up -d

实测回显:

[+] Running 1/1
 ✔ Container gotenberg-8-api  Started

验证认证行为(实测回显):

/health 未带凭据:      HTTP 200   # 健康检查路由豁免认证
转换路由未带凭据:      HTTP 401   # 业务路由要求认证
转换路由带凭据(-u admin:q1w2e3r4): HTTP 200
/version 未带凭据:     HTTP 401   # 版本路由同样受保护
/prometheus/metrics 未带凭据: HTTP 401
不存在路由:            HTTP 404

结论:认证开关对 /version、/prometheus/metrics 与全部转换路由生效,唯独 /health 保持豁免——这是刻意的「liveness 探针友好」设计,负载均衡与编排平台的健康探测无需配置凭据。

示例二:调大请求体上限与超时(配置写法)

    environment:
      API_BODY_LIMIT: "50MB"
      API_TIMEOUT: "60s"

API_BODY_LIMIT 从无限制收紧为 50MB 可防止异常大包打满内存;API_TIMEOUT 调大到 60 秒可容纳慢转换(长网页渲染、大文档导出)。两个变量同样走 docker compose up -d 应用。

⚠️ 注意:环境变量值统一按字符串书写(如 "true"、"50MB")。配置错误时服务可能启动失败,用 docker compose logs gotenberg 查看具体报错项即可定位。

八、配置文件挂载

Gotenberg 没有配置文件,本节说的「文件挂载」是指把字体等资源文件传入服务——这是中文环境部署的关键一环。

问题背景:PDF 渲染依赖字体。服务内预装了 Noto 系列 CJK 字体(实测环境 fc-list 统计共 345 款字体,其中 Noto/文泉驿等 CJK 相关字体 302 款),中文 HTML 与 Office 文档默认即可正常渲染。但遇到小语种、商用授权字体或设计稿指定字体时,就需要把字体文件挂载进去。

挂载方法(本文 compose.yaml 已包含):

    volumes:
      - /opt/gotenberg/fonts:/usr/local/share/fonts/custom:ro

把 .ttf/.otf 字体文件放入宿主机 /opt/gotenberg/fonts/ 后重启服务。验证字体是否被识别:

# 在服务内执行 fc-list 过滤新挂载的字体
docker exec gotenberg-8-api fc-list | grep -i droid

实测回显(挂载 DroidSansFallbackFull.ttf 后):

/usr/local/share/fonts/custom/DroidSansFallbackFull.ttf: Droid Sans Fallback:style=Regular

字体被 fontconfig 识别后,Chromium 与 LibreOffice 转换时即可按字体名引用。移除挂载并重启,字体随之消失——方便做版本化字体管理。

💡 说明:挂载点选 /usr/local/share/fonts/custom 而非覆盖系统字体目录,是只读追加式设计:不破坏内置 Noto 字体集,出问题移除挂载即可回滚。若要「彻底替换默认字体集」,才考虑覆盖 /usr/local/share/fonts 整个目录,但需保证目录内字体完整可用。

九、等价 docker run

不使用 Compose 的读者,可以用单条 docker run 命令实现与本文 compose.yaml 等价的部署。

# 与本文 compose.yaml 等价的最小 docker run
docker run -d \
  --name gotenberg-8-api \
  -p "8130:3000" \
  --restart unless-stopped \
  gotenberg/gotenberg:8

带字体挂载与自定义网络的形式:

# 创建自定义网络(网段按需调整,避开宿主机已有网段)
docker network create --subnet 10.89.57.0/24 gotenberg-net

# 启动:挂载字体目录 + 接入自定义网络
docker run -d \
  --name gotenberg-8-api \
  --network gotenberg-net \
  -p "8130:3000" \
  -v /opt/gotenberg/fonts:/usr/local/share/fonts/custom:ro \
  --restart unless-stopped \
  gotenberg/gotenberg:8

官方文档的最简形式则更短:docker run --rm -p "3000:3000" gotenberg/gotenberg:8——--rm 表示停止后自动清理,适合一次性试用;若要更安全可绑定本机回环 127.0.0.1:3000:3000,仅允许本机访问。

两种方式差异对照:

维度Composedocker run
声明式配置与版本管理✅ compose.yaml 可入库❌ 命令行参数散落
健康检查内建✅ healthcheck 段❌ 需 --health-* 系列参数
多服务编排✅ 原生支持❌ 单服务
一键停止清理docker compose downdocker rm -f 手工

单服务部署两者皆可;计划纳入基础设施代码管理的生产环境建议 Compose。

十、常用运维命令

本节汇总日常运维高频命令,全部为实测可用形态。

# 查看运行状态(含健康状态)
docker compose ps

# 查看最近 100 行日志
docker compose logs --tail 100 gotenberg

# 重启服务(配置变更后也可用 up -d 滚动重建)
docker compose restart gotenberg

# 升级到 8.x 最新版(滚动标签场景)
docker compose pull && docker compose up -d

# 临时拉起命令行做字体等运行时检查
docker exec -it gotenberg-8-api sh

# 停止并清理编排(网络随项目一并清理)
docker compose down

关键命令的实测说明:

  • docker compose pull && docker compose up -d 是滚动升级的标准动作:pull 拉新版,up -d 只重建镜像变化的实例,数据无状态不受影响;
  • 升级后用 curl -s http://localhost:8130/version 核对版本号是否已变;
  • docker compose down 会删除容器与自定义网络;字体目录与 compose.yaml 在宿主机上不受影响,重新 up -d 即完整恢复。

监控接入:Gotenberg 内置 Prometheus 指标端点,路径 /prometheus/metrics(默认路径,可用 PROMETHEUS_METRICS_PATH 改)。典型指标如 gotenberg_chromium_requests_queue_size(Chromium 排队长度)、gotenberg_chromium_restarts_count(Chromium 重启次数)等,可直接被抓取,用于容量观察与告警。

十一、常见问题

本章沉淀部署阶段的高频问题与排障路径,均来自实测或官方文档明确记载的行为。

Q1:启动后 /health 一直 503 或连接被拒?

先看日志:docker compose logs gotenberg。常见两类原因:一是宿主机端口冲突,ports 映射的宿主端口已被占用导致启动失败,换端口即可;二是启动时限太紧,磁盘或 CPU 紧张时初始化超过 API_START_TIMEOUT(默认 30s),可适当调大。健康检查自身也受 healthcheck.start_period 影响,刚启动 10 秒内 unhealthy 属正常。

Q2:中文渲染成方块(豆腐块)怎么办?

根因是字体缺失。先确认内置字体:docker exec gotenberg-8-api fc-list | grep -ci cjk,正常应有数百款 CJK 字体(实测 302 款)。若确需自定义字体,按第八章挂载字体目录并重启,再用 fc-list | grep 字体名 确认识别。字体被识别后重新转换即可。

Q3:开启了 Basic 认证后监控抓取失败?

/prometheus/metrics 受认证保护(实测 401)。两种解法:监控端抓取时携带凭据;或仅对监控来源放宽——由于认证是全服开关,实践中更常见的做法是保留认证并让 Prometheus 配置 basic_auth 凭据。

Q4:镜像拉取超时?

官方镜像在 Docker Hub。按「官方源 → 国内加速器/代理」的顺序处理:先直接 pull;超时则配置镜像加速器(/etc/docker/daemon.json 的 registry-mirrors)或 HTTP 代理后重启 Docker 再拉。本次实测环境走代理 192.168.1.62:7897 拉取成功,拉取大小约 1.5GB(压缩态)。

Q5:如何限制单个转换请求的资源占用?

服务本身不提供单请求级资源配额。工程上的通用做法:入口用 API_BODY_LIMIT 限制请求体大小;编排层限制实例级 CPU/内存;再大的文件与耗时通过 Webhook 异步化削峰。三者组合即可稳定生产行为。

十二、参考链接

  1. 官方安装文档(镜像变体/部署形态):https://gotenberg.dev/docs/getting-started/installation
  2. 官方配置文档(参数与环境变量):https://gotenberg.dev/docs/configuration
  3. 健康检查路由文档:https://gotenberg.dev/docs/system/get-health-check
  4. 本专栏姊妹篇——《Gotenberg 介绍与选型指南》
  5. 本专栏姊妹篇——《Gotenberg 配置参数详解》
  6. 本专栏姊妹篇——《Gotenberg 常用命令与运维实战(核心篇)》