自动更新Harbor仓库的描述信息

Harbor 镜像仓库可以添加描述信息,像 Docker Hub 那样,浏览镜像仓库,就能大致了解镜像的用途及使用方法。但是手动维护描述信息会很麻烦,更好的方案是直接将代码仓库的 README.md 文件自动更新到描述信息。本文记录了一种在 Drone CI 中通过定制 kaniko 插件来自动更新 Harbor 仓库描述信息的方案。

方案

使用 Go 语言,新建 desc.go,代码如下:

package main
import (
	"encoding/json"
	"net/http"
	"io/ioutil"
	"fmt"
	"flag"
	"bytes"
	"strings"
	"os"
)
// Generated by curl-to-Go: https://mholt.github.io/curl-to-go

type Payload struct {
	Description string `json:"description"`
}

func main () {
	api := flag.String("api", "http://harbor-api-proxy.intra.xx.com/api/repositories", "harbor api for repo description")
	desc := flag.String("desc", "README.md", "description filename")
	repo := flag.String("repo", "", "repo name")
	flag.Parse()

	if *repo == "" {
		fmt.Println("must provide repo name")
		os.Exit(1)
	}

	repository := strings.Replace(*repo, "/", "%2F", -1)

	// read description from desc file
	b, err := ioutil.ReadFile(*desc)
	if err != nil {
		fmt.Print(err)
	}
	str := string(b)

	data := Payload{Description: str}
	payloadBytes, err := json.Marshal(data)
	if err != nil {
		fmt.Print(err)
	}
	body := bytes.NewReader(payloadBytes)

	url := *api + "/" + repository
	req, err := http.NewRequest("PUT", url, body)
	if err != nil {
		fmt.Print(err)
	}
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		fmt.Print(err)
	}

	fmt.Println(resp.Status)
	defer resp.Body.Close()
}

编译

CGO_ENABLED go build -o bin/desc desc.go

bin/desc 添加到镜像中:

ADD bin/desc /kaniko/desc

desc 工具的用法:

# ./bin/desc -h
Usage of ./bin/desc:
  -api string
    	harbor api for repo description (default "http://harbor-api-proxy.intra.xx.com/api/repositories")
  -desc string
    	description filename (default "README.md")
  -repo string
    	repo name

plugin.sh 中使用 desc

# update repo description. use harbor api. Should run after image push. Otherwise in first build harbor api will return 404 Not Found
/kaniko/desc -api "${PLUGIN_DESC_API:-http://harbor-api-proxy.intra.xx.com/api/repositories}" -desc "${PLUGIN_DESC_FILE:-README.md}" -repo "${PLUGIN_REPO:-}"

更进一步,还可以考虑在此步骤中将代码仓库的自动信息附加到 README.md 的结尾,方便从镜像仓库快速跳转到代码仓库查看 Dockerfile 等需求。

# update repo description. use harbor api. Should run after image push. Otherwise in first build harbor api will return 404 Not Found
echo -e "\n\n# Additional Info\n\n| Item | Value |\n|-|-|\n|Source Code|${DRONE_GIT_HTTP_URL}|\n|Commit SHA|${DRONE_COMMIT_SHA}|\n|Commit Author|${DRONE_COMMIT_AUTHOR_NAME}|\n|Commit Branch|${DRONE_COMMIT_BRANCH}|\n|Build Link|${DRONE_BUILD_LINK}|\n\n" >> ${PLUGIN_DESC_FILE:-README.md}
echo "Update repository description: "
/kaniko/desc -api "${PLUGIN_DESC_API:-http://harbor-api-proxy.intra.xx.com/api/repositories}" -desc "${PLUGIN_DESC_FILE:-README.md}" -repo "${PLUGIN_REPO:-}"

用法

通过 kaniko 参数可以设置 DESC_APIDESC_FILE

kind: pipeline
name: default

steps:
- name: publish
  image: ops/drone-kaniko
  settings:
    registry: registry.example.com # if not provided index.docker.io is supposed
    repo: registry.example.com/example-project
    desc_api: https://harbor-proxy.com
    desc_file: README.md
    tags: ${DRONE_COMMIT_SHA}
    cache: true
    skip_tls_verify: false # set to true for testing registries ONLY with self-signed certs
    build_args:
    - COMMIT_SHA=${DRONE_COMMIT_SHA}
    - COMMIT_AUTHOR_EMAIL=${DRONE_COMMIT_AUTHOR_EMAIL}
    username:
      from_secret: docker-username
    password:
      from_secret: docker-password

更好的方式是定制 desc 工具,使用符合自身业务的 DESC_APIDESC_FILE 默认值,这样就可以不用在 yaml 中指定了。

演示

Harbor 中的效果如图所示。

Harbor 描述信息

harbor proxy

上文 desc 中调用的 DESC_API 是没有认证的,实际上是一个代理。在我的场景下,使用 OIDC 登录 Harbor,没有理解 OIDC 方式下调用 API 的方法,所以就弄了个代理,用 admin 账号调用 API,并且限制只能 CI 服务器的 IP 调用。应该还有更好的方案来调用 Harbor API。

Harbor Proxy 通过 Nginx 实现,核心配置如下:

# need resolver
resolver 169.169.0.2;
upstream harbor-core {
	server cr-harbor-core.intra.svc.cluster.local:80;
	keepalive 512;
}

server {
	listen 80;

	set_real_ip_from 0.0.0.0/0; #真实服务器上一级代理的IP地址或者IP段,可以写多行。
	real_ip_header X-Forwarded-For;  #从哪个header头检索出要的IP地址。
	real_ip_recursive on; #递归的去除所配置中的可信IP。
	
	include allow.conf;

	location ~ /api/repositories {
		if ($request_method !~ ^(PUT)$) {return 403;}

		proxy_set_header Authorization $http_authorization;

		proxy_pass http://harbor-core;
	}

	location ~ /api {
		return 403;
	}
}

完整项目请参考 Github

参考资料

1. https://github.com/banzaicloud/drone-kaniko/issues/18
2. https://github.com/ops-itop/harbor-proxy

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注