Harbor:镜像分发、权限与维护
容器平台启动应用前,要从镜像仓库取得 manifest、配置和文件层。Harbor 在镜像分发协议之外提供项目权限、机器人账号、扫描、复制和保留策略,使多个团队能够共享仓库服务,并控制哪些镜像可以发布、读取和删除。
仓库故障既可能阻止新实例启动,也可能让回退所需镜像无法取得。因此,镜像交付完成后,还要保存精确镜像身份、维护数据副本,并验证目标环境能实际拉取。
从镜像地址理解 Harbor 的职责
地址中的名称与内容身份
harbor.example.com/team/orders:1.4.0
├─ harbor.example.com Registry 主机;非默认端口需写 :端口
├─ team Harbor 项目,也是授权和配额范围
├─ orders 项目中的 repository
└─ 1.4.0 tag:一个可受策略保护的名称
harbor.example.com/team/orders@sha256:...
└─ digest 指向 manifest 或多平台 index 的内容摘要单平台 manifest 引用配置对象和文件层;多平台 index 进一步引用不同平台的 manifest。按 index digest 拉取时,客户端仍需选择匹配的平台。Docker 本地 image ID 常对应配置对象,不能直接把它填成远端 manifest digest。对象结构见 OCI Image Spec。
tag 默认可以重新指向别的内容。发布系统记录批准的 digest,部署时使用 repository@digest,并为正式标签设置不可变策略。digest 解决内容定位,签名和发布审批再回答内容由谁发布、是否允许进入环境。
推送过程中有哪些参与者
客户端先连接 HTTPS 入口,按 Registry 的认证挑战向 Harbor Core 获取相应 scope 的 token,再向 Registry 上传或读取内容。Core 检查身份和项目权限,Registry 保存 manifest 与 blob,Jobservice 执行复制、扫描等后台工作,数据库保存项目和制品关系,缓存组件承担会话、任务等运行状态。
登录成功后,向另一个项目 push 仍可能被拒绝;一个项目的页面能够打开,也不能说明后台复制或扫描已经完成。观察对象应与动作匹配:上传看客户端结果和 artifact,复制看任务执行结果,扫描看报告状态及所用数据库。
这里使用独立 Linux 主机的 Compose 安装方式。Kubernetes/HA、OCI 附件和供应链扩展见 Harbor 工具主文,基础镜像构建见 Docker。
安装 HTTPS 实例并完成第一轮推送
准备专用 Linux 主机
固定版本为 Harbor v2.15.2。准备 Linux x86-64、Bash、Docker Engine、Compose 插件、OpenSSL、curl 和 tar;小型实验可分配 4 CPU、8 GiB 内存及足够空闲磁盘,生产根据镜像增长与并发重新容量规划。端口 443 提供 HTTPS;80 只在需要重定向时开放。安装前检查 官方前置条件。
本节命令在没有既有 Harbor 的专用主机执行。安装器会生成配置并管理一组容器,不能在未知现有部署目录中直接运行。操作者需要 sudo/Docker 管理权限;这些权限可影响主机,应限制到运维身份。
确定仓库真实域名,例如 harbor.example.com,让客户端与 Harbor 主机都能解析到正确入口。准备该域名的完整证书链和私钥,分别保存到 /opt/harbor-certs/fullchain.pem 与 /opt/harbor-certs/privkey.pem,私钥只让必要管理身份读取。证书申请与续期见 HTTPS 证书;Harbor 的安装要求见 HTTPS 配置。
取得安装器并核验来源
在普通用户的新目录下载指定版本:
WORK=$(mktemp -d)
cd "$WORK"
VERSION=v2.15.2
BASE="https://github.com/goharbor/harbor/releases/download/$VERSION"
curl -q --fail-with-body --location --output harbor-online.tgz \
"$BASE/harbor-online-installer-$VERSION.tgz"
curl -q --fail-with-body --location --output harbor-online.sigstore.json \
"$BASE/harbor-online-installer-$VERSION.tgz.sigstore.json"该版本发布资产提供 Sigstore bundle,不能照旧教程找不存在的 .asc 文件。使用可信安装的 Cosign 执行验证,并约束官方工作流身份:
cosign verify-blob --bundle harbor-online.sigstore.json \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity "https://github.com/goharbor/harbor/.github/workflows/publish_release.yml@refs/tags/$VERSION" \
harbor-online.tgz应验证成功后才解压运行。不要关闭身份、透明日志或证书检查来消除错误;先核对版本对应的资产和工作流。Cosign 的可信安装见 官方安装说明,blob 检查见 签名验证,版本资产与变更见 Harbor v2.15.2。
配置文件与持久数据分开保存
tar -xzf harbor-online.tgz
cd harbor
cp harbor.yml.tmpl harbor.yml
chmod 600 harbor.yml编辑 harbor.yml,保留同版本模板中的其他必需字段,只修改以下项目。下面的域名、密码均需替换成实际值,不能原样运行:
hostname: harbor.example.com
http:
port: 80
https:
port: 443
certificate: /opt/harbor-certs/fullchain.pem
private_key: /opt/harbor-certs/privkey.pem
harbor_admin_password: "替换为管理员独立强密码"
database:
password: "替换为数据库独立强密码"
max_idle_conns: 100
max_open_conns: 900
data_volume: /srv/harbor-datacertificate 和 private_key 是主机上已有文件。data_volume 承载实际持久内容,应放在容量与备份有保障的数据盘;安装目录还保存配置和管理脚本,两者都要保留。初始管理员密码只对首次初始化生效,后续改 harbor.yml 不会自动轮换已有数据库里的账号密码。参数含义见 harbor.yml 配置。
确认主机 80/443 未被其他服务占用,再运行安装器。基础分发不要求扫描器;需要 Trivy 时在安装命令中加入 --with-trivy,同时准备扫描数据库出口与磁盘:
sudo ./install.sh
sudo docker compose ps
curl -q --noproxy '*' --fail-with-body --connect-timeout 3 --max-time 15 \
https://harbor.example.com/api/v2.0/health组件启动后,应看到健康状态,API 健康结果为 healthy;不健康时查看 sudo docker compose logs --tail 100 及配置的日志目录。使用私有 CA 时 curl 加 --cacert /实际路径/ca.crt,客户端也必须信任 CA,不能改成 -k。
独立 Docker 客户端在 /etc/docker/certs.d/harbor.example.com/ca.crt 安装经过校验的 CA;非默认端口的目录名包含端口。信任变更按平台要求生效,安排好可能需要的 daemon 维护窗口。只有自建 CA 才需要这一步,公共可信证书不应随意加入额外根证书。
反向代理部署需要设置真实 external_url,保留认证头与正确转发协议,允许镜像层大小和上传时长。外部地址、证书名称和 token 返回地址必须一致;安装参数中存在代理并不意味着 Docker daemon 的上游代理已配置。
私有项目和机器人账号
以管理员登录,修改初始密码,创建私有项目 ops5。在项目 Robot Accounts 中创建两份独立凭据:publisher 允许该项目 pull/push,reader 只允许 pull,并设到期时间。保存页面导出的完整用户名和秘密,后续客户端不用个人管理员账号。机器人类型、权限与轮换入口见 项目配置。
在已能构建 Docker 镜像的 Linux 客户端,新建空目录并保存下面的 Dockerfile。这里只使用本机生成的静态文件,避免依赖公网基础镜像:
FROM scratch
COPY release.txt /release.txt普通 Docker 操作者执行:
REGISTRY=harbor.example.com
printf 'release=1.0.0\n' > release.txt
docker build --provenance=false -t "$REGISTRY/ops5/message:1.0.0" .
DOCKER_CONFIG=$(mktemp -d)
export DOCKER_CONFIG
read -rp '完整 publisher 机器人用户名: ' ROBOT_USER
read -rsp '机器人密码: ' ROBOT_PASSWORD; printf '\n'
printf '%s' "$ROBOT_PASSWORD" | docker login "$REGISTRY" \
--username "$ROBOT_USER" --password-stdin
unset ROBOT_PASSWORD
docker push "$REGISTRY/ops5/message:1.0.0"push 输出 manifest digest。进入项目核对 repository、tag、digest 与大小,再把该完整 digest 保存到发布记录。机器人名可能含 $,交互读取可以避免 Shell 把它误展开成变量。临时 DOCKER_CONFIG 中可能保存可恢复的认证信息,应限制权限;生产使用凭据助手或流水线秘密管理。
这个 scratch 镜像没有程序入口,用于验证分发,不用于 docker run。真实应用镜像的启动与健康检查另按应用契约测试。
用只读身份按 digest 拉取
退出 publisher,使用 reader 再登录。从刚批准的发布记录取得完整 sha256:...,不要填本地 image ID:
docker logout "$REGISTRY"
read -rp '完整 reader 机器人用户名: ' ROBOT_USER
read -rsp '机器人密码: ' ROBOT_PASSWORD; printf '\n'
printf '%s' "$ROBOT_PASSWORD" | docker login "$REGISTRY" \
--username "$ROBOT_USER" --password-stdin
unset ROBOT_PASSWORD
read -rp '发布记录中的完整 digest: ' DIGEST
docker pull "$REGISTRY/ops5/message@$DIGEST"
docker image inspect "$REGISTRY/ops5/message@$DIGEST" --format '{{json .RepoDigests}}'预期 pull 成功,RepoDigests 包含指定 repository@digest。用 reader 向新的测试 tag push 应收到权限拒绝;只在专用实验项目做这个负例,并先确认 reader 的 pull 已成功,避免把认证失败误判为权限设计正确。
更强的交付验证应在另一台没有这些层缓存的目标平台拉取,并核对应用启动。多平台镜像还要分别验证所需架构;只上传本机单平台镜像再改名,不能补齐其他平台内容。
把分发策略接到实际发布过程
不可变标签、配额与保留
在项目中为正式标签配置 Tag Immutability,例如保护符合 release-* 的标签;先在实验 repository 验证同名标签无法改写,再把规则用于正式项目。可变的开发标签留在另一命名规则中,避免开发流程和正式发布争用同一个名称。
项目配额限制团队可占用的空间。达到配额后,新上传可能被拒绝,即使主机磁盘仍有空间;管理员需要分别看项目配额和底层磁盘。保留策略负责选择留下的 artifact/tag,要排除当前部署和回退窗口需要的版本,并先使用 Dry Run 查看匹配结果。不可变规则与保留删除存在相互约束,不能只看某一条规则的名称推断最终删除结果。
复制完成后验证目的端
管理员在 Registries 添加目标端点,配置受限凭据与可信 TLS;创建 Replication Rule,明确 push-based 或 pull-based、源项目过滤、目标命名空间、触发方式以及是否复制删除。先用独立测试 repository 手工触发,再进入自动调度。配置入口见 复制。
任务进入队列只说明调度请求已接收。继续查看 execution 和逐资源任务是否成功,再使用目的端自己的只读身份按 digest 拉取。多平台 index 的子 manifest、OCI 附件与目标产品兼容性也要检查。若目标发生格式转换,应重新核验其内容身份,不能默认源、目的 digest 必然相同。
复制不等于完整备份:项目权限、全局配置和密钥可能没有复制,误删除也可能随配置传播。灾备端需要独立保留和恢复策略。
Proxy Cache、离线与信任材料
Proxy Cache 项目按需缓存指定上游,消费者改用该项目下的镜像路径。它不自动装下全部上游镜像,也不适合作为团队普通 push 目标;具体访问与缓存规则见 Proxy Cache。
离线交付至少要保存目标平台镜像、所需 manifest/index、签名或其他附件、可信根与验证策略。docker save/load 适合搬运本机已有镜像,但不能假定同时带上远端所有平台和签名附件。跨 registry 完整同步宜使用理解 OCI 对象关系的工具,并在目的端重新验收。
离线安装器包含 Harbor 的服务镜像,但扫描数据库、后续基础镜像、证书信任和升级材料仍需另外准备。禁止用来路不明的公共镜像站临时替换内部正式制品;确需代理时,固定来源和摘要并记录同步结果。
扫描与签名各检查什么
启用 Trivy 后,在 artifact 页面触发扫描,检查任务是否结束、报告是否对应当前 digest、漏洞数据库是否更新。项目可配置阻止拉取超过阈值的镜像,但还需确定“没有扫描结果”和“扫描失败”如何处理。漏洞列表为空可能来自数据库不可用或包识别范围有限,不能直接解释成安全。扫描配置见 Vulnerability Scanning。
签名检查绑定具体 digest 与可信签名者,发布端负责签发,消费或准入端负责执行验证策略。Harbor 保存相关对象并不自动保证所有客户端都会验签;部署工具必须明确拒绝未通过策略的镜像。扫描处理已知漏洞信息,签名处理来源与内容绑定,两者都不能替应用测试。
回收空间、升级与恢复服务
删除与垃圾回收分两步
删除 tag 或 artifact 后,文件层还可能被其他 manifest 引用。Harbor 的垃圾回收寻找可清理内容并释放空间,不能按“删了几个镜像”推断立即释放相同大小的磁盘。
管理员进入 Administration → Clean Up → Garbage Collection,先运行 Dry Run,检查预计删除量与任务日志,再安排 GC。启用“允许回收未打标签的 artifact”会改变无标签内容的保留方式;按 digest 部署的对象可能没有 tag,必须先与部署记录核对。GC 对近期上传存在保护窗口,也可能因此暂时不释放刚删除内容。行为与限制见 Garbage Collection。
回收后检查任务结果、实际可用空间,再从客户端读取应保留的版本。停止 GC 只能阻止继续处理,已经删除的数据需要从备份恢复。不要直接进入 Registry blob 目录删文件,也不要为了尽快释放空间跳过引用判断。
独立 Compose 实例的冷备份
保存 harbor.yml、生成配置、证书与加密密钥、数据库、Registry 数据,以及所用 Harbor/组件镜像版本。使用外部数据库或对象存储时,其备份也必须进入同一个恢复计划。只导出几份镜像不能恢复机器人权限和项目设置。
对于前面使用本地 data_volume 的独立主机,在维护窗口先停止写入入口、等待后台任务处理完毕,再在安装目录停止整组服务。确认没有其他实例写这些数据后,使用新的备份目录归档:
# 当前目录必须是这一个 Harbor 的安装目录
pwd
sudo docker compose ps
sudo docker compose stop --timeout 120
sudo docker compose ps --status running
# 上一条不应再列出运行中的服务
BACKUP=$(mktemp -d)
sudo tar --acls --xattrs --numeric-owner -czf "$BACKUP/harbor-data.tgz" \
-C /srv harbor-data
sudo tar --acls --xattrs --numeric-owner -czf "$BACKUP/harbor-install.tgz" \
-C "$(dirname "$PWD")" "$(basename "$PWD")"
sudo tar --acls --xattrs --numeric-owner -czf "$BACKUP/harbor-certs.tgz" \
-C /opt harbor-certs
sudo sha256sum "$BACKUP/harbor-data.tgz" "$BACKUP/harbor-install.tgz" \
"$BACKUP/harbor-certs.tgz"
sudo docker compose startGNU tar 的退出状态必须成功;归档中含秘密,使用受限加密存储。安装目录、数据目录和证书目录的实际路径如果不同,先核对再替换,不要扩大到整个根目录。停机期间数据不变,文件备份才能对应同一个状态。
恢复在隔离的新主机进行:先校验可信摘要,恢复相同目录结构、属主和权限,加载同版本镜像,再启动服务。先阻断指向原生产系统的复制、Webhook 等出站任务,确认项目、机器人读取权限、样本 digest 和完整层下载正确后,才考虑切换入口。域名变化还需同步证书与 external_url。
v2.15.2 的数据库升级需要额外维护窗口
这一版本会把内置 PostgreSQL 从 15 升到 18,启动时执行 pg_upgrade,缓存后端也改为 Valkey。升级后初始化可能更久,不能把耗时简单判成无响应后强制反复重启。发行说明还列出非 ASCII 数据相关的索引重建注意事项;出现机器人权限异常、列表卡住等现象时,按说明在维护窗口调查索引。
升级应先用备份克隆验证,按 升级与数据迁移确认原版本是否支持直接迁移,再使用目标版本 prepare 迁移配置。不要直接复制一个新 docker-compose.yml 覆盖旧环境。
数据库格式或 schema 已变时,回退需要原程序、原配置和升级前一致数据。旧数据库镜像直接挂载 PostgreSQL 18 的目录无法完成回退。恢复时间、回退所需镜像与足够磁盘,都应在升级前准备。
常见失败的检查顺序
| 现象 | 先检查 | 处理后如何确认 |
|---|---|---|
| x509/证书名称错误 | 真实连接主机、SAN、证书链、客户端 CA 与端口目录 | 保持 TLS 校验执行 login 和 pull |
| login 成功,push denied | 完整机器人名、项目、pull/push 权限、配额、不可变规则 | 专用测试 tag 成功,reader 写入仍失败 |
| manifest unknown | repository、tag/digest、复制任务及保留删除记录 | 从指定目标端重新按完整 digest 拉取 |
| no matching manifest | 客户端平台与 index 子 manifest | 构建并发布缺失平台,再在目标架构拉取 |
| 大层上传失败 | 代理请求体限制、超时、磁盘、Registry 日志 | 使用同一路径重传并完成 manifest 提交 |
| 扫描/复制一直排队 | Jobservice、缓存、目标端认证和网络 | 具体任务结束,并验证报告或目的 artifact |
| 删镜像后空间未降 | 共享层引用、GC 结果与保护窗口 | 检查实际磁盘,不手工删 blob |
| 升级后异常 | 数据迁移日志、数据库主版本、索引与旧配置 | 按发行说明修复,或恢复升级前整套状态 |
持续监控 API 错误率、push/pull 延迟、磁盘增长、数据库与任务队列,并为证书到期和机器人失效建立提醒。仓库健康检查通过后,再定期从目标环境抽样拉取回退镜像,确认恢复材料仍然可用。
权威资料与规范地址
安装与制品校验
项目分发与安全策略
存储维护与升级
| 查阅内容 | 官方地址 |
|---|---|
| 垃圾回收 | https://goharbor.io/docs/2.15.0/administration/garbage-collection/ |
| 升级与迁移 | https://goharbor.io/docs/2.15.0/administration/upgrade/ |
