Drone持续集成从入门到Github项目实践

前言

在最近某次更新博客时,突然觉得每次写完文章再登陆服务器将代码pull到服务器本地部署的过程好傻(尽管总共也花不了1分钟时间),但作为一个表面的IT工作者怎么能忍受每次都进行这种重复工作呢,就想着有没有一种方法能够像之前Netlify那样push完就自动更新部署的方式。回忆起之前知乎划水时瞥见的CI/CD工具貌似能满足要求,于是在对比了几十种相关工具后1,最终Drone以其开源、简易赢得了我的青睐,然后花了大概1-2天的时间入门、整理完成了本博客的自动化部署。

本文主要工作如下:

  1. 对CI/CD的相关概念进行整理。
  2. 对Drone的安装过程及常见问题进行详细介绍。
  3. 以本站为例,结合Drone和exec实现Github推送的自动部署。

CI/CD介绍

CI即持续集成(Continuous Integration),是在源代码变更后自动检测、拉取、构建和进行自动化测试的过程,属于开发人员的自动化流程。该解决方案可以解决在一次开发中有太多应用分支,从而导致相互冲突的问题。其基本思路是,自动化监测代码仓库的变化并拉取最新代码、编译构建和自动化测试。CI的触发方式可分为以下三种: 轮询:按一定的时间间隔反复询问代码仓库是否发生了变更,若发生了变更则开启CI流程;定时:定期从代码仓库拉去最新代码并进行构建与测试,不必关心是否有变更发生;推送:当代码仓库发生变更时,通过推送的方式(如webhook)通知CI进行任务,这需要CI环境被代码仓库访问到,因此需要一个公网可达地址。

CD即持续交付(Continuous Delivery)或持续部署(Continuous Deployment)。持续交付通常是指开发人员对应用的更改会自动进行错误测试并上传到存储库(如 GitHub 或容器注册表),然后由运维团队将其部署到实时生产环境中。持续部署指的是自动将开发人员的更改从存储库发布到生产环境,它以持续交付为基础,实现了管道后续阶段的自动化。 CI/CD 既可能仅指持续集成和持续交付构成的关联环节,也可以指持续集成、持续交付和持续部署这三项构成的关联环节2

环境安装

Drone与流行的源代码控制平台(GitHub、GitLab、Gogs、Gitea、Bitbucket Cloud、Bitbucket Server、Gitee)可以无缝集成,官方文档皆有所介绍,本文以Github为例进行配置,对Drone工作流程和基础概念不了解可以参考Drone 中的概念:webhooks、workspace、cloning、pipelines、services、plugins、deployments

创建Github OAuth Apps

  1. 在Github中打开 Settings->Developer settings->OAuth Apps ,选择 New OAuth App 。
    https://cdn.jsdelivr.net/gh/wefantasy/FileCloud/img/202203242040589.png
    New OAuth App
  2. 填写相关信息:Application name随意命名、Homepage URL为运行Drone服务器的地址、Authorization callback URLHomepage URL追加/login后的地址、然后点击Register Application
    https://cdn.jsdelivr.net/gh/wefantasy/FileCloud/img/202203242042433.png
    Register Application
  3. 点击创建,并记下Client IDSecrets

安装Drone Server

Drone安装过程主要分为Server、Runner,其中Server是一个独立的守护进程,会轮询服务器以等待执行pipeline;Runner是不同type的pipeline的实际执行者。

  1. Drone的运行需要依赖Docker环境,Docker安装可以参考搭建Hyperledger Fabric 2.3.2开发环境及简单案例运行#基础环境
  2. 使用Docker命令拉取最新稳定镜像。
1
2
docker pull drone/drone:2
docker pull drone/drone-runner-docker:1
  1. 创建docker配置文件docker-compose.yaml,并写入以下内容(docker-compose语法不再赘述):
 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
version: '3'

services:
  drone-server:
    image: drone/drone:2
    ports:
      - 10020:80
    volumes:
      - drone-data:/data:rw
    restart: always
    environment:
      - DRONE_SERVER_HOST=${DRONE_SERVER_HOST:-https://drone.ifantasy.net}
      - DRONE_SERVER_PROTO=${DRONE_SERVER_PROTO:-https}
      - DRONE_RPC_SECRET=${DRONE_RPC_SECRET:-secret}
      - DRONE_GITHUB_SERVER=https://github.com
      - DRONE_GITHUB_CLIENT_ID=${DRONE_GITHUB_CLIENT_ID}
      - DRONE_GITHUB_CLIENT_SECRET=${DRONE_GITHUB_CLIENT_SECRET}

  drone-agent:
    image: drone/drone-runner-docker:1
    restart: always
    depends_on:
      - drone-server
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:rw
    environment:
      - DRONE_RPC_PROTO=http
      - DRONE_RPC_HOST=drone-server
      - DRONE_RPC_SECRET=${DRONE_RPC_SECRET:-secret}
      - DRONE_RUNNER_NAME=${HOSTNAME:-drone}
      - DRONE_RUNNER_CAPACITY=2
    dns: 114.114.114.114

volumes:
  drone-data:

其中主要参数含义如下3

  • DRONE_GITHUB_CLIENT_ID: 在Github中创建OAuth Application时生成的Client ID
  • DRONE_GITHUB_CLIENT_SECRET: 在Github中创建OAuth Application时生成的Client Secret
  • DRONE_SERVER_PROTO: Drone提供服务的prototype,可选为http或https
  • DRONE_SERVER_HOST: Drone的server地址,可设置为外部可访问的域名或IP地址
  • DRONE_TLS_AUTOCERT: 设置是否自动开启安全传输层协议,若设置为true,那么drone server proto会设置为使用https,DRONE_SERVER_PROTO设置为http也是无效
  • DRONE_RUNNER_CAPACITY: drone提供服务的最大并行度
  • DRONE_SECRET_SECRET: 可自由设置
  1. 在docker-compose.yml同级目录下创建文件.env,内容如下:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 必填 服务器地址
DRONE_SERVER_HOST=drone.ifantasy.net
DRONE_SERVER_PROTO=http
# 请自行生成秘钥对,你可以用命令openssl rand -hex 16生成,然后黏贴在这里
DRONE_RPC_SECRET=fantasy
HOSTNAME=drone
# 必填 在 GitHub 应用页面查看
DRONE_GITHUB_CLIENT_ID=${Client ID}
# 必填 在 GitHub 应用页面查看
DRONE_GITHUB_CLIENT_SECRET=${Secrets}
  1. 在该目录下使用docker-compose up -d命令启动docker容器。
    至此Drone基础服务安装完毕,可以通过对应域名或服务器10020端口访问其提供的web服务,也已经能够执行一部分自动化操作,但是如果此时调用所需exec类型的pipeline,用户界面的Last Status会始终处于Pending状态4,原因是没有安装drone-runner-exec
    https://cdn.jsdelivr.net/gh/wefantasy/FileCloud/img/202203251011861.png
    基础服务安装完毕

安装drone-runner-exec

  1. 下载服务器对应的安装包:
1
2
curl -L https://github.com/drone-runners/drone-runner-exec/releases/latest/download/drone_runner_exec_linux_amd64.tar.gz | tar zx
sudo install -t /usr/local/bin drone-runner-exec
  1. 创建配置文件/etc/drone-runner-exec/config,写入如下内容:
1
2
3
4
DRONE_RPC_PROTO=http
DRONE_RPC_HOST=127.0.0.1
DRONE_RPC_SECRET=fantasy
DRONE_LOG_FILE=/var/log/drone-runner-exec/log.txt

其中各参数含义如下:

  • DRONE_RPC_PROTO:与Drone服务器连接协议类型,本例drone-runner-exec与Drone Server运行在同一服务器上,所以不需要https
  • DRONE_RPC_HOST:运行Drone Server服务的地址
  • DRONE_RPC_SECRET:必须与上文中.env文件中的DRONE_RPC_SECRET参数一致
  • DRONE_LOG_FILE:日志文件地址
  1. 运行以下命令安装服务:
1
2
drone-runner-exec service install
drone-runner-exec service start
  1. 不出意外的话可以在/var/log/drone-runner-exec/log.txt中看到以下内容:
1
2
INFO[0000] starting the server
INFO[0000] successfully pinged the remote server

当然,跟着官方文档大概率是会出意外的,比如在以上流程结束后,你的任务流还是一直处于Pending状态,正当你手足无措时偶然在/var/log/drone-runner-exec/log.txt日志文件中看见下列错误:

  • required key CLIENT_DRONE_RPC_HOST missing value:表示drone-runner-exec service start时没有收到CLIENT_DRONE_RPC_HOST参数,个人认为可能是Drone官方的BUG,此时可尝试将/etc/drone-runner-exec/config中的配置以环境变量的方式运行5
    1
    
    DRONE_LOG_FILE=/var/log/drone-runner-exec/log.txt DRONE_RPC_HOST=127.0.0.1:10020 DRONE_RPC_SECRET=fantasy drone-runner-exec
    
  • cannot ping the remote server:可能是将DRONE_RPC_HOST配置为了域名,而域名使用了CloudFlare等CDN加速导致无法直接访问到服务器,将该值改为服务器IP地址即可,本文中drone-runner-exec与Drone Server运行在统一服务器上,所以可以直接写为127.0.0.1

实例

经过以上折腾,如果你没有看过本文的话到这里大概率已经至少大半天时间过去了,而现在我们终于可以体验自动化集成带来的快乐,接下来以本博客网站为例实现:将本站内容使用git push到GitHub后,GitHub调用Webhook通知服务器的Drone服务拉取最新的git代码仓库,然后根据代码仓库根目录的.drone.yml文件中exec类型的pipeline实现自动部署。本站相关技术可参考 关于我

激活仓库

  1. 打开docker-compose.yml中配置的网址drone.ifantasy.net,进入Drone服务主页。
    https://cdn.jsdelivr.net/gh/wefantasy/FileCloud/img/202203251011861.png
    基础服务安装完毕
  2. 点击Continue按钮,完成Github登录授权。
  3. 授权成功后即可看到本GitHub账号所有的仓库。
    https://cdn.jsdelivr.net/gh/wefantasy/FileCloud/img/202203251017603.png
    可访问仓库
  4. 选择目标仓库,点击Activate Repository按钮完成激活。
    https://cdn.jsdelivr.net/gh/wefantasy/FileCloud/img/202203251019637.png
    Activate Repository
  5. 可在Drone和Github webhook看到激活成功(FabricLearn仓库为示例,下文实验仓库为MyBlog)。
    https://cdn.jsdelivr.net/gh/wefantasy/FileCloud/img/202203251021149.png
    Drone激活成功
    https://cdn.jsdelivr.net/gh/wefantasy/FileCloud/img/202203251022251.png
    Github激活成功

配置仓库

  1. 将本站最新的仓库代码拉取到本地。
  2. 在根目录下创建Drone配置文件.drone.yml,内容如下(其中各个参数含义在Configure中已有很好的解释):
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
kind: pipeline
type: exec
name: deployment

platform:
  os: linux
  arch: amd64

steps:
  - name: deployment
    commands:
      - cd /var/www/MyBlog/
      - git pull

branches: master

注意:本站使用的Hugo部署方式是,直接将Nginx的静态服务映射到hugo生成的public文件夹,所以只需要使用pull将最新public文件拉取到本地即可完成部署。

https://cdn.jsdelivr.net/gh/wefantasy/FileCloud/img/202203251029943.png
.drone.yml

3. 将最新的修改git push至远程仓库。
4. 推送片刻后,即可在Drone服务主页看到CI执行情况。
https://cdn.jsdelivr.net/gh/wefantasy/FileCloud/img/202203251033425.png
执行结果
https://cdn.jsdelivr.net/gh/wefantasy/FileCloud/img/202203251034745.png
执行过程
5. 清除缓存刷新博客主站,即可看到最新更新内容。

总结

在本文中,我们先是对CI/CD的基础概念和常用场景进行介绍,之后详细介绍了Drone的安装过程和可能遇到的问题及其解决办法,然后以结合本站为例,具体讲解了配置文件的编写方式,最终实现了本站自动化部署的需求。

参考


  1. RancherLabs. 22 款受欢迎的 CI 工具,你想要的都在这里. InfoQ. [2020-05-14] ↩︎

  2. 放不开的时光尾巴. Drone CI:搭建自己CI/CD(一). 知乎. [2020-07-25] ↩︎

  3. 兰陵美酒郁金香. Drone for Github|Golang CI集成. 兰陵美酒郁金香的个人博客. [2021-09-21日] ↩︎

  4. FuSh1. Drone CI/CD 使用 exec 流水线进行持续交付,exec一直卡pending. CSDN. [2021-05-14] ↩︎

  5. bradrydzewski. [Documentation] Potential Documentation Error. discourse.drone.io. [2021-06-20] ↩︎