我最早接触的持续集成工具是大名鼎鼎的 Jenkins,接手同事留下的一个单节点 Jenkins。由于没有太强烈的使用需求,体会不到 Jenkins 的强大,印象停留在 “麻烦” 两个字:需要给研发同事手动添加账号,然后用一个有很多很多方框的表单来设置权限。而 Drone CI 在账号权限方面就给人眼前一亮的感觉,直接集成代码仓库,和 Github Actions,Travis CI 等使用流程类似。另外,Drone CI 原生基于容器,插件直接做成镜像,这样写出来的 yaml 配置文件可以做到简短清晰。本文记录 Drone CI 使用过程中遇到的问题及解决方案,基于 1.6.1 版本,可能不适用于最新版本。
如有兴趣,可以看看我个人的 Drone CI 的运行效果:https://ci.annhe.net/annProg/chart。
安装
代码仓库为 Gitea,使用 Kubernetes 安装,参考配置如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
--- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: drone-server-rbd-rbd1 spec: accessModes: - ReadWriteOnce storageClassName: rbd resources: requests: storage: 200Gi --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: drone-rbac subjects: - kind: ServiceAccount name: default namespace: default roleRef: kind: ClusterRole name: cluster-admin apiGroup: rbac.authorization.k8s.io --- apiVersion: apps/v1 kind: Deployment metadata: name: drone-server namespace: default labels: app: drone-server spec: replicas: 1 selector: matchLabels: app: drone-server strategy: type: RollingUpdate # 由于挂载了 rbd,需要先销毁pod才能创建新的 rollingUpdate: maxUnavailable: 1 maxSurge: 0 template: metadata: labels: app: drone-server spec: containers: - name: drone-server image: cr.xxx.com/drone/drone:1.6.1 env: - name: UPDATEAT value: 2019-10-27-21:22 - name: DRONE_KUBERNETES_ENABLED value: "true" - name: DRONE_KUBERNETES_NAMESPACE value: default - name: DRONE_GITEA_SERVER value: https://git.xxx.com - name: DRONE_GITEA_CLIENT_ID value: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - name: DRONE_GITEA_CLIENT_SECRET value: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - name: DRONE_SERVER_HOST value: ci.xxx.com - name: DRONE_SERVER_PROTO value: https - name: DRONE_USER_CREATE value: username:root,admin:true - name: DRONE_GIT_ALWAYS_AUTH value: "true" - name: DRONE_RPC_SECRET value: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - name: DRONE_LOGS_DEBUG value: "true" - name: DRONE_LOGS_TRACE value: "true" - name: DRONE_LOGS_PRETTY value: "true" - name: DRONE_GIT_IMAGE value: cr.xxx.com/drone/git:latest # 此镜像修复了 k8s 上 image pull policy 问题 # tag 为 latest 且未指定 pull policy 时,policy 为 always - name: DRONE_KUBERNETES_IMAGE value: cr.xxx.com/drone/controller:1.6.1-1 - name: DRONE_KUBERNETES_IMAGE_PULL value: IfNotExists ports: - name: http containerPort: 80 volumeMounts: - name: data mountPath: "/data" volumes: - name: data persistentVolumeClaim: claimName: drone-server-rbd-rbd1 restartPolicy: Always --- kind: Service apiVersion: v1 metadata: name: drone-server-service namespace: default spec: type: NodePort selector: app: drone-server ports: - protocol: TCP port: 80 name: http targetPort: 80 nodePort: 30000 |
然后使用 Ingress Nginx 做负载均衡,注意需要增大 proxy_read_timeout
的值,默认的 3s
对于 drone 的 api/stream
接口可能太短。

使用kaniko
我对 CI 的主要需求是做镜像,kaniko 这种不需要特权模式就能生成镜像的工具是很好的选择。使用 Drone CI 的 kaniko 插件,可以参考以下几点:
auto_tag
支持,参见 Github- 自动更新镜像仓库描述信息,参见 自动更新Harbor仓库的描述信息
- cache 支持,参见 Github
用 Drone CI 生成镜像的一个例子,可以看到 yaml 配置很简洁。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
kind: pipeline name: chart steps: - name: build image: banzaicloud/drone-kaniko:0.5.1 settings: repo: ann17/chart auto_tag: true username: from_secret: username password: from_secret: password |
问题记录
插件镜像不更新
安装部分 yaml 中有以下代码:
1 2 3 4 |
# 此镜像修复了 k8s 上 image pull policy 问题 # tag 为 latest 且未指定 pull policy 时,policy 为 always - name: DRONE_KUBERNETES_IMAGE value: cr.xxx.com/drone/controller:1.6.1-1 |
这里的修复方案针对 1.6.1
版本,新版本可能不存在此问题了。修复方案见 Github。使用此分支重新编译 drone-controller
。在 Drone 代码的 go.mod
中添加以下代码后重新编译。
1 |
replace github.com/drone/drone-runtime => github.com/ops-itop/drone-runtime k8s-pullpolicy |
另外,如果不重新编译,也可以在 yaml 中手动指定 pull policy 来解决:
1 |
pull: always |
但是对于 tag
为 latest
的镜像,自动设置为 always
才更合理。
secret管理
只能给 repo 添加 secret,secret 更改比较麻烦。考虑提issue,增加用户级别的 secret,比如,用户级别的 docker push password,当 repo 中未定义 docker push password,yaml
中又引用时,使用用户级别的 docker push password。但是搜索到一个 issue,见 drone/issues/1619 ,提出一个 Organization
级别的 secret
概念,被作者给否了,作者提出一个变通的方案:使用命令行批量设置 secret,代码如下。
1 |
drone repo ls | xargs -I{} drone secret add {} KEY VALUE |
特定分支触发
以下示例,在 k8s-sidecar
分支 push
或者创建 tag
时触发 CI。
1 2 3 4 5 6 7 8 9 10 |
when: ref: - refs/heads/k8s-sidecar - refs/tags/* ----或者用trigger trigger: ref: - refs/heads/test - refs/tags/* |
参考资料
1 2 3 4 |
1. https://drone.io/ 2. https://discourse.drone.io/t/drone-1-3-1-on-kubernetes-not-pull-latest-plugin-image/6088 3. https://docker-runner.docs.drone.io/configuration/conditions/ 4. https://discourse.drone.io/t/execute-a-build-step-only-when-a-feature-branch-is-tagged-with-a-specific-pattern/1237/3 |
发表回复