Habaform——用类似 IaC(Infrastructure as code) + GitOps 的方式管理 Harbor 的 Project 和 User

作为 Harbor 的用户,我们知道:

If you create user accounts in the Harbor database, Harbor is locked in database mode. You cannot change to a different authentication mode after you have created local users.

Harbor 的用户验证有三种方式,分别叫做:

  • Database Authentication
  • LDAP/Active Directory Authentication
  • OIDC Provider Authentication

由于我个人需要在纯内网环境下使用 Harbor ,加上没有 LDAP 的加持,自然只有一个 「Database Authentication」可以选,由于每用户都是独立的帐号,每个帐号都有自己所属的 Project,也有一些共用的 Project 多个人共用,管理起来的成本非常大,不过好在现在已经从之前的「无文档,无记录」,升级成了用一个 Google Sheet 来记录所有的 Project,类似这样:

这样看上去直观了不少,至少有了一个统一的地方可以看到每个 Project 的所有人/用途和 GC Policy。

但是这是一个 xls,不是一个 exe,它只能用来记录,需要人工同时维护表格和 Harbor(手动点点点),容易出现表格和实际的数据不一致的情况,鉴于此,我们可以继续深入改进一下,用类似 IaC 的方式来管理 Harbor 的 Project 和 Users。

于是我造了一个方形的轮子,叫 Habaform.

Habaform

Habaform 名称来源:Haba(Harbor)-form(Terraform).

GitHub 地址:https://github.com/n0vad3v/habaform

Usage

当使用 pip3 install habaform 安装了之后,我们来看看 Habaform 怎么玩。

Init Habaform

对于一个船新的 Habaform 管理的 Harbor,我们可以通过 habaform parse 来获得一份 habaform_file,用法如下(首先需要 export HARBOR 的登录信息),比如:

export HARBOR_USERNAME="admin"
export HARBOR_PASSWORD="Harbor12345"
export HARBOR_URL="http://hub.nova.moe"

然后就可以开始解析目前的 Harbor 结构了,先创建一个目录用来存放这些信息:

habaform parse

此时,当前目录下会出现一个目录和一个文件,类似这样:

.
├── DO_NOT_TOUCH
│   └── habaform.hf
└── habaform.hf

1 directory, 2 files

此时两个 habaform.hf 文件内容完全一致,文件内容类似如下:

habaformVersion: 1
projects:
- civic:
    members:
    - admin(projectAdmin)
- honda:
    members:
    - admin(projectAdmin)
    - pingcap(developer)
- library:
    members:
    - admin(projectAdmin)
- novakwok:
    members:
    - admin(projectAdmin)

保持这个样子,可以直接丢到一个 GitHub 仓库上。

GitOps

有了一个中心化的 GitHub 仓库之后,我们可以开始配置 GitHub Action 来完成 GitOps,比如我们希望在代码合并的时候自动 habaform plan 来判断这一次合并会造成的更改,虽然是内网环境,但是由于已经有大量的 Self-hosted Runner 的部署在,我们依然可以使用 GitHub Actions 来完成这一系列内网操作(你也想要 Self-hosted Runner?来看看「在 Kubernetes 上运行 GitHub Actions Self-hosted Runner」这篇文章吧~),关键代码如下:

name: Plan Habaform
on: [pull_request]

jobs:
  Plan:
    runs-on: [self-hosted,X64]
    steps:
      - uses: actions/[email protected]
      - uses: actions/[email protected]
        with:
          python-version: '3.x'

      - name: Setup Habaform
        run: |
          pip3 install habaform

      - name: Plan
        id: plan
        env:
          HARBOR_USERNAME: ${{secrets.HARBOR_USERNAME}}
          HARBOR_PASSWORD: ${{secrets.HARBOR_PASSWORD}}
          HARBOR_URL: ${{secrets.HARBOR_URL}}
        run: |
          echo 'HABAPLAN<<EOF' >> $GITHUB_ENV
          habaform plan >> $GITHUB_ENV
          echo 'EOF' >> $GITHUB_ENV

      - name: Preview Plan info
        uses: actions/[email protected]
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            github.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `${{ env.HABAPLAN }}`
            })

对于没有问题的 PR,合并后需要自动 Apply 到实际的 Harbor 上,我们再准备一个 Action 来做这个事情,关键代码如下:

name: Apply Habaform

on:
  push:
    branches: [ master ]
    paths:
      - 'habaform.hf'

jobs:
  Apply:
    runs-on: [self-hosted,X64]
    steps:
      - uses: actions/[email protected]
      - uses: actions/[email protected]
        with:
          python-version: '3.x'

      - name: Setup Habaform
        run: |
          pip3 install habaform

      - name: Apply
        id: apply
        env:
          HARBOR_USERNAME: ${{secrets.HARBOR_USERNAME}}
          HARBOR_PASSWORD: ${{secrets.HARBOR_PASSWORD}}
          HARBOR_URL: ${{secrets.HARBOR_URL}}
        run: |
          habaform apply

      - name: Sync config
        run: |
          git config --global user.name "github-actions[bot]"
          git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
          git add .
          git commit -m "Sync hf file"
          git push

Workflow

有了上述准备后,我们来看看一个典型的 Workflow,由于手上没有测试环境,我们直接用生产环境的库来测试好了~

  1. 首先,我们遇到了需要针对 Project 的修改,比如要删除 pingcap 这个 Project,这个时候,我们只需要提交一个 PR,内容是在 habaform.hf 中直接删除 pingcap 的部分,像这样:

提交 PR 之后 GitHub Actions 就会自动将这次变更的效果给 Preview 出来并 Comment 到 PR 的 Issue 上,类似这样:

如果感觉没问题(Preview 符合预期),那么就可以直接合并 PR,在合并之后,由于 habaform.hf 文件有修改,会触发 Apply Habaform 这个 GitHub Action 任务,任务会自动把修改的内容 Apply 到实际的 Harbor 上,并同步两个 habaform.hf 文件。

虽然很简陋,不过,这样就完成了~

当然,Habaform 不简单局限于增/删 Project,它还可以直接管理 Project 的成员信息,只要直接修改 habaform.hf 即可,对于成员的 Role 来说,只需要在括号内申明就可以了,可用的 Role 信息如下:

  • projectAdmin
  • maintainer
  • developer
  • guest
  • limitedGuest

以上,在有了 Habaform 之后,我们可以让 Habaform 来管理我们的 Harbor 的 Project/User 关系了。

Miscs

Habaform Feature

  • IaC 管理 Harbor 的 Project-User,后期会考虑加入更多功能
  • 对于 Delete Project 操作而言,会递归删除 Project 下所有 repo 之后删除 Project

Potential Bugs

  • 由于没有类似 Terraform 的 S3 Backend,基于 DO_NOT_TOUCH/habaform.hf 作为 Trusted Source 可能会在多个 PR 同时进行的时候遇到问题
  • 可能还会有些我不知道的 Bug,最坏情况是 Habaform 文件和 Harbor 实际结构不一致(比如 Habaform 上删除了 Project 但是 Harbor 上并没有成功删除之类的),此外,使用时请在 apply 前仔细阅读 plan 的内容

Reference

  1. Configuring Authentication
  2. Workflow commands for GitHub Actions

comments powered by Disqus