Drone轻量自动化 - 将提交代码与线上部署画上等号

2,797 阅读5分钟

我所使用的集成构建平台为Drone,关于Drone的介绍安装可查看上一篇文章

我们所要实现的,是代码提交之后,通过Drone将代码自动发布到线上,无需人工处理,所以多数工作实际在于脚本的编写。

而基本原理很简单,这里我使用的代码托管平台为Github,在提交代码(push)时,Github会向我们的Drone发送一条通知,内容包含了此次提交的各种信息,然后Drone会进行一系列预设操作,此时的入口默认为项目根目录.drone.yml文件,则根据该文件的描述执行了我们整个构建过程。

简单画了一下我当前的架构图:

image.png

编写yml配置文件

一份基础的.drone.yml配置可能是这样的:

kind: pipeline
type: docker
name: 部署Web项目

clone:
  disable: true

steps:

  - name: docker-clone
    image: alpine/git

  - name: docker-move
    image: alpine

  - name: docker-deploy
    image: appleboy/drone-ssh

trigger:
  branch:
    - publish
  event:
    - push

volumes:
  - name: cache
    host:
      path: /data/cache

可以看到根级的clone选项被我设置了disable: true,这表明无需clone代码,不设置的话drone默认会有一个clone的步骤。

根级steps则具体描述了整个部署过程,它可以是分阶段的,通过-来创建,这里我们整个部署过程都基于docker,在每个步骤下我们必须描述当前会基于哪个镜像操作,然后进行到该步骤时drone会创建一个临时的docker容器,这种容器插件的理念会贯穿在我们整个构建过程中。

多个步骤下,创建的容器实际都是独立的,但它们应该都挂载映射了同一个目录 /drone/src,所有容器的操作都是在这个目录下进行的,假设在步骤1中创建的容器A,创建了一个文件,然后在步骤2中创建容器B,对这个文件进行操作,这就是我部署所有步骤的核心。而具体操作什么,则以步骤2中的容器所依赖的镜像来决定(比如这个文件是Java,那么容器B就应该拉取的是java的docker镜像来操作,很好理解吧)。

根级的trigger我则简单配置了对分支的过滤,意思是只有当提交的代码是publish分支下的,才会执行部署操作。

下面我以一个实例来演示我如何部署。

拉取代码

部署的第一步,是获取目标代码,这个步骤可以使用alpine/git这个镜像

steps:
  - name: docker-clone
    pull: if-not-exists
    image: alpine/git
    environment:
      warehouse_name: 仓库名
      publish_branch: publish
    volumes:
      - name: sshkeys
        path: /root/.ssh
    commands:
      - echo $publish_branch
      - echo $DRONE_GIT_SSH_URL
      - chmod -R 600 /root/.ssh/
      - ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts
      - git clone -b $publish_branch --depth=1 $DRONE_GIT_SSH_URL
      - cd $warehouse_name
      - mv -f ./* /drone/src
      
volumes:
  - name: sshkeys
    host:
      path: /root/.ssh

配置ssh (在宿主机环境, 已配置则忽略) :

ssh-keygen -t rsa -C "your_email@example.com"
cd /root/.ssh/

cat id_rsa.pub

在这一步,前置步骤需要宿主机和Github配置好SSH的公钥私钥,这里主要是让容器内的环境可以使用宿主的sshKey,然后以最低深度clone仓库下publish分支的代码,其中environment是为该环境下注入全局变量。

最后我将clone下来的代码全部移到默认根目录,方便接下来操作。

执行部署

这一步比较灵活,通用的步骤是以ssh连接宿主机,这样进入宿主机之后就可以执行一些docker操作。

- name: link-to-ssh
    pull: if-not-exists
    image: appleboy/drone-ssh
    settings:
      PASSWORD:
        from_secret: PASSWORD
      host: xx.xx.xx.xx
      username: root
      password: PASSWORD
      port: 22
      script:
        - echo hello world

这一步由于涉及到服务器私密信息,不想暴露在配置文件中,于是需要到Drone的对应项目管理下创建一个Secret

image.png

然后通过from_secret即可调用到。

在线编译前端示例

drone会拉取node镜像,然后执行代码编译。

  - name: build-front
    pull: if-not-exists
    image: node
    settings:
      mirror: https://docker.mirrors.ustc.edu.cn
    commands:
      - yarn
      - yarn build

编译完成后可以通过volumes将编译后文件放到宿主机。

由于我个人服务器资源不高,在线编译速度慢,所以我其实是在本地进行打包编译,然后用脚本将打包后的dist目录压缩到publish分支再提交,而drone只需要执行解压文件转移文件即可。这部分与drone没有太大关系,所以暂不展开细说。

尚未解决的问题

目前有一个问题是项目仓库必须是公开的,一旦设为私有库webhook就无法正确请求到drone了,调试很久也不知原因,这在我之前使用Jenkins的时候并无此问题,所以判断应该是drone本身有bug,但如果对于企业项目的话代码不会托管在Github这种第三方平台,都是内部自己的仓库(如gitlab等),所以项目都没必要设为私有。

轻量代码仓库的解决方案有GogsGitea等,但我实在折腾不动了,于是把自己的项目改造了一番,涉及账号等私密信息的都不存放在代码里了。

Drone作为一个轻量的CI/CD构建工具,在使用上是完全没有问题的,相比Jenkins这种老大哥,Drone可能更适合小团队或个人使用,而目前国内社区热度似乎也不高,基本没有什么文章,官网文档也过于简单,项目一直在更新中,总之我个人还是比较喜欢这款工具的,希望它能越来越成熟吧。

补充码云 Gitee 相关

由于国内网络的问题,Github服务经常不稳定,后来直接更换到了码云作为发布仓库。有些需要注意的地方说明一下:

0. 仓库404问题

这个问题只在码云会遇到,由于码云的新建仓库逻辑是把仓库名称和链接分开的,所以一定要保证两者一致,采用驼峰写法它会"自作聪明"地给你把链接拆成带'-'的形式,这样drone识别仓库就会404了。

image.png

1. SSH算法问题

码云SSh不再能使用ras算法了官网文档,所以生成公钥需要:

ssh-keygen -t ed25519 -C "yourName@xxxx.com"

这种key才可以使用。记得上面的加入主机列表也要改成 - ssh-keyscan -t ed25519 gitee.com >> ~/.ssh/known_hosts