1. ArchivesSpace 到底是什么,以及为什么值得用 Docker 跑
如果你在图书馆、档案馆、高校或任何跟"存量资料管理"沾边的单位待过,大概率听说过 ArchivesSpace 这个名字。它是一个开源的档案信息管理平台,用来做档案的著录、编目、检索、权限控制和数字化资源关联。简单说,就是给你的馆藏资料建一个规范化的"户口本",每一份档案从入馆、整理、上架到对外开放检索,全生命周期都在这个系统里留痕。
但这个东西有个让 IT 运维不太舒服的特点——它不是一个大一统的应用,而是由多个组件拼起来的。底层要一个数据库存元数据(默认支持 H2 和 MySQL 两种),要一个 Solr 做全文检索引擎,上面还分成 Staff 前端(档案管理员用的工作台)、Public 前端(访客检索界面)、Backend API(RESTful 接口)和 Indexer(索引同步服务)。以前部署一套,你得手动装 Java 运行时、下载 Solr、装 MySQL、解压 ArchivesSpace 发行包、改配置文件、写系统服务脚本……每个环境变量不一样,依赖版本稍微对不上就启动失败,排错能排到怀疑人生。
用 Docker 跑就完全是另一种体验。镜像把 Java 运行时、ArchivesSpace 应用代码、内置依赖全部打包好,你只需要关心两个问题:数据放哪、端口怎么映射。这也是我为什么写这篇东西的原因——我去年给单位做档案系统试点,前后折腾了三种部署方式,Docker 这条路走得最顺,也最省心。
这篇博文适合谁?两类人。第一类是想快速评估 ArchivesSpace 功能的档案业务人员和 IT 支持人员,你不需要了解 JVM 和 Solr 的内部机制,跟着步骤能跑起来就行。第二类是准备上生产环境的运维工程师,我后面会讲编排方案、数据持久化、备份恢复这些绕不开的硬话题。两种诉求我都会照顾到,不过话说在前面,第一遍建议先按顺序往下走,别跳着看,有些配置互相有依赖关系。
2. 环境准备与镜像选型:动手前先定方案
2.1 基础环境要求
先说你本机(或服务器)需要具备什么条件。ArchivesSpace 官方镜像基于amazoncorretto之类的 OpenJDK 镜像构建,所以只要 Docker Engine 能跑,底层系统是 Ubuntu、CentOS、Debian、Windows Server 甚至 macOS 其实差异不大。我实测的环境是 Ubuntu 22.04 LTS + Docker 24.x + Docker Compose v2,这也是我认为最省心的一套组合。
内存方面,ArchivesSpace 官方建议至少 4GB 可用内存。如果你只是单容器跑着玩,不接 MySQL,2GB 也能勉强跑起来,但 Solr 索引一上来就会很吃力。我建议开发环境 4GB,生产环境至少 8GB。磁盘空间其实不太敏感,应用本体加索引初始 5GB 绰绰有余,大头是以后数字化档案文件存放目录,那个另算。
Docker 安装过程我就不啰嗦了,不同平台的命令网上到处都是。有一个容易忽略的点是 Docker 版本别太老,ArchivesSpace 的镜像经历了多次构建流程调整,老版本 Docker 可能会遇到镜像拉取层校验问题。我建议 Docker Engine 不低于 20.10,Compose 插件不低于 v2.10。在 Ubuntu 上装完以后,先跑一下docker version确认客户端和服务端都正常,再跑docker compose version确认 Compose 可用。
2.2 官方镜像与第三方镜像怎么选
Docker Hub 上搜 ArchivesSpace,你能看到好几类镜像。最稳的肯定是官方那个archivesspace/archivesspace,它跟随 GitHub 仓库同步更新,标签规则也很直白,比如v3.4.1、v3.5.0。我墙裂建议只用官方镜像,原因有二:
一是官方镜像的启动脚本逻辑完整。它会在容器启动时自动执行数据库迁移(如果你配置了外部数据库但库是空的,它会建好全部表结构)、初始化和默认配置生成。第三方镜像很多是把发行包解压进镜像就完事,缺少这层逻辑,你往往得手动进容器去跑aspace db:migrate。
二是安全更新有保障。档案系统里存的是真实业务数据,安全基线比普通内部工具高一个档次,用官方镜像至少能说明构建过程可控。
版本选择上,我现在会用最新的 3.x 稳定版。3.x 相比 2.x 在 UI、OAI-PMH 接口、数字对象处理上都有明显改进。但有一点要注意,ArchivesSpace 文档和社区帖子更新速度跟不上版本迭代,网上很多教程是 2.x 时期的,数据库配置项、环境变量名有变化,往下看你就能感受到这个坑。
# 查看官方镜像所有可用版本标签 docker pull archivesspace/archivesspace:latest docker image inspect archivesspace/archivesspace:latest --format '{{.Config.Labels}}'先拉 latest 标签,通常指向最新的稳定版,但不建议生产环境长期用 latest,后续我会讲怎么把版本锁死。
3. 先把服务跑起来:单容器模式速览
3.1 端口划分与首次启动
ArchivesSpace 最让人困惑的一点是它默认占用一堆端口。官方镜像里已经把这些端口通过 ENV 和 EXPOSE 声明好了,单容器模式下最省事的启动命令是这样:
docker run -d \ --name aspace \ -p 8080:8080 \ -p 8081:8081 \ -p 8082:8082 \ -p 8083:8083 \ -v aspace_data:/archivesspace/data \ -v aspace_logs:/archivesspace/logs \ archivesspace/archivesspace:v3.4.1这四个端口各管一摊,给你捋清楚:
| 端口 | 服务 | 用途说明 |
|---|---|---|
| 8080 | Staff 前端 | 档案管理员登录、编目、管理的工作台 |
| 8081 | Backend API | RESTful 接口,一般不需要直接浏览器访问 |
| 8082 | Public 前端 | 对外访客的检索浏览界面 |
| 8083 | Solr 管理端 | 内置 Solr 的管理控制台,不对外 |
首次启动会有一个明显的过程:容器起来之后,Solr 初始化、数据库建表、索引同步都要跑一会儿。等 1-2 分钟后访问http://localhost:8080,看到登录页就说明起来了。默认账号是admin,密码也是admin,第一次登录系统会强制你改掉。这个默认密码是安全上最大的坑,后面我会专门说。
3.2 数据持久化没你想的那么简单
单容器模式下,你可能会想"我映射了 volume 就完事了"。错。ArchivesSpace 的数据分三部分,我只映射了其中两部分:
- MySQL 或 H2 数据库文件——默认在
/archivesspace/data下面 - 日志文件——默认在
/archivesspace/logs下面 - Solr 索引——默认在内置数据目录
上面命令里我只映射了data和logs,Solr 索引没做持久化。这样做是有意的:Solr 索引只是检索的缓存,它可以从数据库和文件存储中重建。如果你把 Solr 的索引目录做进持久化,一旦版本升级、索引格式变化,反而会带来一堆兼容性麻烦。官方推荐的思路就是:索引丢了就重建,不是什么大事。
所以单容器模式适合什么场景?适合你第一次接触 ArchivesSpace,想在本地把界面、功能、数据模型都摸一遍,看看它跟你单位的业务是不是匹配。它不适合生产。原因很直接:一是 H2 数据库在并发写入场景下性能不够稳定,二是内置 Solr 和应用抢内存,三是单点,挂了就是挂了。生产环境直接跳到下一节的编排方案。
4. 生产级部署:MySQL + Solr + ArchivesSpace 的编排方案
4.1 为什么生产环境要拆开跑
ArchivesSpace 的生产部署,我建议至少拆成两个容器:数据库独立出来,应用和内置 Solr 放一起。有钱有闲的话可以拆三个——应用一个、Solr 单独一个、MySQL 一个。为什么数据库必须独立?
H2 是嵌入式数据库,它把所有数据存在一个文件里,适合单机演示。但档案系统的特点是什么?数据持续增长、需要定期备份、查询路径复杂。MySQL 的成熟度、备份工具链生态、社区排错经验都远优于 H2。而且把数据库独立出来后,应用容器就可以随时销毁重建,数据库的命不随应用走。
Solr 单独拆一个容器也可以,尤其是你预期索引导入量很大的时候。但我实测下来,个人和中小型团队的体量(几十万条档案记录级别),把 Solr 和应用合在一个容器里问题不大。真正要单独的 MySQL,是我最强调的一条。
4.2 Compose 文件拆解
我自己在用的 compose 方案,是官方示例的改良版,加上了一些环境变量和网络配置。直接给你看完整的docker-compose.yml:
version: "3.8" services: mysql: image: mysql:8.0 container_name: aspace-mysql restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-change_this_root_password} MYSQL_DATABASE: archivesspace MYSQL_USER: aspace MYSQL_PASSWORD: ${MYSQL_PASSWORD:-change_this_aspace_password} command: - --character-set-server=utf8mb4 - --collation-server=utf8mb4_unicode_ci - --innodb_buffer_pool_size=1G volumes: - mysql_data:/var/lib/mysql networks: - aspace_net healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 10s timeout: 5s retries: 10 aspace: image: archivesspace/archivesspace:v3.4.1 container_name: aspace-app restart: unless-stopped depends_on: mysql: condition: service_healthy ports: - "8080:8080" - "8081:8081" - "8082:8082" environment: ASPACE_DB_TYPE: mysql ASPACE_DB_HOST: mysql ASPACE_DB_PORT: "3306" ASPACE_DB_USER: aspace ASPACE_DB_PASSWORD: ${MYSQL_PASSWORD:-change_this_aspace_password} ASPACE_DB_NAME: archivesspace JAVA_OPTS: "-Xms1024m -Xmx2048m" volumes: - aspace_data:/archivesspace/data - aspace_logs:/archivesspace/logs - ./config/config.rb:/archivesspace/config/config.rb:ro networks: - aspace_net volumes: mysql_data: aspace_data: aspace_logs: networks: aspace_net: driver: bridge这个文件有几个细节值得展开讲。
第一,MySQL 8.0 的字符集参数。档案系统里中文是绝对的主角,MySQL 8.0 默认字符集虽然是 utf8mb4,但保险起见我仍然在启动命令里显式声明。千万别用 MySQL 5.7 的默认配置直接连,排序规则不对会导致中文检索结果跟你预期不一致。
第二,healthcheck 的用途。depends_on加上condition: service_healthy,是确保应用容器等数据库真正就绪后才启动。要是没这个条件,应用容器起来发现连不上数据库,不会自动重试,而是直接退出。这是容器编排里最常见的怪问题——不是你的配置错了,是启动顺序没管好。
第三,JAVA_OPTS 内存设置。这个变量不是随便传的。ArchivesSpace 实际上同时启动四个后台 Java 进程(backend、frontend、public、indexer),官方启动脚本会把JAVA_OPTS的基础参数应用到这几个进程上,同时每个进程还有自己的额外内存参数控制。我给的是 1G 初始堆、2G 最大堆,这是基于含内置 Solr 的场景调过的。机器内存只有 4G 的话,JAVA_OPTS 最多给 2G 最大堆,否则容器会 OOM。
第四,config.rb 挂载。容器外的配置文件通过只读方式挂进容器,这是生产环境管理配置的标准做法。文件内容长什么样,下一小节展开。
4.3 关键配置项 config.rb 详解
config.rb是 ArchivesSpace 所有运行时配置的集中地。容器化部署下,最合理的做法是你在宿主机建好这个文件,然后像上面 compose 那样挂载进去。我的最小生产配置长这样:
# 应用基础地址,生产环境务必改成真实域名或IP AppConfig[:backend_url] = "http://localhost:8081" AppConfig[:frontend_url] = "http://localhost:8080" AppConfig[:public_url] = "http://localhost:8082" # 数据库 AppConfig[:db_url] = "jdbc:mysql://mysql:3306/archivesspace?useUnicode=true&characterEncoding=utf8mb4&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai" AppConfig[:db_user] = "aspace" AppConfig[:db_password] = ENV['ASPACE_DB_PASSWORD'] # 文件存储目录 AppConfig[:file_store_path] = "/archivesspace/data/files" # 邮件配置(如果你需要系统发通知) AppConfig[:mailto] = "archive-admin@example.com" AppConfig[:notification_from_address] = "no-reply@example.com"这里有个容易搞混的概念:AppConfig[:backend_url]、frontend_url不是给你浏览器访问用的,而是给系统内部各组件互相调用用的。比如 frontend 调 backend 的 API,它会读这个配置。所以域名涉及容器内外的网络差异,容器里localhost指向容器自身,这里如果你把backend_url写成localhost,没问题,因为容器内 frontend 和 backend 在同一网络命名空间,可以直接访问。但如果你用了上节说的单独网络,后端和前端在不同容器里,那backend_url就要写成http://aspace:8081(服务别名)。这是踩坑重灾区。
db_url里面那段allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai我解释一下:MySQL 8.0 的默认认证插件是 caching_sha2_password,JDBC 首次连接时需要允许获取公钥;时区参数则避免容器和宿主机默认 UTC 导致的时间差 8 小时问题。
5. 部署中最容易踩的坑:密码、时区、内存与索引
5.1 默认密码不只是 admin/admin
前面提到默认账号密码是 admin/admin,每次新部署都会强制改。但你可能不知道还有个隐藏级别:系统初始化后,除了 admin 账号,ArchivesSpace 还会创建一组固定 API 账号,比如用于 OAI-PMH 的oai用户,用于后端程序的aspaceadmin。这些账号的初始密码也在官方文档里写得明明白白,生产环境务必一并用 SQL 改掉,或者至少设上强密码策略。
实际运维里我发现一个更隐蔽的问题:单容器模式下如果你用了已存在的 volume 重新部署新版本,数据库和缓存都保留,系统会认为你已经初始化过,不会再让你重置密码。如果你丢失了 admin 密码,不能像普通软件那样绕过去。怎么办?我做过一次,是通过直接改数据库表里的密码哈希,拿一个已知密码的哈希替换进去。这不是什么正规操作路径,但急等用的时候确实能救命。建议各位部署完成之后就立刻把管理员密码记录到企业密码管理工具里,这事拖不得。
5.2 时区问题:日志和记录时间差 8 小时
国内部署最容易忽略的就是时区。默认容器时区是 UTC,你的档案元数据如果记录了时间(比如创建时间、入库时间),显示出来会比北京时间慢 8 小时。修改方式有三种:
- 在 compose 的环境变量里加
TZ=Asia/Shanghai - 手动挂载
/etc/localtime:/etc/localtime:ro - 在数据库 JDBC URL 里指定
serverTimezone=Asia/Shanghai
我建议三个一起上。第一个解决容器内进程的系统时间,第二个解决 JVM 读取宿主时区,第三个解决 MySQL 连接会话时区。只配其中一个,后面 Log 索引出来的时间戳照样对不齐。
5.3 Solr 索引不同步的排查思路
跑了几个星期以后,你可能会碰到这个现象:档案记录明明在后台能看到,但前台检索就是搜不到。或者新导入的记录没有被索引。看起来像 Solr 挂了,但去 8083 一看,核心还在,commit 也正常。
这时候先别急着重建索引,按这个顺序排查:
# 1. 看应用日志里有没有索引同步报错 docker logs aspace-app 2>&1 | grep -i indexer # 2. 看内置 Solr 的日志 docker exec -it aspace-app /bin/bash find /archivesspace/logs -name "*.out" -o -name "*.log" | xargs grep -i solr最常见的原因是内存不足导致 Indexer 进程被 OOM Killer 杀了,或者非常罕见地死锁。遇到这种情况,重启应用容器一般能解决——索引进程会重新拉起,从上次的位置继续同步。如果反复出现,就要调大JAVA_OPTS或者单独拆分 Solr 容器了。
最万不得已的办法是触发全量索引重建。在后台管理界面,进入系统设置能找到重置索引的选项,或者从命令行执行:
docker exec -it aspace-app /archivesspace/scripts/indexer_reindex_all.sh这个操作会重新扫描全部档案记录,数据量大的时候耗时较长,建议在低峰期执行。
5.4 端口映射踩坑:本机已经占用 8080
很多人第一次部署就栽在端口冲突上。服务器上已有的监控系统、Java 应用、Nginx,哪个都可能占了 8080。解决办法不是改容器里的端口——ArchivesSpace 启动脚本写死了一些端口常量——而是改宿主机映射的左侧端口。比如你有服务占了 8080,那就:
ports: - "8090:8080" - "8091:8081" - "8092:8082"但要注意,一旦改了宿主映射,config.rb 里的frontend_url等配置必须同步改。因为这个配置不仅给浏览器访问用,还参与一些回调逻辑(比如后台生成导出文件的下载链接),不保持一致就会出现"页面能登录但下载文件 404"的怪现象。
6. 档案数据不能丢:备份恢复方案设计
6.1 什么数据需要备份
跟普通业务系统不同,档案系统对数据安全的要求更苛刻。你要备份的东西有三类:
| 数据类别 | 所在位置 | 备份策略 |
|---|---|---|
| MySQL 元数据 | mysql_data 卷 | 每日全量 + 定期归档 |
| 文件存储(数字化档案) | aspace_data 卷的 data/files | 按增量同步 |
| 配置文件 | config/config.rb 和 compose 文件 | 纳入 Git 管理 |
第一类和第二类是最关键的。我见过有同事以为只要备份了 MySQL,整个系统就安全了——后来发现数字化扫描件全在data/files目录里,数据库丢了能恢复记录结构,文件丢了连记录对应的实体都找不回来。所以备份方案里这两样必须捆绑,缺一不可。
6.2 用 mysqldump 做一致性备份
用 Docker volume 做备份有个坏处:你把 mysql volume 直接拷贝副本,只能保证文件存在,不保证数据库一致性。恩,正常情况下 MySQL 8.0 的 InnoDB 崩溃恢复机制能处理这种文件级拷贝,但如果你启用了 binlog,直接从文件拷贝会有一致性问题。稳妥做法永远是走 MySQL 自身的导出工具:
# 进入 MySQL 容器内执行导出 docker exec aspace-mysql \ mysqldump -u root -p \ --single-transaction \ --routines \ --triggers \ archivesspace > aspace_backup_$(date +%Y%m%d).sql--single-transaction参数对于 InnoDB 表很重要,它能在不锁表的情况下获得一致性快照。档案系统通常不需要实时备份,每天凌晨一次全量就够了。
6.3 恢复演练:别等灾难发生才学恢复
备份做得再好,没演练过恢复流程等于白做。我建议每季度做一次恢复演练,流程很简单:
# 1. 新建一个临时 MySQL 容器,导入备份 # 2. 修改 compose 文件指向这个临时库 # 3. 启动应用容器,确认数据可检索恢复时有个细节:如果你用了采集了一批索引数据,恢复数据库后 Solr 索引并不需要手动清空。启动后 Indexer 会比对数据库记录和索引记录,自动把增量补齐。这一点相当人性化。
6.4 自动化备份脚本实例
给你看我服务器上实际在跑的备份脚本,逻辑很简单,但很实用:
#!/bin/bash # /opt/aspace-backup/backup.sh BACKUP_DIR="/data/aspace-backup" DATE=$(date +%Y%m%d_%H%M) KEEP_DAYS=14 # 1. 备份 MySQL docker exec aspace-mysql \ mysqldump -u root -p${MYSQL_ROOT_PASSWORD} \ --single-transaction \ --routines \ --triggers \ archivesspace > ${BACKUP_DIR}/db_${DATE}.sql # 2. 备份文件存储目录 docker run --rm \ -v aspace_data:/source:ro \ -v ${BACKUP_DIR}:/backup \ alpine tar czf /backup/files_${DATE}.tar.gz -C /source data/files # 3. 清理过期备份 find ${BACKUP_DIR} -name "db_*.sql" -mtime +${KEEP_DAYS} -delete find ${BACKUP_DIR} -name "files_*.tar.gz" -mtime +${KEEP_DAYS} -delete注意第二步用了临时 alpine 容器来打包 volume,这样不需要把数据先拷到宿主机再打包,节省磁盘空间也省了一道手续。
7. 对外访问与后续扩展:反向代理和插件管理
7.1 用 Nginx 代理统一入口
生产环境很少有人直接让用户访问 8082 端口,都是套一层 Nginx。我的做法是把 Staff 前端放内网(或者只对工作人员开放),Public 前端通过 443 对外提供 HTTPS 访问。那问题来了,Public 前端部署在 8082,你需要在 Nginx 里做个反向代理:
server { listen 443 ssl; server_name archive.example.edu.cn; # SSL 证书配置省略 location / { proxy_pass http://127.0.0.1:8082; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }这里有个容易被忽略的问题:Public 前端内部会生成一些绝对链接(比如导出文件、分页链接),它使用 config.rb 里AppConfig[:public_url]作为基准。你这个配置如果还写着http://localhost:8082,用户通过https://archive.example.edu.cn访问时,页面上生成的部分链接会跳到localhost:8082去——用户那边直接打不开。正确改法是:
AppConfig[:public_url] = "https://archive.example.edu.cn" AppConfig[:frontend_url] = "http://staff.example.edu.cn:8080"一定记住:public_url写的是外面用户访问的完整外网地址,不是容器内的地址。这个同理也适用于后面如果给 Staff 端做代理。
7.2 插件与定制主题
ArchivesSpace 支持插件机制,官方插件市场有大量的工具(比如批量导入导出、EAD 增强、主题美化)。Docker 部署方式下加插件有两种办法。
第一种是临时进容器把插件目录挂到宿主机,但这种一重建容器就丢,不推荐。第二种是维持一个私有镜像,基于官方镜像做加法:
# Dockerfile ARG ASPACE_VERSION=v3.4.1 FROM archivesspace/archivesspace:${ASPACE_VERSION} COPY plugins/ /archivesspace/plugins/ COPY build/ /archivesspace/build/在 compose 里用build: .替代image: archivesspace/archivesspace:v3.4.1。重点来了:有些插件需要在构建时编译前端资源。ArchivesSpace 后端进程加载插件的同时,还需要把插件的静态资源(CSS、JS)打包进前端界面。纯复制目录不跑构建,插件菜单能看到,但样式和交互功能有可能缺失。如果你发现插件装了前台不生效,大概率是少了build这一步。此时需要进容器里面跑一下:
/archivesspace/scripts/build_plugins.sh然后重启容器,后台管理界面里的插件管理页面会显示当前加载了哪些插件以及版本信息。这套路我建议在正式更新插件之前先在测试环境走一遍,避免生产环境改完重启才发现资源没编译。
7.3 升级路径和版本锁定的经验
容器化部署升级很方便,但 ArchivesSpace 的升级有一个特点:它是"上报式"的,每次启动新版本应用,系统检测到数据库 schema 版本比代码旧,就会自动执行迁移脚本。这个设计对日常升级友好,但你也应该注意:
升级前必做两件事:
- 备份数据库和文件存储(按第六节方案走一遍)
- 只升级一个小版本跨度,不要从 2.x 直接跳 3.x,中间跨了多个迁移脚本,成功率会明显下降
升级操作本身很简单:
# 修改 compose 文件里的镜像版本号 # 然后重新拉取并重建 docker compose pull aspace docker compose up -d aspace容器启动后观察日志,出现类似Database migration completed字样说明迁移成功。如果卡住不动,大概率是数据库表比较大,迁移比较耗时,给它一点耐心。这个升级方式我跑了三个版本,基本零事故。
8. 我踩过的一些额外的小坑和最终建议
补充几个容易被忽略但会让系统不好用的小细节,一并写了。
不要随意开启 Browse 界面的小组件配置。后台管理里有很多可选的社区组件,比如数据可视化面板、地图组件等。这些组件在演示环境看着炫,但实际数据量不大时反而拖慢页面加载,而且有些组件依赖额外的 JavaScript 库,和 Nginx 代理有一些兼容性问题。我一般建议开最少的组件,保持核心检索功能的稳定。
利用容器的资源限制参数。如果你的服务器上还跑着别的服务,建议给 ArchivesSpace 容器加内存限制。比如:
deploy: resources: limits: memory: 4g不加限制的话,JVM 会把宿主机所有空闲内存都吃掉,导致宿主机其他服务跟着遭殃。这是我深有感触的——以前跑一个文档系统,Java 应用经常把宿主机内存耗到触发 OOM,后来统一加限制才消停。但要提醒你,内存限制一旦设低,JVM 启动时就该报错,调整到稳妥值再重启。
善用健康检查接口。ArchivesSpace 后端提供/health接口,可以用来做容器健康检查和监控系统的探针。比如:
curl http://localhost:8081/health返回OK就说明后端活着。我在 Uptime Kuma 和 Prometheus 里都配了这个探针,比看端口通不通靠谱,因为它能确认应用层面的健康状态,而不仅仅是 socket 活着。
最后,整体部署方案的一个核心思路是:数据库和文件存储是命根子,应用容器是可以随时随手扔掉的。这种思路决定了你如何设计容错、备份和升级流程。Docker 的优势在于让你用更快的方式部署和替换应用,但数据的可靠性从来都不是自动化技术替你兜底的,是你自己的备份机制在兜底。
我这一年用下来,ArchivesSpace 配合 Docker 的方式,让档案管理员和 IT 之间的协作顺畅了非常多。前者不必理解 Java 进程和数据库迁移,后者不必手工维护一堆系统服务。你跟着这篇文章走完第一遍,从零到能用的时间大概在半天左右。后面再基于单位实际需求慢慢调整配置和主题就行,这才是这套方案真正的价值所在。