由于时钟偏移导致推送镜像失败并返回 500 或 Unauthorized

问题描述

在具有多个副本的 Harbor 部署中(例如,Harbor Core 有 2 个或更多 Pod),即使凭据正确,用户也可能遇到以下一种症状:

  • docker push 失败,并显示 unauthorized: unauthorized to access repository
  • 在浏览标签时,Harbor UI 返回 500 Internal Server Error
  • 从容器平台拉取镜像列表时,偶尔失败。

这些症状通常是间歇性的——对同一操作重试后可能成功,因为负载均衡器会将请求路由到不同的 Core Pod。

根本原因

Harbor 组件使用有时效限制的令牌(JWT)来认证内部调用。当承载不同 Harbor 组件 Pod 的节点(通常是 harbor-coreharbor-registry)系统时钟未同步时,一个组件签发的令牌会被另一个组件拒绝,并报错为 not valid yetexpired

即使是几秒钟的时钟漂移,也足以导致令牌验证失败。

上游参考:

故障排查

检查 Harbor Core Deployment 的日志。以下错误表明存在时钟偏移问题:

2023-10-12T07:10:59Z [ERROR] [/pkg/token/token.go:66]: parse token error, token is not valid yet
2023-10-12T07:10:59Z [WARNING] [/server/middleware/security/v2_token.go:48][requestID="0968ba9698aa27dc3e07fce7fcd62b9a"]: failed to decode bearer token: token is not valid yet

你可以通过将 Harbor Core 缩容为单个副本来验证这一假设。如果在仅有一个 Pod 时问题消失,则可以确认问题是 Pod 之间的时钟偏移,而不是其他身份验证问题。

kubectl -n <NAMESPACE> scale deployment <RELEASE>-harbor-core --replicas=1

要检查承载 Harbor 组件 Pod 的每个节点上的时钟,请执行以下操作:

# 列出每个 Harbor Pod 调度到哪个节点上
kubectl -n <NAMESPACE> get pods -l app=harbor -o wide

# 在每个列出的节点上,检查当前时间
date -u

这些节点之间任何大于2 秒的时间偏差都必须修正。

解决方案

使用 NTP(或 chrony)同步所有集群节点的系统时钟。时钟收敛后,令牌验证错误会停止,推送/拉取操作也将稳定成功。

一般要求:

  • 承载 Harbor Pod 的所有节点都必须同步时钟。
  • 任意两个节点之间的偏差应小于 2 秒
  • 使用一个可靠且每个节点都可访问的 NTP 源。

在完成时钟同步后,如果你在故障排查期间修改过 Harbor Core 的副本数,请恢复原始副本数:

kubectl -n <NAMESPACE> scale deployment <RELEASE>-harbor-core --replicas=<ORIGINAL_REPLICAS>

说明

  • 此类问题并不特指 Harbor Core。任何跨节点部署且时钟存在偏差的 Harbor 组件,都可能出现类似的令牌验证失败。
  • 重启 Harbor Pod 不是一种临时解决方案——只要底层时钟仍不同步,令牌就会持续被拒绝。