跳转至

RUNBOOK — Harbor 内网镜像仓库(harbor-01)

服务地址:https://192.168.31.31 | 主机:harbor-01(192.168.31.31) 日常运维就照这份做;变更历史看 SOP.md,当前进度与遗留项看 HARBOR-RESULT.md。


1. 服务概览

项 内容
用途 5 个海外镜像源的内网代理缓存:ghcr.io、registry.k8s.io、quay.io、registry.gitlab.com、docker.io
组成 Harbor v2.15.2,9 个容器:harbor-core / harbor-portal / harbor-jobservice / registry / registryctl / harbor-db(PostgreSQL) / redis / nginx / harbor-log
部署方式 Docker CE + compose,安装目录 /opt/harbor;不是 k8s 内工作负载
数据 /data/harbor(数据盘 /dev/vdb,200 G);Docker 镜像层在 /data/docker
依赖 上游 5 个公网源;出网走 Harbor 主机默认路由(→ 旁路由 192.168.31.2 Clash)。香港跳板 SOCKS5 隧道已于 2026-10-01 下线(见 SOP.md)
消费者 4 台 k8s 节点(.10/.13/.14/.15)经 containerd certs.d 接入
异常时的业务影响 节点拉取新镜像会回落直连海外(慢);已在节点本地的镜像不受影响,运行中 Pod 不受影响
重要性 中——影响部署与扩容速度,不影响存量业务运行

重要认知:Harbor 只影响「拉新镜像」。节点上的既有镜像与运行中 Pod 与它无耦合。


2. 接入与凭据

项 值
Web / API https://192.168.31.31(自签证书,浏览器需信任;curl 用 -k)
账号 admin(唯一账号)
口令位置 192.168.31.31:/root/.secrets/harbor-admin.pass(600);数据库口令同在 /root/.secrets/harbor-db.pass
API 免口令调用 192.168.31.31:/root/.secrets/harbor.netrc(600),curl -sk --netrc-file <该文件>
取用口令(不打印) ssh root@192.168.31.31 'cat /root/.secrets/harbor-admin.pass'(仅在需要的终端里用,不要贴进任何文档或日志)
Harbor 主机登录 操作机 root 免密 ssh

节点侧客户端配置片段(已就位,此处供新建节点参考):

# /etc/containerd/certs.d/ghcr.io/hosts.toml
server = "https://192.168.31.31"

[host."https://192.168.31.31"]
  capabilities = ["pull", "resolve"]
  ca = "/etc/containerd/certs.d/ghcr.io/ca.crt"
  override_path = "/v2/ghcr.io"

ca.crt 同目录,内容为 Harbor 主机的 /data/harbor/certs/ca.crt。


3. 日常速查表

# 1) Harbor 整体状态(预期 9 行 Up (healthy))
ssh root@192.168.31.31 'docker ps --format "{{.Names}}\t{{.Status}}"'

# 2) Harbor API 存活(预期 200)
curl -sk -o /dev/null -w '%{http_code}\n' https://192.168.31.31/api/v2.0/ping

# 3) 5 个 proxy 项目是否齐(预期 5 行)
curl -sk --netrc-file <(ssh root@192.168.31.31 'cat /root/.secrets/harbor.netrc') \
  'https://192.168.31.31/api/v2.0/projects?page_size=100' | python3 -c 'import sys,json;print("\n".join(p["name"] for p in json.load(sys.stdin)))'

# 4) 上游出网(预期:隧道单元已删除、1080 无监听)
ssh root@192.168.31.31 '[ -f /etc/systemd/system/harbor-upstream-tunnel.service ] && echo "隧道单元仍在(不期望)" || echo "隧道已下线(正常)"; ss -lnt | grep -c ":1080 "'

# 5) 4 台节点接入文件是否齐(预期每台 5 个 yes)
for ip in 192.168.31.10 192.168.31.13 192.168.31.14 192.168.31.15; do
  echo -n "$ip: "; ssh root@$ip 'ls /etc/containerd/certs.d/ 2>/dev/null | tr "\n" " "; echo'
done

# 6) Harbor 存储占用
ssh root@192.168.31.31 'du -sh /data/harbor/registry; df -h /data | tail -1'

# 7) Harbor 主机磁盘
ssh root@192.168.31.31 'df -h / /data'

# 8) 各上游源已缓存多少仓库
ssh root@192.168.31.31 'for p in ghcr.io quay.io registry.k8s.io registry.gitlab.com docker.io; do echo -n "$p: "; ls /data/harbor/registry/docker/registry/v2/repositories/$p 2>/dev/null | wc -l; done'

# 9) 重启 Harbor(不影响节点已有镜像)
ssh root@192.168.31.31 'cd /opt/harbor && docker compose restart'

# 10) 停 / 起 Harbor
ssh root@192.168.31.31 'cd /opt/harbor && docker compose down'      # 停
ssh root@192.168.31.31 'cd /opt/harbor && docker compose up -d'    # 起

4. 日常操作

4.1 状态检查

见速查表 1~5。判据:9 个容器全 healthy、ping=200、5 个 project 齐、隧道已下线(1080 无监听)。

4.2 启动 / 停止 / 重启

ssh root@192.168.31.31 'cd /opt/harbor && docker compose ps'
ssh root@192.168.31.31 'cd /opt/harbor && docker compose restart harbor-core'
ssh root@192.168.31.31 'cd /opt/harbor && docker compose logs -f --tail=100 harbor-core'

4.3 进入容器 / 主机排障

ssh root@192.168.31.31 'docker exec -it harbor-db psql -U postgres -d registry'   # 数据库
ssh root@192.168.31.31 'docker logs harbor-core --since 10m 2>&1 | tail -50'      # core 日志
ssh root@192.168.31.31 'tail -50 /data/harbor/logs/registry/registry.log'         # registry 日志

harbor-core / registry 是 distroless 镜像,没有 shell,不能 docker exec 进去。

4.4 导入新镜像 / 预热

日常运维不需要主动导入:Harbor 是代理缓存,节点首次拉取会自动从上游取并缓存。仅在两个场景下需要预热:

# 场景:helm hook 镜像或节点重建前,想先把镜像"喂"进 Harbor
cd /home/rain/Documents/services/harbor
vim config/warmup-images.txt      # 加入 <registry>/<repo>:<tag>,每行一条
.venv/bin/python main.py warmup   # 幂等:已入库的自动跳过

4.5 扩容(新增节点)

新节点接入只需两份文件:

NEW=192.168.31.16
for reg in ghcr.io registry.k8s.io quay.io registry.gitlab.com docker.io; do
  ssh root@$NEW "install -d -m 755 /etc/containerd/certs.d/$reg"
  ssh root@192.168.31.31 "cat /data/harbor/certs/ca.crt" | ssh root@$NEW "cat > /etc/containerd/certs.d/$reg/ca.crt"
  ssh root@$NEW "printf 'server = \"https://192.168.31.31\"\n\n[host.\"https://192.168.31.31\"]\n  capabilities = [\"pull\", \"resolve\"]\n  ca = \"/etc/containerd/certs.d/$reg/ca.crt\"\n  override_path = \"/v2/$reg\"\n' > /etc/containerd/certs.d/$reg/hosts.toml"
done
# 把新节点加进 config/default.yaml 的 nodes.k8s 后重跑:
cd /home/rain/Documents/services/harbor && .venv/bin/python main.py deploy-nodes

4.6 删除节点接入(回滚)

ssh root@192.168.31.13 'rm -rf /etc/containerd/certs.d/{ghcr.io,registry.k8s.io,quay.io,registry.gitlab.com,docker.io}'

5. 配置管理

配置 位置 修改流程 生效方式
Harbor 主配置 192.168.31.31:/opt/harbor/harbor.yml(由工程渲染,勿手改) 改工程 config/default.yaml → 重跑 main.py deploy-harbor 重新 install.sh(会重建容器)
工程配置 /home/rain/Documents/services/harbor/config/default.yaml 直接编辑;环境差异另建 config/env.yaml 覆盖 下次运行子命令即生效
上游源清单 config/default.yaml 的 registries 加/改条目后重跑 deploy-harbor(projects 步骤) 按条目幂等收敛
预热清单 config/warmup-images.txt 直接编辑 下次 warmup 生效
节点接入内容 工程按配置渲染 同上 重跑 deploy-nodes,内容变化即更新
Docker 守护配置 192.168.31.31:/etc/docker/daemon.json 改工程 harbor.docker_data_root / harbor.docker_dns 后重跑 内容变化自动重启 docker;容器 DNS 变化需重建容器(deploy-harbor 会做)
上游出网 由 harbor.upstream_proxy.enabled 控制(当前 false,组件走默认路由) 改该开关后重跑 main.py deploy-harbor true:建隧道单元并重建容器;false:停服务 + 删单元 + 撤防火墙放行

易错点:

  1. harbor.yml 的 proxy.no_proxy 必须是逗号分隔字符串,写成 YAML 列表会让 prepare 直接报错(仅在重新启用代理时才会渲染该段)。
  2. upstream_proxy.enabled: false 时不要手删 unit——重跑 deploy-harbor 会一致地关闭(停服务 + 删单元 + 撤放行),手删会与幂等判定冲突。
  3. 改工程配置后不要手工编辑远端文件,以免与幂等判定冲突(下次运行会覆盖回去)。
  4. 容器 DNS 判定读的是容器 resolv.conf 的 ExtServers——不要改回 docker inspect .HostConfig.Dns:该字段在「daemon 级默认 DNS」下为 null,会让 harbor 步恒判 pending、每次重跑都重建容器(2026-10-01 实测踩到)。

6. 备份与恢复

对象 备份策略 位置
Harbor 数据(镜像层 + 数据库) 无自动备份。升级 Harbor 前必须手工备份 /data/harbor(数据盘)
harbor.yml 每次变更前自动 /opt/harbor/harbor.yml.bak.<ts>
节点 certs.d 每次变更前自动打包 <节点>:/root/harbor-nodeaccess-backup/<ts>/certs.d.tar.gz
repo / daemon.json 变更前自动 同目录 .bak.<ts>
本次变更总台账 — backup/README.md

手工备份 Harbor 数据:

ssh root@192.168.31.31 'cd /opt/harbor && docker compose stop'
ssh root@192.168.31.31 'tar -czf /data/harbor-backup-$(date +%Y%m%d).tgz -C /data harbor'
ssh root@192.168.31.31 'cd /opt/harbor && docker compose start'

恢复:停栈 → 解包覆盖 /data/harbor → 起栈 → 用速查表 1、2 验证。

恢复演练尚未做过;首次恢复前建议先在非生产时段验证一次。


7. 监控与告警

关注对象 查看入口 建议阈值
Harbor 存活 速查表 2(/api/v2.0/ping) 非 200 持续 2 分钟 → 告警
容器健康 速查表 1 任一容器非 healthy
磁盘 速查表 7 /data 使用率 >85%
上游出网 速查表 4 隧道应为「已下线」;若被重新启用,则要求 active 且 1080 在听
上游健康 docker logs harbor-core --since 10m \| grep unhealthy 出现 current registry is unhealthy

接入监控的既有路线:本环境已有 textfile → node_exporter:9100 采集方式,Harbor 指标可沿用该路线(本次未接,见 HARBOR-RESULT.md 遗留项 7)。

日志位置:

ssh root@192.168.31.31 'docker logs harbor-core --since 30m 2>&1 | tail -100'   # 应用
ssh root@192.168.31.31 'tail -100 /data/harbor/logs/registry/registry.log'      # 仓库
ssh root@192.168.31.31 'journalctl -u harbor-upstream-tunnel -n 50 --no-pager'  # 隧道(仅重新启用后才存在)

8. 故障处置

场景 1:节点拉镜像仍然很慢 / 仍走海外

症状:节点上 ctr -n k8s.io images pull ghcr.io/... 耗时数分钟;docker.io 等仍超时。

诊断

# 1) 节点上接入文件在不在、内容对不对
ssh root@192.168.31.13 'cat /etc/containerd/certs.d/ghcr.io/hosts.toml'
#    预期含 override_path = "/v2/ghcr.io";缺这行就是原因
# 2) containerd 是否读到了(配置目录必须在 config.toml 里声明)
ssh root@192.168.31.13 'grep config_path /etc/containerd/config.toml'
#    预期 config_path = "/etc/containerd/certs.d"
# 3) Harbor 是否活着
curl -sk -o /dev/null -w '%{http_code}\n' https://192.168.31.31/api/v2.0/ping    # 预期 200
# 4) Harbor 里到底有没有这个制品
curl -sk --netrc-file <(ssh root@192.168.31.31 'cat /root/.secrets/harbor.netrc') \
  'https://192.168.31.31/api/v2.0/projects/ghcr.io/repositories/cloudnative-pg%252Fpostgresql/artifacts/17.6'
#    200=已缓存;404=未缓存,Harbor 会去上游拉(首次必然慢)

处置

诊断结论 动作
hosts.toml 缺失或内容不对 cd /home/rain/Documents/services/harbor && .venv/bin/python main.py deploy-nodes
制品 404(首次入库) 正常现象。想提前喂:在 Harbor 主机 docker pull 192.168.31.31/<project>/<repo>:<tag>
Harbor 不可用 见场景 3

验证:节点上 ctr -n k8s.io images pull <ref>(先 images rm 掉本地)应在数十秒内完成。

场景 2:Harbor 拉不到上游,日志报 registry unhealthy

症状:docker logs harbor-core | grep unhealthy 有输出;节点拉未缓存的镜像报 not found。

最常见成因:刚重建过容器。install.sh 重建 Harbor 后,5 个上游 registry 会被重新健康检查, 期间一律标记 unhealthy,proxy cache 直接返回 404(并非上游真的不可达)。后台健康检查 每 5 分钟一轮,通常下一轮自动恢复;恢复前不要跑 warmup——会连报失败并按失败阈值提前停止 (2026-10-01 实测踩到)。

诊断

# 1) 5 个 registry 健康状态(预期全 healthy)
curl -sk --netrc-file <(ssh root@192.168.31.31 'cat /root/.secrets/harbor.netrc') \
  'https://192.168.31.31/api/v2.0/registries?page_size=100' | \
  python3 -c 'import sys,json;[print(" id=%s %-22s status=%s"%(r["id"],r["name"],r["status"])) for r in json.load(sys.stdin)]'
# 2) 容器内到上游是否可达(走默认路由 → 旁路由 Clash)
ssh root@192.168.31.31 'docker exec harbor-core curl -s -o /dev/null -m 12 -w "%{http_code}\n" https://ghcr.io/v2/'
#    预期 401(可达);000=不通
# 3) 容器 DNS 是否为公共 DNS(不能解析成 Clash fake-ip 的 198.18.x.x)
ssh root@192.168.31.31 'docker exec harbor-core cat /etc/resolv.conf | grep ExtServers'
#    预期 [223.5.5.5 119.29.29.29]
# 4) 宿主侧上游带宽(默认路由 → Clash)
ssh root@192.168.31.31 'curl -s -m 20 -o /dev/null -w "%{speed_download} B/s\n" https://speed.cloudflare.com/__down?bytes=10485760'

处置

诊断结论 动作
刚重建过容器、registry 全 unhealthy 等一轮(≤5 分钟)后复查即可;期间不要跑 warmup
等待后仍 unhealthy,但容器内到上游可达 重启 harbor-core 触发新一轮检查:cd /opt/harbor && docker compose restart harbor-core
容器内到上游不通 查默认路由与旁路由:ssh root@192.168.31.31 'ip route get 8.8.8.8'(应为 via 192.168.31.2)
带宽显著低于 1 MB/s 到旁路由 192.168.31.2 看 OpenClash 主组所选节点与 /root/speed_select.log
曾重新启用过隧道且未恢复 确认 harbor.upstream_proxy.enabled: false 并重跑 deploy-harbor

验证:docker logs harbor-core --since 2m | grep unhealthy 不再出现;拉一个未缓存镜像成功。

场景 3:Harbor 容器起不来 / 页面打不开

症状:docker ps 有容器非 healthy,或浏览器无法访问 https://192.168.31.31。

诊断

ssh root@192.168.31.31 'cd /opt/harbor && docker compose ps'
ssh root@192.168.31.31 'docker logs harbor-core --tail=50 2>&1'
ssh root@192.168.31.31 'df -h / /data'                                    # 磁盘满是最常见原因
ssh root@192.168.31.31 'ls -Zd /data/harbor'                              # 预期含 container_file_t
ssh root@192.168.31.31 'curl -sk -o /dev/null -w "%{http_code}\n" https://192.168.31.31/api/v2.0/ping'

处置

诊断结论 动作
/data 使用率满 清理旧缓存(Harbor 控制台按项目删制品),或扩 /dev/vdb
SELinux 上下文丢失 semanage fcontext -a -t container_file_t '/data/harbor(/.*)?'; restorecon -R /data/harbor 后 docker compose restart
配置被手改坏 重跑 main.py deploy-harbor(会用工程模板重新渲染 harbor.yml)
以上都不是 cd /opt/harbor && docker compose down && ./install.sh

验证:速查表 1、2 恢复正常。注意:Harbor 停机期间节点拉新镜像会回落直连(慢),存量 Pod 不受影响。

场景 4:节点 containerd 异常或 Pod 起不来

症状:ImagePullBackOff;systemctl status containerd 异常。

诊断

ssh root@192.168.31.13 'systemctl is-active containerd; ls -l /etc/containerd/certs.d/*/'
kubectl get pods -A | grep -Ev 'Running|Completed'

处置:先回滚接入文件(这是最可能的变更点),确认恢复后再排查:

ssh root@192.168.31.13 'rm -rf /etc/containerd/certs.d/{ghcr.io,registry.k8s.io,quay.io,registry.gitlab.com,docker.io}'
ssh root@192.168.31.13 'systemctl restart containerd'     # 仅在 containerd 确实异常时才重启

验证:systemctl is-active containerd = active;受影响 Pod 恢复正常。


9. 安全与权限

项 说明
Harbor 账号 仅 admin;proxy cache 项目为 public,节点侧拉取无需凭据
凭据存放 192.168.31.31:/root/.secrets/(700),三个文件均 600;不入工程目录、不入文档、不打终端
CA 私钥 /data/harbor/certs/ca.key(600),不出 Harbor 主机
上游出网 当前无隧道:组件经 Harbor 主机默认路由出网(旁路由 Clash)。曾用隧道监听 0.0.0.0:1080(firewalld 仅放行 172.16.0.0/12 与 127.0.0.1),2026-10-01 已下线
隧道凭据(仅重新启用时相关) Harbor 主机 /root/.ssh/id_ed25519 → 香港跳板 authorized_keys;/usr/local/sbin/harbor-ssh 保留未删
证书轮换 见 SOP.md 第 3 节:重跑 deploy-harbor(证书步骤)→ 再重跑 deploy-nodes 分发新 CA
访问控制 节点侧无新增账户;操作需 root(SSH 免密)

10. 容量与性能

项 当前值
/data 容量 / 余量 200 G / 约 198 G
Harbor 存储占用 4.9 GB(58 条清单已入库 57 条)
k8s 集群镜像总量参考 单节点 containerd 存储约 15 G
上游拉取速度(2026-10-01 实测) 经默认路由(Clash)各源镜像层:ghcr 4.40、registry.k8s.io 5.70、quay 6.86、docker.io 1.28 MB/s;同日香港隧道仅 2.4 KB/s(已下线)
内网拉取速度 节点 ← Harbor 命中缓存后 40~47 MB/s

扩容触发条件:/data 使用率 >85% → 删旧缓存或扩盘。

已知瓶颈:上游链路,速度取决于旁路由 Clash 当前所选节点(由 speed_select.rb 每 5 分钟巡检选优)。可选手段:Harbor 侧并发拉取(warmup.concurrency,默认 4)。若未来重新启用香港隧道:其瓶颈在「家宽 → 香港」这条链路(2026-10-01 实测丢包 13.3%、仅 2.4 KB/s),不在香港主机性能上(该主机直连 cloudflare 实测 41 MB/s)。


11. 附录

文件 说明
SOP.md 变更实施、验证与回滚(含全部踩坑)
HARBOR-RESULT.md 结果回填与遗留项
backup/README.md 备份台账
/home/rain/Documents/services/harbor/ 实现体工程;main.py --help 看子命令
HARBOR-HANDOFF.md 原始需求规格书

修订记录

日期 变更
2026-10-01 首次建立(随 Harbor 部署与节点接入变更交付)
2026-10-01 上游加速隧道下线、组件改走默认路由:修订第 1(依赖)、3(速查表 4)、4.1(判据)、5(配置管理与易错点)、7(监控与日志)、8(场景 2 重写)、9(安全)、10(容量与性能)各节

来源:/home/rain/Documents/k8s_ins/ghcr-slow-20261001/RUNBOOK.md | 最后更新:2026-10-01 14:33(由 build/sync.py 同步,请勿在站点侧修改)