---
url: /zh/artifact/docker.md
description: |
  介绍如何登录和使用 CNB Docker 镜像制品库， 包括制品路径规则、推送和拉取容器镜像的方法。
---
## 登录 CNB Docker 制品库

登录命令如下。获取 `CNB_TOKEN` 的方式参考 [创建访问令牌](./intro.md#创建访问令牌)。

```bash
docker login docker.cnbprod.alpha.qq.com -u cnb -p ${CNB_TOKEN}
```

## Docker 制品路径规则

发布制品到仓库时，支持两种命名规则：

1. **同名制品**：制品路径与仓库路径一致，如：`docker.cnbprod.alpha.qq.com/${CNB_REPO_SLUG_LOWERCASE}`
2. **非同名制品**：以仓库路径作为命名空间，制品路径 = 仓库路径/制品名称，
   如：`docker.cnbprod.alpha.qq.com/${CNB_REPO_SLUG_LOWERCASE}/<IMAGE_NAME>`

## 推送制品

### 本地命令行推送

同名制品

```bash
docker build -t docker.cnbprod.alpha.qq.com/${CNB_REPO_SLUG_LOWERCASE}:latest .
docker push docker.cnbprod.alpha.qq.com/${CNB_REPO_SLUG_LOWERCASE}:latest
```

非同名制品

```bash
docker build -t docker.cnbprod.alpha.qq.com/${CNB_REPO_SLUG_LOWERCASE}/<IMAGE_NAME>:latest .
docker push docker.cnbprod.alpha.qq.com/${CNB_REPO_SLUG_LOWERCASE}/<IMAGE_NAME>:latest
```

### 云原生构建中推送

```yaml title=".cnb.yml"
main:
  push:
    - services:
        - docker
      stages:
        - name: docker build
          script: docker build -t ${CNB_DOCKER_REGISTRY}/${CNB_REPO_SLUG_LOWERCASE}:latest .
        - name: docker push
          script: docker push ${CNB_DOCKER_REGISTRY}/${CNB_REPO_SLUG_LOWERCASE}:latest
```

### 云原生开发中推送

同名制品

```bash
docker build -t ${CNB_DOCKER_REGISTRY}/${CNB_REPO_SLUG_LOWERCASE}:latest .
docker push ${CNB_DOCKER_REGISTRY}/${CNB_REPO_SLUG_LOWERCASE}:latest
```

非同名制品

```bash
docker build -t ${CNB_DOCKER_REGISTRY}/${CNB_REPO_SLUG_LOWERCASE}/<IMAGE_NAME>:latest .
docker push ${CNB_DOCKER_REGISTRY}/${CNB_REPO_SLUG_LOWERCASE}/<IMAGE_NAME>:latest
```

## 使用制品

### 在命令行使用

```bash
docker pull docker.cnbprod.alpha.qq.com/<ARTIFACT_PATH>:latest

# ...
```

### 定制构建/开发环境

在 `.cnb.yml` 中引用 CNB 制品库中的 Docker 镜像作为构建环境：

```yaml{4} title=".cnb.yml"
main:
  push:
    - docker:
        image: ${CNB_DOCKER_REGISTRY}/${CNB_REPO_SLUG_LOWERCASE}:latest
      stages:
        - name: hello world
          script: echo "Hello World"
```

或作为云原生开发环境：

```yaml{4} title=".cnb.yml"
$:
  vscode:
    - docker:
        image: ${CNB_DOCKER_REGISTRY}/${CNB_REPO_SLUG_LOWERCASE}:latest
      services:
        - vscode
        - docker
```

## 推送 buildx 构建缓存

使用 `docker buildx build --cache-to type=registry` 将构建缓存推送到制品库时，
如果缓存导出失败并报 **404 Not Found**，通常是由旧版 buildx/buildkit 的缓存导出格式导致：

```text
#39 writing cache manifest sha256:... done
#39 ERROR: error writing manifest blob: failed commit on ref "sha256:...":
unexpected status from PUT request to https://docker.cnbprod.alpha.qq.com/v2/<REPO>/manifests/<CACHE_TAG>: 404 Not Found
```

此时镜像本体推送成功，仅缓存导出失败，典型于 Docker 27.5.x 等旧版本自带的 buildx。

### 解决办法

在 `--cache-to` 中追加 `image-manifest=true,oci-mediatypes=true`：

```bash
docker buildx build \
  --cache-from type=registry,ref=${CNB_DOCKER_REGISTRY}/${CNB_REPO_SLUG_LOWERCASE}:<CACHE_TAG> \
  --cache-to type=registry,ref=${CNB_DOCKER_REGISTRY}/${CNB_REPO_SLUG_LOWERCASE}:<CACHE_TAG>,mode=max,image-manifest=true,oci-mediatypes=true \
  -t ${CNB_DOCKER_REGISTRY}/${CNB_REPO_SLUG_LOWERCASE}:latest \
  --push .
```

或将 Docker/buildx 升级到 BuildKit v0.21+ 的版本（`image-manifest` 默认开启）。

详情可参见上述参数的 [官方说明](https://github.com/moby/buildkit#registry-push-image-and-cache-separately)。

### 原因

旧版 buildx（BuildKit v0.21 之前）导出多架构缓存（如 `mode=max` 配合多 `--platform`）时，
默认将缓存清单生成为 OCI index（manifest list），且 index 引用的子缓存 manifest 仅作为普通 blob 上传、
未通过 manifests API 推送。制品库登记 index 时要求其引用的子 manifest 均已登记，
找不到子项记录即返回 404（镜像推送不受影响，其子 manifest 总是先推送再推 index）。
`image-manifest=true` 可将缓存改为导出**单个 OCI image manifest**，是制品库支持的标准格式；
该参数以 `oci-mediatypes=true` 为前提（其自 BuildKit v0.8 起默认即为 `true`，显式写出仅为确保生效）。
BuildKit **v0.21 起 `image-manifest` 默认为 `true`**，新版本不再出现该问题。

## 限制

* Docker 制品库仅接受容器镜像（单/多架构）和 buildx 注册表缓存的推送。
  Helm Chart、Docker Model 等其它类型的制品推送到 Docker 地址会被拒绝，
  请确认推送目标地址与制品类型匹配（详见 [制品类型准入限制](./intro.md#制品类型准入限制)）。
* 单层最大 64 GB
* 镜像最大 64 层
* 制品元数据最大 64 KB
* 不支持 Docker Registry V1 API，请使用 Docker 20.10+ 客户端。

  如遇到以下错误，请升级 Docker 版本：

  ```text
  Error: image <IMAGE_NAME> not found
  ```

  ```text
  Failed to pull image: rpc error: code = Unknown desc = missing signature key
  ```

  如果确实需要使用较老版本的 Docker（17.12 以下），需手动禁用 V1 协议：

  * 启动参数方式禁用 V1：`dockerd --disable-legacy-registry`（Linux 平台，默认 `false`）
  * 配置文件方式禁用 V1：在 `daemon.json` 中设置 `"disable-legacy-registry": true`（所有平台，默认未设置）

  > 注意：Windows/macOS 平台会自动强制使用 V2 协议，无需额外配置。
  > 该选项在 Docker 17.12+ 中已移除，因为 V1 支持已被彻底删除。

## 更多信息

更多 Docker 用法，参阅 [Docker 官方文档](https://docs.docker.com/)。
