上一次我们使用Gitea搭建了自己的Git版本控制系统,可以用来管理自己的代码
还需要一个自动构建工具来解放生产力,这里我推荐使用Drone来搭建CI/CD持续集成,持续部署平台
为什么选用Gitea+Drone呢?因为这两款软件都是基于go编写的,运行过程中可谓十分轻量级,对于资源的占用都是很少的,并且都可以基于docker来安装,安装部署起来十分方便
相对来说主流的Gitlab+Jenkins一套下来对于资源的占用,个人是很难能流畅运行的,至少我的机器连个Gitlab都跑不起来,更别提使用Java编写的Jenkins了。。。
废话少说,直接开搞~
这里我的服务器环境使用的是最新的CentOS7 x64系统,只安装了一个docker
1 安装Gitea
Gitea的安装过程详见:https://ffis.me/experience/1960.html
这里就不做过多的阐述了
2 安装Drone
新版的Drone可以直接使用OAuto2和drone进行通信,无缝集成,配置完成后只需要得到gitea的授权即可进入drone平台,连账户和密码都不用输了
2.1 Gitea创建OAuth2应用程序
我们进入Gitea-->点击右上角头像-->设置-->应用-->管理OAuth2应用程序
来创建一个OAuth2应用程序
这里的重定向URL是授权成功后跳转到drone的地址,根据自己的drone地址来创建
创建成功后就可以拿到客户端ID和客户端密钥了,这里可以先记录下来,我们后边会用到,因为一旦离开这个页面就没法再查看密钥了,只能重新生成
2.2 创建共享密钥
这里我们还需要创建一个共享密钥来供drone和docker-runner通信使用
我们可以使用openssl生成共享密钥:
$ openssl rand -hex 16
da7fb75c68106b563100bec5ce166b72
2.3 安装Docker Compose
这里我使用Docker Compose来部署Drone
Docker Compose是用来批量创建和管理Docker容器的,只需要配置好yml配置文件,就可以批量管理Docker容器
安装过程可参考:https://www.runoob.com/docker/docker-compose.html
2.4 编写docker-compose.yml文件
这里我们通过使用 Docker Compose 来构建并启动 Drone和 Docker Runner,编写 docker-compose.yml 文件
$ mkdir drone
$ cd drone
$ vim docker-compose.yml
在配置文件中,我们设置 docker-compose.yml 的格式为 3 号版本,定义以下两个docker服务。
- Drone Server:使用
drone/drone:1
版本镜像,将 drone 容器的 80 端口映射到宿主机的 7079 端口。映射容器内/data
目录到宿主机的/data/drone
目录,以便 drone 可以保留数据。配置服务自动重新启动,并配置构建 drone 所需的环境变量。 - Docker Runner:使用
drone/drone-runner-docker:1
版本镜像,将 docker 启动句柄挂载到容器/var/run/docker.sock
文件中,以便 drone 可以使用 docker-runner 来执行镜像构建任务。环境变量中需要配置 drone server 的端口协议以及共享密钥,以便与 server 进行通信。
具体配置可参考如下配置:
version: '3'
services:
# 容器名称
fan-drone-server:
# 构建所使用的镜像
image: drone/drone:1
# 映射容器内80端口到宿主机的7079端口
ports:
- 7079:80
# 映射容器内/data目录到宿主机的/data/drone目录
volumes:
- /data/drone:/data
# 容器随docker自动启动
restart: always
environment:
# Gitea 服务器地址
- DRONE_GITEA_SERVER=https://git.ffis.me
# Gitea OAuth2客户端ID
- DRONE_GITEA_CLIENT_ID=aaaaaaaaaaa-8888-8888-8888-fffffffffffff
# Gitea OAuth2客户端密钥
- DRONE_GITEA_CLIENT_SECRET=aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbffffffff
# drone的共享密钥
- DRONE_RPC_SECRET=asdfsadfasdfsadfsadfasdf
# drone的主机名
- DRONE_SERVER_HOST=drone.ffis.me
# 外部协议方案
- DRONE_SERVER_PROTO=https
# 创建管理员账户,这里对应为gitea的用户名
- DRONE_USER_CREATE=username:noisky,admin:true
fan-docker-runner:
image: drone/drone-runner-docker:1
ports:
- 7080:3000
restart: always
depends_on:
- fan-drone-server
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
# 用于连接到Drone服务器的协议。该值必须是http或https。
- DRONE_RPC_PROTO=https
# 用于连接到Drone服务器的主机名
- DRONE_RPC_HOST=drone.ffis.me
# Drone服务器进行身份验证的共享密钥,和上面设置一样
- DRONE_RPC_SECRET=asdfsadfasdfsadfsadfasdf
# 限制运行程序可以执行的并发管道数。运行程序默认情况下执行2个并发管道。
- DRONE_RUNNER_CAPACITY=2
# docker runner 名称
- DRONE_RUNNER_NAME=fan-docker-runner-1
2.5 构建drone和runner
docker-compose up -d
-d 为后台运行
这里我的drone使用的域名访问,是因为我配置了nginx反向代理,如果你没有配置也可以使用ip:端口的形式访问,一定要配置好域名再进行构建,不然会报错
贴出我的drone的nginx反向代理配置,供参考
location / {
proxy_pass http://127.0.0.1:7079/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
2.6 打开drone
到这里如果没有出问题的话drone就构建完成了,我们在浏览器输入配置的drone地址,可看到自动跳转到gitea的授权页面
这里我们进行授权后就跳转到drone的页面了,只需授权一次即可,往后我们登录了gitea就直接进入drone了
进入drone会看到未激活的仓库,我们点击激活它
激活后回到gitea,我们会看到仓库已经自动配置好了web钩子
我们可以进去测试钩子,一般是没问题的
到这里我们的drone就安装完毕了,激活仓库后,我们向仓库推送一个commit,gitea就会发送消息通知drone去干活啦~
3 配置Drone自动构建
drone的安装过程还是很简单的,下面我们来进行drone构建的配置
drone支持不同环境的不同管道配置,这里我使用Docker Pipelines管道配置
简单来说就是drone的每一步操作都在一个临时的drone的容器中进行,容器操作完会自动销毁,容器之间会共享当前的工作目录
这里我还是构建一个springboot工程,下面介绍两种部署方式:
3.1 本地部署
本地部署主要步骤:
- drone拉取最新的代码到当前工作目录
- drone创建maven/grade容器,通过指定的构建工具maven/grade等将代码编译/打包为jar包,然后将jar包和Dockerfile文件复制到挂载的宿主机共享目录中
- drone创建ssh容器,在容器中通过ssh连接到宿主机,通过定义好的命令,到jar和Dockerfile目录中将jar包制作构建为镜像,然后通过镜像创建应用容器并运行,期间会删除之前老的应用程序容器和镜像
- drone创建钉钉通知容器,将构建成功/失败的消息通过钉钉机器人通知到管理员
至此本地构建完毕,这个构建步骤是我自己搞的,其优点是所有操作都在本机执行,构建的应用不用经过网络传输,整体部署的速度很快,其缺点是只能单机部署,无法进行分布式多机器部署,如果自己个人单机使用的话推荐使用这种方式,我的测试demo,整体部署流程下来只用了12s,速度还是很快的
编写drone部署的文件
在仓库的根目录下创建.drone.yml
配置文件
配置文件参考如下配置:
# drone 本地构建
kind: pipeline
type: docker
name: MyHelloWorld
# drone构建步骤
steps:
# 1.maven打包
- name: maven compile
pull: if-not-exists
image: maven:ibmjava-alpine
volumes:
# maven构建缓存
- name: cache
path: /root/.m2
# 挂载宿主机的目录
- name: data
path: /home
commands:
# 开始打包maven工程
- cd demo
- mvn clean package -Dmaven.test.skip=true
# 将打包后的文件复制到宿主机映射目录
- cp target/*.jar /home
- cp ../Dockerfile /home
# 2.使用ssh访问主机制作镜像并运行
- name: ssh commands
pull: if-not-exists
image: appleboy/drone-ssh:1.5.7
settings:
host: 0.0.0.0
username: root
password:
# 从drone仓库配置中秘密空间读取密码
from_secret: ssh_password
port: 22
script:
- echo =======暂停容器=======
- docker stop `docker ps -a | grep springdemo | awk '{print $1}' `
- echo =======暂停旧容器和镜像=======
- docker rm -f `docker ps -a | grep springdemo | awk '{print $1}' `
- docker rmi `docker images | grep springdemo | awk '{print $3}' `
- echo =======开始构建新镜像=======
- cd /data/drone/helloDemo
- docker build -t springdemo:v1 .
- echo =======开始部署应用=======
- docker run -d -p 8188:8180 --name springdemo springdemo:v1
- echo =======清理构建文件=======
- rm -rf *
- echo =======部署成功=======
# 3.钉钉通知
- name: dingTalk notification
pull: if-not-exists
image: guoxudongdocker/drone-dingtalk:latest
settings:
token:
from_secret: dingtalk_token
type: markdown
message_color: true
message_pic: true
sha_link: true
when:
status: [failure, success]
# 挂载的主机卷,可以映射到docker容器中
volumes:
# maven构建缓存
- name: cache
host:
# path: /tmp/cache/.m2
path: /var/lib/cache
# maven构建后与宿主机通信的共享目录
- name: data
host:
path: /data/drone/helloDemo
# drone执行触发器
trigger:
branch:
- master
文件编写完成后,git push到仓库中,gitea会通知drone进行部署,drone找到.drone.yml
配置文件,就会按照配置文件中的步骤进行构建了,部署期间可以在drone中查看到每一步的部署情况
3.2 分布式云部署
云部署主要步骤:
- drone拉取最新的代码到当前工作目录
- drone创建maven/grade容器,通过指定的构建工具maven/grade等将代码编译/打包为jar包,然后将打包完成后的jar移动到根目录,也就是工作目录
- drone创建docker构建容器,将jar通过dockerfile指定的方式构建为镜像,然后将构建完成的镜像上传到腾讯云/阿里云私有仓库中
- drone创建ssh容器,通过ssh连接到一个或多个主机,然后批量从私有仓库中拉取最新镜像进行部署
- drone创建钉钉通知容器,将构建成功/失败的消息通过钉钉机器人通知到管理员
这种方式配置较为简单,所有操作都在docker中进行,没有和主机通讯,并且构建好的镜像直接推送到第三方私有仓库中的,期间会通过网络传输,多多少少都会耗费点时间;
不过好在同一服务商的私有仓库都是通过内网进行访问的,访问速度影响可忽略不计;
而且有很大的优化空间,毕竟我们写的代码只有几百k的大小,其中的系统层、jdk层、lib依赖库层,基本上代码都是不变的;
所以可以通过对docker镜像进行分层构建,分层推送,通过缓存的加速也是可以做到秒级推送,
这样每次更新的就只有我们写的代码,传输的数据量就很少了,不过这个属于比较高级的应用了,我们这里先不研究了;
云部署主要好处是可以做到分布式部署,多个主机可以从私有仓库中拉取最新镜像,实用性还是很高的。
编写drone部署的文件
同样也是在仓库的根目录下创建.drone.yml
配置文件
参考如下配置:
# drone 云部署
kind: pipeline
type: docker
name: MyHelloWorld
# drone构建步骤
steps:
# 1.maven打包
- name: maven compile
pull: if-not-exists
image: maven:ibmjava-alpine
volumes:
# maven构建缓存
- name: cache
path: /root/.m2
commands:
# 开始打包maven工程
- cd demo
- mvn clean package -Dmaven.test.skip=true
# 将打包后的jar包移动到 Dockerfile 文件同级目录
- mv target/demo-0.0.1-SNAPSHOT.jar ../demo-0.0.1-SNAPSHOT.jar
# 2.Docker 制作镜像,推送到私有仓库
- name: docker build
image: plugins/docker
pull: if-not-exists
volumes:
- name: docker
path: /var/run/docker.sock
settings:
username: username
password:
from_secret: dockerHub_password
tags:
- latest
repo: ccr.ccs.tencentyun.com/fanfan/hellodemo
registry: ccr.ccs.tencentyun.com
dockerfile: Dockerfile
# 3.使用ssh访问主机运行最新版容器
- name: ssh commands
pull: if-not-exists
image: appleboy/drone-ssh:1.5.7
settings:
host: 49.234.106.44
username: root
password:
from_secret: ssh_password
port: 22
script:
- echo =======暂停容器=======
- docker stop `docker ps -a | grep springdemo | awk '{print $1}' `
- echo =======暂停旧容器=======
- docker rm -f `docker ps -a | grep springdemo | awk '{print $1}' `
- echo =======开始部署应用=======
- docker run -d -p 8188:8180 --name springdemo --restart=always ccr.ccs.tencentyun.com/fanfan/hellodemo:latest
- echo =======部署成功=======
# 4.钉钉通知
- name: dingTalk notification
pull: if-not-exists
image: guoxudongdocker/drone-dingtalk:latest
settings:
token:
from_secret: dingtalk_token
type: markdown
message_color: true
message_pic: true
sha_link: true
when:
status: [failure, success]
# 挂载的主机卷,可以映射到docker容器中
volumes:
# maven构建缓存
- name: cache
host:
# path: /tmp/cache/.m2
path: /var/lib/cache
- name: docker
host:
path: /var/run/docker.sock
# drone执行触发器
trigger:
branch:
- master
编写好部署的配置文件,推送到仓库中,drone就行按照配置的步骤进行部署了
首次部署的速度可能略慢,我这里用了50s,不过等仓库缓存变热之后速度就上来了,这里我用了33s
总体很是可以接受的,如果进行分层构建优化的话,应该还会再快,不过还是和本地部署的速度没得比,这里根据自己的需要选择不同的部署方式即可,并且不同语言的应用部署的方式是不一样的,可以定制属于自己的部署方式
部署成功后的钉钉通知页面
4 资源占用
Gitea和Drone都是基于go语言编写的,其优点是轻量级,占用资源较少,下面为部署了gitea和drone后的资源占用
可以看到总占用也不到200M的内存,相比传统的gitlab+Jenkins非常轻量化了,并且该有的功能都有,如果用户数不是很大的话,还是很推荐大家使用的
自动部署一旦配置好了,所有的编译/测试/打包/部署的工作就交给drone去完成了,而我们只需要专注于我们的代码编写就行了,是不是特别爽呢?还不快去搭建一个属于自己的自动构建平台吧~
膜拜大佬,请教下大佬,drone在kubernetes的CD操作你是如何实现的?插件需要自己做吗?
請問能知道我這個為什麼所有的build 都是在 pending 嗎?
version: '3'
services:
gitea:
drone-server:
drone-runner:
请问为什么使用exec runner执行的时候无法进入宿主机目录呢,一直在临时目录下,但是宿主机的所有命令是可以用的,但是如果我想在宿主机的home目录下创建文件是不可以的
可以考虑使用SSH连接到宿主机操作...
也就是说,它的这个操作全部都是在临时目录下进行的吗,用完就删除啊,就和travisci差不多那种了吗,它的这个本地执行真的让我以为可以直接操作宿主机......
不知道你的exec runner是什么情况,我用的是docker runner 每一个步骤都在一个docker容器中,操作的文件是共享的,也可以和宿主机进行共享,但是直接操作宿主机我是通过ssh容器再连接到宿主机的,直接操作宿主机好像要配置docker的权限什么的,也可以做 但是较为麻烦所以就没去研究
我看了drone的官方文档,上面说exec runner有一个工作区,工作区在一个临时目录里面,linux的tmp目录,我用pwd查看了,执行完构建就会消失,而且我在构建的过程中使用linux命令是无法切换到宿主机的,比如cd,但是可以在创建的临时目录里面操作,但是可以使用我宿主机里面配置的环境变量,所以我使用exec runner就很疑惑,我可以使用宿主机的任何东西,但是无法和宿主机直接交互,但是这个exec runner官方说的是没有隔离的,我在想我是不是哪里没有配置,比如把这个临时目录映射到宿主机?
你好,刚用drone,请教个问题,使用gitea / drone 来管理代码和cicd,当前对于公共仓库是没有问题的,可是如果设置仓库为私有时,就出现问题了,查阅了官方文档,提到两个参数:DRONE_GIT_USERNAME / DRONE_GIT_PASSWORD,然后也设置了,可是还是无法正常构建和部署,麻烦指导一下,谢谢了
问下 我.drone.yml里有这么一段脚本 secret已经从drone的secrets添加进去了 但是我看运行时打印的 ALIYUN_OSS_BUCKET 变量
并没有打印出*号或者我在drone的secrets添加的变量, 是哪里出错了
deployment-to-oss:
你好,请问为什么我的部署的第一个步骤的clone时间都要花费几十秒甚至分钟级别呢,我看你的截图里基本是1s内
比如你这张图中的第一个步骤
项目代码在KB级别,非常小
这个不太好定位问题,你自己在机器上手动clone一下试试要多久,如果很慢的话就考虑是git服务的速度是不是不太稳定
大佬,请问怎么使用 drone-docker-runner 拉取私有镜像啊。
明明我本地 docker 拥有镜像 A,.drone.yml 中也只声明了一个步骤,在镜像 A 中执行 hello world
但 drone 构建时老是报错:
default: Error response from daemon: Get https://registry-1.docker.io/v2/: dial tcp: lookup registry-1.docker.io on [::1]:53: read udp [::1]:38996->[::1]:53: read: connection refused
default – clone: Error
我的主机连不上互联网,所以需要的镜像都是从外部导入进去的,但是 drone 似乎每次都会重新 pull 镜像,即使我配置了 pull: if-not-exists 也不行。
使用局域网的镜像源,配置了 image_pull_secrets 也不行。
如果只需要在本地主机部署的话,可以放弃容器化流水线的思想,drone-docker-runner里只用一个ssh的镜像,远程连接到主机模拟用户操作就行了
哇,昨晚弄那么晚,今天在互联网环境起了一个 docker-runner,发现他在拉取流水线里面需要的镜像之前拉取了 drone/git 这个镜像,我把这个镜像放到内网中去后就OK了。
真的坑,日志里看不出缺少什么镜像,只看到我配置的那几个 registry-mirrors 拉取失败的消息,也没看到从 insecure-reistries 拉取的消息,误导我老半天了。
楼主,目前springboot单模块应用用这个drone跑起来是没问题的,但是我们目前的项目,是有多个module的,每个module就是一个服务,.drone.xml只能放在根目录,对于这种多模块的项目,你们这边有什么好的方案,谢谢
如果多模块同时部署的话,使用push事件触发drone构建后,可以在编译阶段进入不同的目录依次进行编译打包(如果是主从工程,直接在主工程统一编译打包),然后分别将打包后的jar包发布,在运行部署阶段再统一的部署打包好的服务即可,因为在配置文件里面是很灵活的,具体打包哪一个服务,打包后文件的位置怎么存放,都是可以分别操作的;
docker和其他自动构建工具主要的区别就是drone是容器化思想,将每一个步骤都在一个容易里面运行,如果统一使用docker hub中心部署的方式很方便,如果不适用docker中心仓库部署的话,则需要通过自己处理下容器间具体怎么通信
我们业务上因为经常要把整套系统移植出去,不适合用镜像仓库,直接一整套在同一套机器的;按你刚才说的,一更新就全部应用都更新了,有时我们只需要更新部分应用而已,这个要怎么搞呢
.drone.yml可以写成按照不同分支触发不同的构建条件,可以给需要单独构建的应用写一个分支触发构建
https://docs.drone.io/promote/
谢谢,后面我自己试下;还有个问题,在step之前我定义的environment里面的参数,类似这个
drone 本地构建kind: pipeline
type: docker
name: apiservice
environment:
drone构建步骤PRENAME: oemsys
APPNAME: apiservice
steps:
# 1.maven打包
name: maven compile
name: cachepull: if-not-exists
image: maven:3.6.1-jdk-8-alpine
volumes:
# maven构建缓存
path: /root/.m2
# 挂载宿主机的目录name: data
path: /home
commands:
echo $PRENAMEecho $PRENAME-$APPNAME# 开始打包maven工程
PRENAME,APPNAME这两个参数死活取不出来,是我哪里用错了么
看完很有用,谢谢
因为按照你配置的端口访问不了,我按照官网提供的参考配置配的端口同样访问不了。我不知道问题出在哪,因为我是github+drone,你是gitea+drone,网上搜了好多参考配置都没用,折腾一天了可太难了