上一次我们使用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去完成了,而我们只需要专注于我们的代码编写就行了,是不是特别爽呢?还不快去搭建一个属于自己的自动构建平台吧~
感觉应该是反向代理配置有问题,你docker容器为什么映射到80和443端口,这应该和nginx的端口是冲突了的;
我搭建的时候是把drone的docker容器映射到了7079 80和443端口是指向nginx 然后nginx再将请求转发到7079的
大佬,可以帮忙把这条留言删了吗,因为我发现涉及到了id,域名,SECRET。我自己再研究研究吧,官网的https://docs.drone.io/server/provider/github/ 和 https://docs.drone.io/runner/docker/installation/windows/参考配置太坑了
ok 已删除 官方的文档确实挺坑的 毕竟是比较冷门的方案 没有什么参考资料 只能自己摸索 不过配置好了应该还是能用的 你再摸索摸索吧
我可以了,之前一直不行原来不是配置的问题,是我用一台Nginx服务器反代我本地的localhost,服务器将localhost认为是自己的localhost所以连不上。我好蠢
我的nginx和docker不在同一台机器上,所以docker drone的127.0.0.1:7079不能反代到nginx的域名上吧?
Hi Noisky,
请问你是在Nginx服务器上运行的docker-compose吗?然后反代了Nginx服务器可以访问的127.0.0.1:7079到域名?
7079是docker容器drone的端口,nginx将域名的访问反代到drone上