# FAQ 与故障排查

## 快速判断

| 现象 | 优先检查 |
| --- | --- |
| `401 Unauthorized` | 是否对正确的 SparkCR host 执行了登录 |
| `429 Too Many Requests` | 匿名 IP 或用户配额是否耗尽 |
| `manifest unknown` | 镜像路径是否包含上游，例如 `docker.io/library/hello-world` |
| 配置后仍直连上游 | runtime 配置路径是否正确，服务是否已重启 |
| 私有镜像推送失败 | Token 是否包含 `push`，私有上游模式是否允许推送 |

## `no basic auth credentials`

runtime 没有保存对应 host 的登录信息，或登录 host 与镜像引用 host 不一致。

路径前缀模式：

```bash
docker login sparkcr.cn
docker pull sparkcr.cn/docker.io/library/hello-world:latest
```

别名入口：

```bash
docker login docker.sparkcr.cn
docker pull docker.sparkcr.cn/library/hello-world:latest
```

## `unauthorized: authentication required`

检查：

1. Access Token 是否复制完整。
2. Token 是否已撤销或过期。
3. 用户名是否填写 [SparkCR 账号邮箱](/register)。
4. runtime 是否把凭据写到了正确的配置目录。

匿名拉取也可用，但会按客户端 IP 使用匿名配额。

## `429 Too Many Requests`

收到 429 时：

1. [登录](/login)后重试，避免走匿名 IP 配额。
2. 检查 [控制台](/dashboard) 中的今日用量。
3. 降低 CI 并发拉取。
4. 查看 [缓存与用量](cache-and-usage.md)，确认是否存在大量冷拉取或并发拉取。

响应中的 `X-RateLimit-*` 头可用于判断剩余额度和重置时间。

## Docker Hub 官方镜像怎么写

Docker Hub 官方镜像需要补 `library/`：

```bash
docker pull sparkcr.cn/docker.io/library/hello-world:latest
```

不要写成：

```bash
docker pull sparkcr.cn/docker.io/hello-world:latest
```

更多上游写法见 [镜像路径速查](registry-reference.md)。

## 私有镜像仓库拉取或推送失败

优先检查：

- 是否已经在 [`Private Registries`](/settings/private-registries) 页面创建私有上游。
- 镜像路径是否使用页面生成的 endpoint。
- Access Token 是否包含 `pull:private` 或 `push`。
- 私有上游模式是否允许当前操作。
- 上游账号是否对目标仓库有拉取或推送权限。

## GHCR `/v2/` token endpoint 返回 403

不要用 `/v2/` 根路径 challenge 继续请求上游 token endpoint 作为健康判断。部分 Registry 会在根路径返回示例或默认 scope，直接换 token 可能返回 `403 DENIED`。

真实拉取会访问具体镜像路径，并使用 manifest 或 blob 请求返回的仓库级 scope 换取 token。

## CI 中登录成功但构建仍失败

优先检查：

- `docker login` 和 `docker build` 是否在同一个 job 中执行。
- `SPARKCR_REGISTRY` 是否包含正确路径前缀。
- Dockerfile 中的基础镜像是否已经改写为 SparkCR 路径。
- 并发 job 是否触发配额限制。

## 首次拉取为什么仍然慢

首次请求通常需要回源。Manifest 可能较快命中，Blob 需要在满足条件后才会写入持久化缓存。预热也主要预热 Manifest，不会主动下载全部 layer。更多细节见 [缓存与用量](cache-and-usage.md)。
