Skip to content

CICD

只做业务要用到的最简单的CICD。
基于LLM话疗和规模调研,最终选择的是 release分支->Drone自动打包->推送k3s。
选型比较:

  • github runner也是个不错的选择,但是这样镜像就得走一遍网络,而且会随着github的政策变化。
  • gitea runner也不错,出来的时间比较短,而且自定义程度不如drone。
  • jekins是行业标准但是java比较亲和,配置复杂度高了不止一点。
    Drone有大公司背书,活的时间也比较久,star多资料多,资源占用少,纯docker runner好限制和调整,带UI界面也是写yaml配置简单,适合我们小团队及格的使用。
    内部工具没那么严格,崩了大不了晚点上线。目前能考虑到的地方就是如果打包出错了,pod版本不一致,怎么做保证原子性。

原因:Submariner 默认仅支持导出 ClusterIP 类型的服务(或者 headless service)

Drone 推送 Harbor 镜像问题总结

背景

本仓库通过 Drone CI 使用 Kaniko 构建镜像,并推送到 Harbor:

txt
harbor.lometa.cn/frontend-dev/lometa/vitepress-doc-packer:latest

调试过程中先后遇到过两类现象:

  1. plugins/docker 镜像拉取卡住:
txt
latest: Pulling from plugins/docker
  1. Kaniko 推送 Harbor 时鉴权失败:
txt
UNAUTHORIZED: unauthorized to access repository: ..., action: push

现象

一开始日志里看起来像 Harbor 账号没有权限:

txt
error checking push permissions  
UNAUTHORIZED: unauthorized to access repository

但加 debug 后发现,旧写法下 Drone 命令里的变量会被预处理,导致日志误导。例如:

yaml
- 'printf ''Harbor username length: %s\n'' "${#HARBOR_USERNAME}"'

这类 ${...} / ${#...} 表达式会先经过 Drone 的参数预处理,不一定是容器 shell 在运行时展开。结果可能显示为空或长度为 0,让人误以为 secret 没有注入。

原因

Drone 会在 YAML 进入实际 shell 执行前做参数预处理。官方文档说明:如果不希望 Drone 提前求值,需要用 $$ 转义,让表达式原样交给 shell。

因此,在 commands 里要写:

yaml
- 'test -n "$${HARBOR_USERNAME}"'  
- 'printf ''length: %s\n'' "$${#HARBOR_USERNAME}"'

而不是:

yaml
- 'test -n "$HARBOR_USERNAME"'  
- 'printf ''length: %s\n'' "${#HARBOR_USERNAME}"'

另外,Harbor 机器人账号用户名里可能带 $,例如:

txt
robot$dev-ci-bot

如果命令里没有正确转义,排查时很容易把 Drone 预处理、shell 展开、Harbor 权限三个问题混在一起。

验证过程

这次排查做了几个对照:

  1. 切到 plugins/docker:构建卡在拉取插件镜像,不适合当前环境。
  2. 切回 Kaniko:能直接进入 Harbor 鉴权和镜像构建流程。
  3. 新建 harbor_devbot_username2 / harbor_devbot_password2:确认新 secret 可用。
  4. 使用 $${...}$${#...}:确认变量由容器 shell 展开,用户名长度和密码长度正常。
  5. 改回正确镜像路径:frontend-dev/lometa/vitepress-doc-packer 后,构建成功并推送镜像。

最终写法

当前 .drone.yml 的关键写法:

yaml
environment:  
  HOME: /kaniko  
  HARBOR_USERNAME:  
    from_secret: harbor_devbot_username2  
  HARBOR_PASSWORD:  
    from_secret: harbor_devbot_password2  
commands:  
  - mkdir -p /kaniko/.docker  
  - 'test -n "$${HARBOR_USERNAME}" || { echo "HARBOR_USERNAME is empty"; exit 1; }'  
  - 'test -n "$${HARBOR_PASSWORD}" || { echo "HARBOR_PASSWORD is empty"; exit 1; }'  
  - 'echo "{\"auths\":{\"harbor.lometa.cn\":{\"username\":\"$${HARBOR_USERNAME}\",\"password\":\"$${HARBOR_PASSWORD}\"}}}" > /kaniko/.docker/config.json'  
  - '/kaniko/executor --dockerfile=Dockerfile --context=dir://. --destination=harbor.lometa.cn/frontend-dev/lometa/vitepress-doc-packer:v$${DRONE_BUILD_NUMBER} --destination=harbor.lometa.cn/frontend-dev/lometa/vitepress-doc-packer:latest'

排查要点

遇到类似问题时,按这个顺序查:

  1. 先确认是否卡在拉取 CI 插件镜像,例如 plugins/docker
  2. 再确认 from_secret 的 secret 名字是否存在,并且对应仓库可用。
  3. commands 里使用 $${VAR},不要直接用 ${VAR}
  4. 如果要打印变量长度,也要写成 $${#VAR}
  5. Harbor 路径要确认清楚,本次最终路径是 frontend-dev/lometa/vitepress-doc-packer
  6. Debug 完后删除用户名和长度打印,避免日志里暴露账号信息。

参考资料

  • Drone 官方文档:Environment syntax

    说明 step 级 environmentfrom_secret 的写法,并在 Common Problems 中明确提到参数展开会在 YAML 解析前预处理;如果不希望系统提前求值,需要使用 $$ 转义。

  • Drone 官方文档:Environment substitution

    说明 Drone 支持 ${parameter}${#parameter} 等类似 shell 的替换语法,并强调这些表达式会在 YAML 解析前求值;需要交给容器 shell 执行时,应写成 $${...}

  • Drone 官方文档:Repository secrets

    说明 repository secrets 的用途、创建位置,以及通过 environment.<NAME>.from_secret 注入 step 环境变量的方式。

最近更新: