我们所要实现的,是代码提交之后,通过Drone将代码自动发布到线上,无需人工处理,所以多数工作实际在于脚本的编写。
而基本原理很简单,这里我使用的代码托管平台为Github
,在提交代码(push)时,Github会向我们的Drone
发送一条通知,内容包含了此次提交的各种信息,然后Drone会进行一系列预设操作,此时的入口默认为项目根目录.drone.yml
文件,则根据该文件的描述执行了我们整个构建过程。
简单画了一下我当前的架构图:
编写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
然后通过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等),所以项目都没必要设为私有。
轻量代码仓库的解决方案有Gogs
、Gitea
等,但我实在折腾不动了,于是把自己的项目改造了一番,涉及账号等私密信息的都不存放在代码里了。
Drone作为一个轻量的CI/CD构建工具,在使用上是完全没有问题的,相比Jenkins这种老大哥,Drone可能更适合小团队或个人使用,而目前国内社区热度似乎也不高,基本没有什么文章,官网文档也过于简单,项目一直在更新中,总之我个人还是比较喜欢这款工具的,希望它能越来越成熟吧。
补充码云 Gitee 相关
由于国内网络的问题,Github服务经常不稳定,后来直接更换到了码云作为发布仓库。有些需要注意的地方说明一下:
0. 仓库404问题
这个问题只在码云会遇到,由于码云的新建仓库逻辑是把仓库名称和链接分开的,所以一定要保证两者一致,采用驼峰写法它会"自作聪明"地给你把链接拆成带'-'的形式,这样drone识别仓库就会404了。
1. SSH算法问题
码云SSh不再能使用ras算法了,所以生成公钥需要使用 ssh-keygen -t ed25519 -C "yourName@xxxx.com"
这种key才可以使用。记得上面的加入主机列表也要改成 - ssh-keyscan -t ed25519 gitee.com >> ~/.ssh/known_hosts