Appearance
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调试过程中先后遇到过两类现象:
plugins/docker镜像拉取卡住:
txt
latest: Pulling from plugins/docker- 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 权限三个问题混在一起。
验证过程
这次排查做了几个对照:
- 切到
plugins/docker:构建卡在拉取插件镜像,不适合当前环境。 - 切回 Kaniko:能直接进入 Harbor 鉴权和镜像构建流程。
- 新建
harbor_devbot_username2/harbor_devbot_password2:确认新 secret 可用。 - 使用
$${...}和$${#...}:确认变量由容器 shell 展开,用户名长度和密码长度正常。 - 改回正确镜像路径:
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'排查要点
遇到类似问题时,按这个顺序查:
- 先确认是否卡在拉取 CI 插件镜像,例如
plugins/docker。 - 再确认
from_secret的 secret 名字是否存在,并且对应仓库可用。 - 在
commands里使用$${VAR},不要直接用${VAR}。 - 如果要打印变量长度,也要写成
$${#VAR}。 - Harbor 路径要确认清楚,本次最终路径是
frontend-dev/lometa/vitepress-doc-packer。 - Debug 完后删除用户名和长度打印,避免日志里暴露账号信息。
参考资料
说明 step 级
environment、from_secret的写法,并在 Common Problems 中明确提到参数展开会在 YAML 解析前预处理;如果不希望系统提前求值,需要使用$$转义。Drone 官方文档:Environment substitution
说明 Drone 支持
${parameter}、${#parameter}等类似 shell 的替换语法,并强调这些表达式会在 YAML 解析前求值;需要交给容器 shell 执行时,应写成$${...}。说明 repository secrets 的用途、创建位置,以及通过
environment.<NAME>.from_secret注入 step 环境变量的方式。