在 ACK 上使用 Harbor CLI 进行 Agent 评测

更新时间:
复制 MD 格式

AI Agent 评测需要对大量任务做隔离运行和结果收集。Harbor CLI 的 ACK 环境将每个任务调度为集群中的独立 Pod,支持 OSS 数据集挂载、镜像预构建和结果自动回收。

Harbor(本文指 AI Agent 评测开源框架,非容器镜像仓库 Harbor)通过 harbor run 在 ACK 集群中为每个评测任务创建独立的 Trial Pod,数据集预先挂载到 Pod 中,逐任务下发和执行。-n 控制并发 Trial 数;-n 1(并发度=1)时逐个创建 Trial Pod,前一个任务完成后才启动下一个。CI/CD 等集群内触发场景中,可用 Kubernetes Job 包装 harbor run 命令(详见下文使用 K8s Job 编排评测)。

环境准备

安装 Harbor CLI

从 GitHub 克隆仓库并通过 pip 安装:

git clone https://github.com/alibaba/harbor.git
cd harbor
pip install -e .
harbor --version

配置 kubeconfig

Harbor ACK 环境通过 kubeconfig 连接集群。执行以下命令验证连接:

kubectl cluster-info

指定 context 或 kubeconfig 文件时,在 harbor run 命令中传入对应参数:

--ek context=my-ack-context
# 或
--ek kubeconfig=/path/to/kubeconfig

创建评测命名空间

评测相关资源(Trial Pod、Secret、PV/PVC 等)统一放在独立命名空间中:

kubectl create namespace harbor-eval

其他工具(可选)

挂载数据集

Trial Pod 是临时创建的,数据集和结果目录需要通过外部存储挂载到 Pod 中。正式评测推荐使用 OSS CSI 静态卷,开发调试可直接指定本地路径。

方案一:OSS CSI 静态卷(推荐)

通过 ACK 的 OSS CSI 插件将 OSS Bucket 中的目录挂载到 Pod。创建两组 PV/PVC:数据集卷以只读方式挂载,结果卷以读写方式挂载。两个 PV 共用同一个包含 AccessKey 的 Secret 进行认证。

首先创建包含 OSS AccessKey 的 Secret,供 PV 挂载时认证:

kubectl create secret -n harbor-eval generic oss-secret \
  --from-literal=akId=<YOUR-ACCESS-KEY-ID> \
  --from-literal=akSecret=<YOUR-ACCESS-KEY-SECRET>

数据集卷(只读):

apiVersion: v1
kind: PersistentVolume
metadata:
  name: harbor-dataset-pv
spec:
  capacity:
    storage: 100Gi
  accessModes:
    - ReadOnlyMany
  persistentVolumeReclaimPolicy: Retain
  csi:
    driver: ossplugin.csi.alibabacloud.com
    volumeHandle: harbor-dataset-pv
    volumeAttributes:
      bucket: my-harbor-bucket
      url: oss-cn-hangzhou-internal.aliyuncs.com
      otherOpts: "-o ro"
      path: "dataset"
    nodePublishSecretRef:
      name: oss-secret
      namespace: harbor-eval
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: harbor-dataset-pvc
  namespace: harbor-eval
spec:
  accessModes:
    - ReadOnlyMany
  resources:
    requests:
      storage: 100Gi
  volumeName: harbor-dataset-pv
  storageClassName: ""

结果卷(可写):

apiVersion: v1
kind: PersistentVolume
metadata:
  name: harbor-results-pv
spec:
  capacity:
    storage: 100Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  csi:
    driver: ossplugin.csi.alibabacloud.com
    volumeHandle: harbor-results-pv
    volumeAttributes:
      bucket: my-harbor-bucket
      url: oss-cn-hangzhou-internal.aliyuncs.com
      path: "results"
    nodePublishSecretRef:
      name: oss-secret
      namespace: harbor-eval
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: harbor-results-pvc
  namespace: harbor-eval
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 100Gi
  volumeName: harbor-results-pv
  storageClassName: ""
说明

OSS CSI fuse 挂载点写入需要 root 权限。Job Pod 的 securityContext.runAsUser 必须设为 0

方案二:本地目录(开发调试)

将数据集放在本地,通过 -p 参数指定路径。Harbor 通过 Kubernetes exec API 将任务文件上传到 Trial Pod,无需额外配置。

预构建镜像

每个评测 Task 都有独立的 environment/Dockerfiletask.toml。如果 ACR 中没有预构建镜像,harbor run 会在 Trial Pod 内现场构建,耗时且依赖构建环境。建议提前构建镜像并推送到 ACR。

在集群内部署 BuildKit

集群内通常没有 Docker daemon,需部署 BuildKit 作为远程构建后端:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: buildkitd
  namespace: harbor-eval
spec:
  replicas: 1
  selector:
    matchLabels:
      app: buildkitd
  template:
    metadata:
      labels:
        app: buildkitd
    spec:
      containers:
        - name: buildkitd
          image: moby/buildkit:v0.15.0
          args:
            - --addr
            - tcp://0.0.0.0:1234
            - --config
            - /etc/buildkit/buildkitd.toml
          securityContext:
            privileged: true
          resources:
            requests:
              cpu: 500m
              memory: 1Gi
            limits:
              cpu: "2"
              memory: 4Gi
          volumeMounts:
            - name: buildkitd-config
              mountPath: /etc/buildkit/buildkitd.toml
              subPath: buildkitd.toml
            - name: registry-auth
              mountPath: /registry-auth/
      volumes:
        - name: buildkitd-config
          configMap:
            name: buildkitd-config
        - name: registry-auth
          secret:
            secretName: buildkitd-registry-auth
---
apiVersion: v1
kind: Service
metadata:
  name: buildkit-service
  namespace: harbor-eval
spec:
  type: ClusterIP
  selector:
    app: buildkitd
  ports:
    - port: 1234
      targetPort: 1234

配置 buildkitd 认证与镜像加速

BuildKit v0.15.0 不支持通过 CLI 参数配置 registry 认证,需通过配置文件设置。创建 buildkitd.toml ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: buildkitd-config
  namespace: harbor-eval
data:
  buildkitd.toml: |
    [registry."docker.io"]
      mirrors = ["mirror.gcr.io"]

    [registry."<YOUR-ACR-ADDRESS>"]
      config = "/registry-auth/"

其中,Docker Hub 镜像源设为 mirror.gcr.io:阿里云 Registry 镜像加速不支持代理第三方仓库(如 swebench),拉取时会返回 insufficient_scope 错误。

创建 ACR 认证 Secret(Docker config 格式):

kubectl create secret generic buildkitd-registry-auth \
  --namespace=harbor-eval \
  --from-file=config.json=$HOME/.docker/config.json

批量构建并推送镜像

使用 harbor admin upload-images 命令扫描数据集中的所有 Task,逐个构建 Dockerfile 并推送到 ACR:

harbor admin upload-images \
  -t /path/to/dataset \
  -r <YOUR-ACR-ADDRESS> \
  --remote-buildkit tcp://buildkit-service:1234 \
  --update-config \
  --sanitize-image-names \
  --skip-unchanged \
  -n 4

参数

说明

-t

数据集目录路径

-r

ACR 地址

--remote-buildkit

BuildKit 服务地址

--update-config

构建完成后将镜像信息写回 task.toml

--sanitize-image-names

对镜像名称做 ACR 兼容处理

--skip-unchanged

跳过内容未变化的 Task,支持断点续传

-n

并行构建数

命令执行流程:

  1. 读取每个 Task 的 Dockerfile

  2. 通过 buildctl 在远端 BuildKit 服务构建镜像

  3. 推送到 ACR

  4. docker_imagebuilt_content_hashimage_sha256 写回 task.toml

说明

Docker Hub 对匿名拉取的频率限制为 100 次/6 小时(认证用户为 200 次/6 小时)。大批量构建时容易触发限流(报错 failed to resolve source metadata),请确认已按上文配置 mirror.gcr.io 镜像加速。

500 个 Task 在 -n 4 并行下约需 2~3 小时,建议使用 nohup ... & disown 执行,避免终端断开导致任务中断。

构建完成后验证镜像:

crane digest <YOUR-ACR-ADDRESS>/<image-name>:<tag>
task.toml 中的 docker_image 字段

upload-images 成功后,task.toml[environment] 段会自动写入以下字段:

[environment]
docker_image = "registry.cn-hangzhou.aliyuncs.com/<ns>/harbor/<task-name>@sha256:..."
built_content_hash = "abc123..."
image_sha256 = "sha256:..."

harbor run 运行时,ACK 环境优先读取 docker_image 直接拉取镜像(秒级),而非集群内现场构建(分钟级)。

运行评测

配置 ACR 拉取凭证

Trial Pod 从 ACR 拉取预构建镜像时需要认证。创建 docker-registry 类型的 Secret:

kubectl create secret docker-registry acr-pull-secret \
  --namespace=harbor-eval \
  --docker-server=registry.cn-hangzhou.aliyuncs.com \
  --docker-username=<账号> \
  --docker-password=<密码>
说明

在命令行直接传入 --docker-password 会将密码写入 shell 历史,建议在安全环境操作或改用凭证文件。

运行评测任务

以下命令在 ACK 集群中启动评测:Harbor 扫描数据集中的所有 Task,为每个 Task 创建 Trial Pod 并执行评测。-a-m 请替换为实际使用的 Agent 和模型。

harbor run \
  -p ./my-dataset \
  --env ack \
  -n 1 \
  --ek namespace=harbor-eval \
  --ek registry=registry.cn-hangzhou.aliyuncs.com/<ns>/harbor \
  --ek image_pull_secret=acr-pull-secret \
  -a qwen-coder \
  -m qwen3.7-max \
  --no-delete \
  -y

常用参数说明

参数

说明

-p

本地数据集路径

-d

数据集注册表引用,如 org/dataset@latest

--env ack

使用 ACK 环境

-n

并发 Trial 数。-n 1 时 Trial 串行执行

--ek namespace

Trial Pod 所在命名空间

--ek registry

ACR 地址。task.toml 中已写入 docker_image 时可省略

--ek image_pull_secret

拉取镜像所用的 Secret 名称

-a

使用的 Agent

-m

使用的模型

--no-delete

评测完成后保留 Trial Pod,便于排查

-y

跳过确认提示

指定节点调度

通过节点选择器将 Trial Pod 调度到特定机型,并覆盖资源配置:

harbor run \
  -p ./my-dataset \
  --env ack \
  -n 1 \
  --ek namespace=harbor-eval \
  --ek image_pull_secret=acr-pull-secret \
  --ek 'node_selector={"node.kubernetes.io/instance-type":"ecs.gn7i-c8g1.2xlarge"}' \
  --override-cpus 4 \
  --override-memory-mb 8192 \
  --override-gpus 1 \
  -a qwen-coder \
  -m qwen3.7-max \
  -y

过滤任务

通过以下参数筛选要运行的任务:

-i "task-prefix-*"   # 只运行名称匹配的任务
-x "skip-*"          # 排除名称匹配的任务
-l 10                # 最多运行 10 个任务

传递 Agent 环境变量

通过 --ae 参数将 API Key 等环境变量传入 Trial Pod,供 Agent 调用模型时使用:

--ae ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
--ae DASHSCOPE_API_KEY=$DASHSCOPE_API_KEY

使用 YAML 配置文件

参数较多时,将配置写入 YAML 文件集中管理:

# eval-config.yaml
dataset: ./my-dataset          # 或填写注册表引用

agent: qwen-coder
model: qwen3.7-max

environment:
  type: ack
  kwargs:
    namespace: harbor-eval
    registry: registry.cn-hangzhou.aliyuncs.com/<ns>/harbor
    image_pull_secret: acr-pull-secret
    service_account: harbor-eval-sa

n_concurrent_trials: 1

agent_env:
  - name: ANTHROPIC_API_KEY
    value: "${ANTHROPIC_API_KEY}"
harbor run -c eval-config.yaml -y

使用 ACS Sandbox 模式(可选)

在阿里云 Serverless 容器(ACS)上运行评测,或使用 OpenKruise SandboxSet 预热 Pod 加速 Trial 启动时,启用 Sandbox 模式。

SandboxClaim 模式依赖 OpenKruise CRD(agents.kruise.io/v1alpha1),启用前请确认集群已安装 OpenKruise,且 ServiceAccount 已具备相应的 CRD 权限(详见下文配置 RBAC)。

核心参数

参数

说明

--ek use_sandbox_claim=true

启用 SandboxClaim 模式,Harbor 自动创建 SandboxSet 预热池

--ek sandbox_image

指定 SandboxSet 使用的镜像(默认取 task.tomldocker_image

--ek sandboxset_replicas

预热池大小,建议与 -n 并发数保持一致

--ek claim_timeout

等待 SandboxClaim 就绪的超时秒数

--ek sandbox_annotations

为 Sandbox Pod 添加注解(JSON 格式)

--ek sandbox_labels

为 Sandbox Pod 添加标签(JSON 格式)

--ek sandbox_env_vars

向 Sandbox Pod 注入环境变量(JSON 格式)

在 ACS 上运行示例

harbor run \
  -p ./dataset \
  --env ack \
  -n 4 \
  --ek namespace=harbor-eval \
  --ek image_pull_secret=acr-pull-secret \
  --ek use_sandbox_claim=true \
  --ek sandboxset_replicas=4 \
  --ek 'sandbox_annotations={"k8s.aliyun.com/product-on-demand":"acs"}' \
  -a qwen-coder \
  -m qwen3.7-max \
  -y

如果不使用 Sandbox 模式,也可通过以下参数将标准 Trial Pod 调度到 virtual-kubelet 节点:

--ek 'node_selector={"type":"virtual-kubelet"}' \
--ek 'tolerations=[{"key":"virtual-kubelet.io/provider","operator":"Exists"}]'

使用 K8s Job 编排评测

CI/CD 流水线中,将 harbor run 命令包装到 Kubernetes Job 中,由集群内部触发评测:

apiVersion: batch/v1
kind: Job
metadata:
  name: harbor-eval-job
  namespace: harbor-eval
spec:
  parallelism: 1
  completions: 1
  backoffLimit: 0
  template:
    spec:
      serviceAccountName: harbor-eval-sa
      restartPolicy: Never
      securityContext:
        runAsUser: 0
      containers:
        - name: harbor-eval
          image: <harbor-cli-image>
          command:
            - harbor
            - run
            - -p
            - /mnt/oss/dataset
            - --env
            - ack
            - -n
            - "1"
            - --ek
            - namespace=harbor-eval
            - --ek
            - image_pull_secret=acr-pull-secret
            - -a
            - qwen-coder
            - -m
            - qwen3.7-max
            - -o
            - /mnt/oss/results/harbor-eval
            - -y
          env:
            - name: ANTHROPIC_API_KEY
              valueFrom:
                secretKeyRef:
                  name: api-keys
                  key: anthropic-api-key
          volumeMounts:
            - name: dataset
              mountPath: /mnt/oss/dataset
              readOnly: true
            - name: results
              mountPath: /mnt/oss/results
      volumes:
        - name: dataset
          persistentVolumeClaim:
            claimName: harbor-dataset-pvc
            readOnly: true
        - name: results
          persistentVolumeClaim:
            claimName: harbor-results-pvc

配置 RBAC

Job Pod 需要通过 ServiceAccount 获得创建 Trial Pod 等操作的权限:

# harbor-eval-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: harbor-eval-sa
  namespace: harbor-eval
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: harbor-eval-role
  namespace: harbor-eval
rules:
  - apiGroups: [""]
    resources: ["pods", "pods/exec", "pods/log"]
    verbs: ["get", "list", "create", "delete", "watch"]
  - apiGroups: [""]
    resources: ["configmaps", "secrets"]
    verbs: ["get", "list"]
  - apiGroups: ["batch"]
    resources: ["jobs"]
    verbs: ["get", "list", "create", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: harbor-eval-rolebinding
  namespace: harbor-eval
subjects:
  - kind: ServiceAccount
    name: harbor-eval-sa
    namespace: harbor-eval
roleRef:
  kind: Role
  name: harbor-eval-role
  apiGroup: rbac.authorization.k8s.io
kubectl apply -f harbor-eval-rbac.yaml

使用 Sandbox 模式时,需为上述 Role 额外添加 sandboxsetssandboxclaimssandboxesget/list/create/delete/watch 权限。

查看评测结果

查看 Trial Pod 状态

# 查看所有 Trial Pod
kubectl get pods -n harbor-eval -l app=sandbox

# 查看特定 Pod 的日志
kubectl logs -n harbor-eval <pod-name> --tail=100

查看 Job 状态

使用 K8s Job 编排评测时,查看 Job 的执行状态和日志:

kubectl get jobs -n harbor-eval
kubectl describe job harbor-eval-job -n harbor-eval
kubectl logs -l job-name=harbor-eval-job -n harbor-eval --tail=200

查看评测结果文件

每个 Trial 的结果目录结构:

harbor-eval/
└── <task-name>/
    ├── agent/          # Agent 执行日志
    ├── verifier/       # Verifier 验证结果
    ├── artifacts/      # 任务产出物
    └── results.json    # 汇总结果

K8s Job 编排时,用 -o /mnt/oss/results 指定输出路径,结果经 OSS CSI fuse 直接写回 OSS,无需额外上传。评测完成后用 ossutil 查看:

ossutil ls oss://my-harbor-bucket/results/harbor-eval/

常见问题

Pod 一直处于 Pending 状态

查看 Pod 事件:

kubectl describe pod <pod-name> -n harbor-eval

常见原因:

  • 节点资源不足:调整 --override-cpus--override-memory-mb

  • 镜像拉取失败:检查 image_pull_secret 和 ACR 地址配置

  • 节点选择器不匹配:确认 node_selector 中的标签在集群节点上存在

镜像拉取失败

# 确认 ACR 中存在目标镜像
docker manifest inspect <acr-address>/<image>:<tag>

# 确认 Secret 与 Pod 在同一命名空间
kubectl get secret acr-pull-secret -n harbor-eval

Harbor CLI 无法连接集群

# 验证 kubeconfig
kubectl cluster-info

# 在 Pod 内确认 RBAC 权限
kubectl auth can-i create pods -n harbor-eval --as=system:serviceaccount:harbor-eval:harbor-eval-sa

集群内运行时,kubeconfig 指向的 VPC 内网 IP 可能无法从 Pod CIDR 访问。将 API Server 地址改为集群内 Service 端点:https://kubernetes.default.svc:443

评测任务超时

任务超时由 task.toml 中的以下字段控制:

[agent]
timeout_sec = 300

[verifier]
timeout_sec = 60

如需全局调整,使用顶层 CLI 参数(注意不是 --ek 参数):

--agent-timeout-multiplier 2.0

docker_image 字段未生效

确认 Harbor CLI 版本不低于 0.6.5,旧版本不读取 docker_image 字段:

harbor --version

相关文档