Harbor 镜像管理 API
Harbor 是企业级镜像仓库,运维常做:列出项目与仓库、查询镜像 Tag、清理过期 Tag、检查漏洞扫描结果。Harbor v2 提供 REST API,本文用 httpx 直接调用(也可选 harborapi 等封装库)。
环境准备
uv add httpx
export HARBOR_URL="https://harbor.example.com"
export HARBOR_USER="robot$ops-sync" # Robot 账号或普通用户
export HARBOR_PASS="robot-secret-placeholder" # 占位符
Harbor 建议为自动化创建 Robot Account,权限限定到目标项目。
封装客户端
#!/usr/bin/env python3
"""Harbor API 基础封装:认证、列项目、列仓库。"""
import os
from typing import Any
import httpx
class HarborClient:
def __init__(self, base_url: str, username: str, password: str) -> None:
self.base = base_url.rstrip("/")
# 使用 Basic Auth;内网自签证书可 verify=False(不推荐生产)
self.client = httpx.Client(
base_url=f"{self.base}/api/v2.0",
auth=(username, password),
timeout=30.0,
verify=True,
)
def list_projects(self) -> list[dict[str, Any]]:
resp = self.client.get("/projects", params={"page_size": 100})
resp.raise_for_status()
return resp.json()
def list_repositories(self, project_name: str) -> list[dict[str, Any]]:
resp = self.client.get(f"/projects/{project_name}/repositories", params={"page_size": 100})
resp.raise_for_status()
return resp.json()
def list_artifacts(self, project: str, repo: str) -> list[dict[str, Any]]:
# repo 名可能含斜杠,如 library/nginx,需 URL 编码
from urllib.parse import quote
repo_path = quote(repo, safe="")
url = f"/projects/{project}/repositories/{repo_path}/artifacts"
resp = self.client.get(url, params={"page_size": 50, "with_tag": True})
resp.raise_for_status()
return resp.json()
def close(self) -> None:
self.client.close()
列出镜像 Tag 与推送时间
def print_image_tags(harbor: HarborClient, project: str, repo: str) -> None:
artifacts = harbor.list_artifacts(project, repo)
for art in artifacts:
tags = [t["name"] for t in art.get("tags") or []]
push_time = art.get("push_time", "unknown")
size_mb = (art.get("size") or 0) / 1024 / 1024
print(f"tags={tags} push={push_time} size={size_mb:.1f}MB")
def main() -> None:
harbor = HarborClient(
os.environ["HARBOR_URL"],
os.environ["HARBOR_USER"],
os.environ["HARBOR_PASS"],
)
try:
for proj in harbor.list_projects():
print(f"项目: {proj['name']}")
print_image_tags(harbor, "library", "nginx")
finally:
harbor.close()
if __name__ == "__main__":
main()
清理旧 Tag(示例)
保留最近 N 个 Tag,删除其余(先 dry-run 打印,确认后再删):
def delete_artifact(harbor: HarborClient, project: str, repo: str, digest: str) -> None:
from urllib.parse import quote
repo_path = quote(repo, safe="")
url = f"/projects/{project}/repositories/{repo_path}/artifacts/{digest}"
resp = harbor.client.delete(url)
resp.raise_for_status()
def cleanup_old_tags(harbor: HarborClient, project: str, repo: str, keep: int = 5, dry_run: bool = True) -> None:
artifacts = harbor.list_artifacts(project, repo)
# 按 push_time 降序,保留最新 keep 个
sorted_arts = sorted(artifacts, key=lambda a: a.get("push_time") or "", reverse=True)
for art in sorted_arts[keep:]:
digest = art["digest"]
tags = [t["name"] for t in art.get("tags") or []]
print(f"{'[DRY-RUN] ' if dry_run else ''}删除 digest={digest[:12]}... tags={tags}")
if not dry_run:
delete_artifact(harbor, project, repo, digest)
提示
- 生产清理策略应结合镜像复制、K8s 正在使用的 digest,避免误删
- 可配合 GitLab CI 在构建成功后触发清理脚本
- 漏洞扫描结果可通过
/projects/{p}/repositories/{r}/artifacts/{d}/scan获取
小结
Harbor API v2 路径以 /api/v2.0 为前缀。运维脚本重点:认证、分页、仓库名编码、删除前 dry-run。下一章介绍 Nexus 制品库管理。