Drone 入门指引

最近在尝试用 Drone 替换动辄占用上 G 内存的 jenkins,决定把初步成果分享出来,本文会提供搭配 Gitea 的一个前端和一个 golang 项目的配置样例。

安装

安装非常简单,按照官方给的样例写好 docker-compose.yml 启动即可:

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
services:  
drone-server:
image: drone/drone
restart: always
depends_on:
- fluentd
ports:
- "9001:8000"
volumes:
- /var/local/drone:/var/lib/drone/
env_file:
- .env
logging:
driver: 'fluentd'
options:
fluentd-address: '127.0.0.1:24224'
tag: 'drone-server'

drone-agent:
image: drone/agent
restart: always
depends_on:
- fluentd
- drone-server
volumes:
- /var/run/docker.sock:/var/run/docker.sock
env_file:
- .env
environment:
DRONE_SERVER: "drone-server:9000"
logging:
driver: 'fluentd'
options:
fluentd-address: '127.0.0.1:24224'
tag: 'drone-agent'

其中 .env 的文件内容为:

1
2
3
4
5
6
DRONE_HOST=ci.yourdomain.com # drone 访问域名
DRONE_OPEN=true # 是否开方注册
DRONE_GITEA=true # 是否关联 gitea
DRONE_GITEA_URL=https://git.yourdomain.com # gitea 地址
DRONE_SECRET=xxxx # drone 服务密钥
DRONE_ADMIN=someone # drone 管理帐号,可以修改项目配置

当然还有现成的 gitea 或者其他 git 服务。

下载官方提供的二进制文件提供命令操作功能 http://docs.drone.io/cli-installation/

搭配 gitea 的方案可以直接使用 gitea 的账号登录,登录后进入 Token 页面就可以获取帐号的 token 将其设置到终端的环境变量中就可以使用命令管理 drone 了。

部署

安装完成后进入 drone 页面登录 gitea 的账号即可看到所有有权限的账号,打开开关后 drone 就会自动在 gitea 内注册 webhook

Golang 项目

  • .dron.yml

    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
    clone:
    git:
    image: plugins/git
    # 没有 submodules 时可以关闭改选项
    recursive: false
    # 推荐使用较浅的深度,加快源码下载速度
    depth: 1

    # 条件分支 master
    branches: [ master ]

    pipeline:
    # 使用 cache 插件恢复缓存的 vendor 目录
    restore-cache:
    image: drillster/drone-volume-cache
    # 恢复缓存参数
    restore: true
    mount:
    - ./vendor
    volumes:
    # 这里使用了 volumes 属性,需要开启仓库受信任选项
    - /var/local/drone-cache:/cache

    build:
    # 这里使用了定制 golang 镜像,安装好了 make 以及 dep
    # 自定义镜像的 registry 需要单个项目配置
    # drone registry add -repository <repository> -hostname registry.yourdomain.com -username deployer -password <password>
    # docker pull 的命令实际上是通过 drone/agent 在宿主机上完成的
    # 所以应该预先使用 docker login 在宿主机上登录自建 registry 的账号
    image: registry.yourdomain.com/dep
    # 由于一些不可描述的原因导致很多 golang 包不能下载,一套 http 代理是必须的
    environment:
    - HTTP_PROXY=172.17.0.1:8118
    - HTTPS_PROXY=172.17.0.1:8118
    # dront build 的默认工作目录格式通常为 /dron/src/<org>/<repository>
    # 和 GOPATH 的路径一致,并且 dep 要求项目必须在 GOPATH 下,所以要将 /drone 设置为 GOPATH
    - GOPATH=/drone
    volumes:
    # 编译脚本中用到了时间参数所以需要同步宿主机的时区文件
    - /etc/localtime:/etc/localtime:ro
    commands:
    - dep ensure -v
    # 使用 Makefile 方便在开发过程中编译调试,后面提供文件内容
    - make

    deploy-test:
    # 使用 rsync 发布代码
    image: drillster/drone-rsync
    volumes:
    # 挂载 hosts 文件下面的 hosts 参数可以简写
    - /etc/hosts:/etc/hosts:ro
    hosts:
    - test01
    user: admin
    delete: true
    source: app
    target: /var/local/app
    script:
    ## 发布完成后重启容器
    - cd ~/docker/testing
    - docker-compose restart service1 service2
    when:
    # 当 master 分支收到新的推送时触发该步骤
    branch: master
    secrets:
    # 使用命令添加 ssh-key,用于 rsync 认证
    # 非企业用户只能分别为每个项目添加,不能使用全局密钥功能
    # drone secret add -repository <repository> -name rsync_key -value @/home/admin/.ssh/id_rsa
    - rsync_key

    deploy-prod:
    image: drillster/drone-rsync
    volumes:
    - /etc/hosts:/etc/hosts:ro
    hosts:
    - prod01
    user: admin
    delete: true
    source: app
    target: /var/local/app
    script:
    - cd ~/docker/production
    - docker-compose restart app1 app2
    when:
    # tag 事件需要开启仓库接受 tag 的事件选项,本来文档提示可以增加 branch 参数以限制 tag 是打在某个分支上的
    # 但是 gitea webhook 推送的分支名类似 refs/tags/20180607 不能匹配
    # 所以不能同时添加 branch 参数,可能 gitlab, github 是可以的
    event: tag
    secrets:
    - rsync_key

    rebuild-cache:
    # 使用 cache 插件缓存 vendor 目录
    image: drillster/drone-volume-cache
    # 构建缓存参数
    rebuild: true
    mount:
    - ./vendor
    volumes:
    - /var/local/drone-cache:/cache
  • Makefile

    1
    2
    3
    4
    5
    6
    7
    APP=app
    VERSION=`date +'%Y-%m-%d_%H:%M:%S'`
    FLAGS="-s -w -X main.Version=${VERSION}"
    build:
    go build -gcflags=-trimpath=${GOPATH} -asmflags=-trimpath=${GOPATH} -tags=jsoniter -o ${APP} -ldflags ${FLAGS}
    clean:
    @rm ${APP}

前端项目

  • .drone.yml

    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
    clone:
    git:
    image: plugins/git
    recursive: false
    depth: 1

    branches: [ master ]

    pipeline:
    restore-cache:
    image: drillster/drone-volume-cache
    restore: true
    mount:
    # 缓存 node_modules 文件夹
    - ./node_modules
    volumes:
    - /var/local/drone-cache:/cache

    build:
    # 由于一些不可描述的原因 npm 的有些包以及二进制依赖很难下载
    # 所以定制一个装了 cnpm 的镜像是有必要的
    image: registry.yourdomain.com/cnpm
    volumes:
    - /etc/localtime:/etc/localtime:ro
    commands:
    - cnpm install
    - cnpm run build

    deploy-prod:
    image: drillster/drone-rsync
    volumes:
    - /etc/hosts:/etc/hosts:ro
    hosts:
    - prod01
    user: admin
    delete: true
    # source 目录的写法,不然会把编译后的文件发布到在目标目录的 dist 目录下
    source: ./dist/.
    target: /var/local/www/app/surfaces
    when:
    event: tag
    secrets:
    - rsync_key

    deploy-test:
    image: drillster/drone-rsync
    volumes:
    - /etc/hosts:/etc/hosts:ro
    hosts:
    - test01
    user: admin
    delete: true
    source: ./dist/.
    target: /var/local/www/app/surfaces
    when:
    branch: master
    secrets:
    - rsync_key

    rebuild-cache:
    image: drillster/drone-volume-cache
    rebuild: true
    mount:
    - ./node_modules
    volumes:
    - /var/local/drone-cache:/cache

其他

  • 使用特殊的 commit message 跳过自动部署

    可以通过添加 [CI SKIP] 到提交信息(commit message)中来让 Drone 跳过某个提交。注意,这里的文本是大小写不敏感的。

  • 由于 jenkins workspace 的惯性思考,导致我一直以为有方法可以持久化保留构建过程中的 workspace,以便于挑过下次构建时在重新完整克隆,实际上官方文档有解释 workspace 每次是相当于执行 docker volume create 而创建的,http://docs.drone.io/workspace/ 而且不能二次挂载。不过重新克隆也有降级方案解决,如果仓库历史很冗长,可以通过设置克隆深度解决,如果仓库里的文件庞大可以考虑定制内置的 git 插件替换 克隆逻辑,有人已经有现成的插件输出,虽然他不建议这么做:https://github.com/drone-plugins/drone-git/tree/next

  • todo

    • 配置文件的发布

      目前还没找到一个合适插件可以渲染服务配置文件

    • approve 机制

      drone 的命令里有提供 build 的 approve 和 reject 功能,不过暂时没在文档上找到怎么启用

最后

Drone 是一个轻量级,为容器构建的强大的持续交付平台,依托 docker 强大的生态可以发挥出无限想象 :)