基于drone构建CI-CD系统
kubernetes集群三步安装
CI 概述
用一个可描述的配置定义整个工作流
程序员是很懒的动物,所以想各种办法解决重复劳动的问题,如果你的工作流中还在重复一些事,那么可能就得想想如何优化了
持续集成就是可以帮助我们解决重复的代码构建,自动化测试,发布等重复劳动,通过简单一个提交代码的动作,解决接下来要做的很多事。
容器技术使这一切变得更完美。
典型的一个场景:
我们写一个前端的工程,假设是基于vue.js的框架开发的,提交代码之后希望跑一跑测试用例,然后build压缩一个到dist目录里,再把这个目录的静态文件用nginx代理一下。
最后打成docker镜像放到镜像仓库。 甚至还可以增加一个在线上运行起来的流程。
现在告诉你,只需要一个git push动作,接下来所有的事CI工具会帮你解决!这样的系统如果你还没用上的话,那请问还在等什么。接下来会系统的向大家介绍这一切。
代码仓库管理
首先SVN这种渣渣软件就该尽早淘汰,没啥好说的,有git真的没有SVN存在的必要了我觉得。
所以我们选一个git仓库,git仓库比较多,我这里选用gogs,gitea gitlab都行,根据需求自行选择
docker run -d --name gogs-time -v /etc/localtime:/etc/localtime -e TZ=Asia/Shanghai --publish 8022:22 \
--publish 3000:3000 --volume /data/gogs:/data gogs:latest
访问3000端口,然后就没有然后了
gogs功能没有那么强大,不过占用资源少,速度快,我们稳定运行了几年了。缺点就是API不够全。
CI 工具
当你用过drone之后。。。
装:
version: '2'
services:
drone-server:
image: drone/drone:0.7
ports:
- 80:8000
volumes:
- /var/lib/drone:/var/lib/drone/
restart: always
environment:
- DRONE_OPEN=true
- DOCKER_API_VERSION=1.24
- DRONE_HOST=10.1.86.206
- DRONE_GOGS=true
- DRONE_GOGS_URL=http://10.1.86.207:3000/ # 代码仓库地址
- DRONE_SECRET=ok
drone-agent:
image: drone/drone:0.7
command: agent
restart: always
depends_on:
- drone-server
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- DOCKER_API_VERSION=1.24
- DRONE_SERVER=ws://drone-server:8000/ws/broker
- DRONE_SECRET=ok
docker-compose up -d
然后你懂的,也没有然后了
用gogs账户登录drone即可
每个步骤就是个容器,每个插件也是个容器,各种组合,简直就是活字印刷术
怎么使用这种初级肤浅的内容我就不赘述了,但是有很多坑的地方:
- 装drone的机器能用aufs尽量用,device mapper有些插件是跑不了的,如一些docker in docker的插件,这不算是drone的毛病,只能说docker对 docker in docker支持不够好
- centos对aufs支持不够好,如果想用centos支持aufs,那你可得折腾折腾了,社区方案在此:https://github.com/sealyun/kernel-ml-aufs
- 最推荐的是drone的机器内核升级到4.9以上,然后docker使用overlay2存储驱动,高版本内核跑容器笔者也实践过比较长的时间了,比低内核稳定很多
安装方式2,在k8s上安装:
helm install stable/drone
使用篇
首先在你的代码仓库主目录下新建三个文件:
- .drone.yml : 描述构建与部署的流程(狭义),流程配置文件(广义)CI/CD无本质区别
- Dockerfile : 告诉你的应用如何打包成镜像,当然如果不是容器化交付可以不需要
- k8s yaml配置文件 or docker-compose文件 or chart包 :告诉你的应用如何部署
- 其他 :如kube-config等
用gogs账户密码登录到drone页面上之后同步下项目就可以看到项目列表,打开开关就可以关联到git仓库,比较简单,自行探索
官方事例
pipeline:
backend: # 一个步骤的名称,可以随便全名
image: golang # 每个步骤的本质都是基于这个镜像去启动一个容器
commands: # 在这个容器中执行一些命令
- go get
- go build
- go test
frontend:
image: node:6
commands:
- npm install
- npm test
publish:
image: plugins/docker
repo: octocat/hello-world
tags: [ 1, 1.1, latest ]
registry: index.docker.io
notify:
image: plugins/slack
channel: developers
username: drone
各步骤启动的容器共享workdir这个卷, 这样build步骤的结果产物就可以在publish这个容器中使用
结合Dockerfile看:
# docker build --rm -t drone/drone .
FROM drone/ca-certs
EXPOSE 8000 9000 80 443
ENV DATABASE_DRIVER=sqlite3
ENV DATABASE_CONFIG=/var/lib/drone/drone.sqlite
ENV GODEBUG=netdns=go
ENV XDG_CACHE_HOME /var/lib/drone
ADD release/drone-server /bin/ # 因为工作目录共享,所以就可以在publish时使用到 build时的产物,这样构建和发布就可以分离
ENTRYPOINT ["/bin/drone-server"]
上面说到构建与发布分离,很有用,如构建golang代码时我们需要go环境,但是线上或者运行时其实只需要一个可执行文件即可,
所以Dockerfile里就可以不用FROM一个golang的基础镜像,让你的镜像更小。又比如java构建时需要maven,而线上运行时不需要,
所以也是可以分离。
用drone时要发挥想象,千万不要用死了,上面每句话都需要仔细读一遍,细细理解。再总结一下关键点:
drone自身是不管每个步骤是什么功能的,只傻瓜式帮你起容器,跑完正常就执行下个步骤,失败就终止。
编译,提交到镜像仓库,部署,通知等功能都是由镜像的功能,容器的功能决定的 drone里叫插件,插件本质就是镜像,有一丢丢小区别后面说
这意味着你想干啥就弄啥镜像,如编译时需要maven,那去做个maven镜像,部署时需要对接k8s,那么搞个有kubectl客户端的镜像;要物理机部署那么搞个
ansible的镜像,等等,发挥想象,灵活使用。
drone环境变量
有时我们希望CI出来的docker镜像tag与git的tag一致,这样的好处就是知道运行的是哪个版本的代码,升级等等都很方便,不过每次都去修改pipeline
文件显然很烦,那么drone就可以有很多环境变量来帮助我们解决这个问题:
pipeline:
build:
image: golang:1.9.2
commands:
- go build -o test --ldflags '-linkmode external -extldflags "-static"'
when:
event: [push, tag, deployment]
publish:
image: plugins/docker
repo: fanux/test
tags: ${DRONE_TAG=latest}
dockerfile: Dockerfile
insecure: true
when:
event: [push, tag, deployment]
这个例子${DRONE_TAG=latest}
如果git tag事件触发了pipeline那就把git tag当镜像tag,否则就用latest,这样我们自己研发过程中就
可以一直用latest迭代,觉得版本差不多了,打个tag,生成一个可以给测试人员测试的镜像,非常优雅,不需要改什么东西,不容易出错
同理还有很多其它的环境变量可以用,如git的commitID 分支信息等等, 这里可以查
对接k8s实践
首先得有个k8s集群,那么首选:kubernetes集群三步安装 广告,无视就好。。。
有了上面的铺垫,对接k8s就相当简单了:搞个kubectl的镜像嵌入流程中即可:
把项目的k8s yaml文件放到代码中,然后pipelie里直接apply
publish:
image: plugins/docker # 镜像仓库,执行Dockerfile插件
tags:
- ${DRONE_TAG=latest}
insecure: true # 照抄
deploy:
image: kubectl:test # 这个镜像自己去打即可
commands:
- cat test.yaml
- ls
- rm -rf /root/.kube && cp -r .kube /root # k8s 的kubeconfig文件,可以有多个,部署到哪个集群就拷贝哪个kubeconfig文件
- kubectl delete -f test.yaml || true
- kubectl apply -f test.yaml
不过最佳实践还有几个细节:
- k8s 的kubeconfig文件同样放在了代码目录(这个不太安全,不过仓库私有还好,还可以利用drone的secret,不细展开)
- k8s 部署的yaml文件里的镜像怎么配置? 每次都修改test.yaml多不爽
- 如果多个集群yaml配置有区别怎么办?写多个yaml?造成混乱,非常不优雅
所以我们引入chart, 用helm进行部署:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: test
namespace: {{ .Values.namespace }}
spec:
replicas: {{ .Values.replicaCount }}
template:
metadata:
labels:
name: test
spec:
serviceAccountName: test
containers:
- name: test
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" # deployment的yaml文件是模板,创建时再传参进来渲染
imagePullPolicy: {{ .Values.image.pullPolicy }}
....
注意,有了模板之后,我们部署v1版本和v2版本时就不需要改动yaml文件,这样降低出错风险,pipeline执行时把环境变量传进来,完美解决
这样git tag 镜像tag与yaml里镜像配置实现了完全的统一:
deploy_dev: # 部署到开发环境
image: helm:v2.8.1
commands:
- mkdir -p /root/.kube && cp -r .kube/config-test101.194 /root/.kube
- helm delete test --purge || true
- helm install --name test --set image.tag=${DRONE_TAG=latest} Chart
when:
event: deployment
environment: deploy_dev
deploy_test: # 部署到测试环境
image: helm:v2.8.1
commands:
- mkdir -p /root/.kube && cp -r .kube/config-test101.84 /root/.kube # 两个环境使用不同的kubeconfig
- helm delete test --purge || true
- helm install --name test --set image.tag=${DRONE_TAG=latest} Chart # 把git tag传给helm,这样运行的镜像就是publish时构建的镜像,tag一致
when:
event: deployment
environment: deploy_test
以上,优雅的解决了上面问题
细节:event可以是git的事件也可以是手动处罚的事件,类型是deployment时就是手动触发的,drone支持命令行触发
我们进行了二次开发,让drone可以在页面上触发对应的事件
原理篇
drone上开通一个仓库时,会给仓库设置一个webhook,在项目设置里可以看到,这样git的事件就可以通知到drone,drone根据事件去拉取代码走流程
pipeline基本原理
理解原理对使用这个系统非常重要,否则就会把一个东西用死。
pipeline就负责起容器而已,容器干啥的系统不关心,用户决定 这句话本文不止强调过一次,非常重要多读几遍
插件原理
镜像即插件,也就是可能现有很多镜像都能直接当作插件嵌入到drone流程中。
有个小区别是,你会发现drone有些插件还带一些参数,这就是比普通的镜像多做了一丢丢事,如publish时打docker的镜像:
publish:
image: plugins/docker
repo: octocat/hello-world
tags: [ 1, 1.1, latest ]
registry: index.docker.io
你会发现它有 repo tags什么的参数,其实drone处理时非常简单,就是把这些参数转化成环境变量传给容器了,
然后容器去处理这些参数。
本质就是做了这个事情:
docker run --rm \
-e PLUGIN_TAG=latest \
-e PLUGIN_REPO=octocat/hello-world \
-e DRONE_COMMIT_SHA=d8dbe4d94f15fe89232e0402c6e8a0ddf21af3ab \
-v $(pwd):$(pwd) \
-w $(pwd) \
--privileged \
plugins/docker --dry-run
那我们自定义一个插件就简单了,只要写个脚本能处理特定环境变量即可,如一个curl的插件:
pipeline:
webhook:
image: foo/webhook
url: http://foo.com
method: post
body: |
hello world
写个脚本
#!/bin/sh
curl \
-X ${PLUGIN_METHOD} \ # 处理一个几个环境变量
-d ${PLUGIN_BODY} \
${PLUGIN_URL}
FROM alpine
ADD script.sh /bin/
RUN chmod +x /bin/script.sh
RUN apk -Uuv add curl ca-certificates
ENTRYPOINT /bin/script.sh
docker build -t foo/webhook .
docker push foo/webhook
打成docker镜像,大功告成
所以大部分情况我们会很懒的什么也不写,直接在容器里执行命令就是了,同样是一个curl的需求,不写插件的话
pipeline:
webhook:
image: busybox # 直接用busybox
command:
- curl -X POST -d 123 http://foo.com 完事,插件都懒得开发了
值得注意的是一些复杂功能还是需要开发插件的,如publish镜像时用的插件。关于该插件我想补充一句
它是docker里面起了一个docker engine,用docker内的docker engine进行打镜像的
所以devicemapper存储驱动是支持不了的。请升级内核用overlay2,或者ubuntu用aufs
其它推荐
总结
要实现高效的自动化,everything as code很重要,很多人喜欢在界面上点点点 填很多参数上线,其实是一种很容易出错的方式
不一定能提高效率。 你们项目如何构建,如何发布,如何部署都应该是代码,没有二义性,把人做的事让程序做,最终人仅是触发而已。
扫码关注sealyun
个人见解,探讨可加QQ群:98488045
基于drone构建CI-CD系统的更多相关文章
- Gitea 与 Drone 集成实践:完全基于 Docker 搭建的轻量级 CI/CD 系统
Drone 是一个使用 Go 语言编写的自助式的持续集成平台,和 Gitea 一样可以完全基于容器部署,轻松扩展流水线规模.开发者只需要将持续集成过程通过简单的 YAML 语法写入 Gitea 仓库目 ...
- 基于 Kubernetes 实践弹性的 CI/CD 系统
大家好,我是来自阿里云容器服务团队的华相.首先简单解释一下何为 Kubernetes 来帮助大家理解.Kuberentes 是一个生产可用的容器编排系统.Kuberentes 一方面在集群中把所有 N ...
- 用 GitHub Action 构建一套 CI/CD 系统
缘起 Nebula Graph 最早的自动化测试是使用搭建在 Azure 上的 Jenkins,配合着 GitHub 的 Webhook 实现的,在用户提交 Pull Request 时,加个 r ...
- Rancher 构建 CI/CD 自动化流程 - 动态配置 Jenkins-slave(二)
一.说明 1.1 说明 前面介绍采用 Jenkinsfile + KubernetesPod.yaml 方式进行部署项目(Rancher 构建 CI/CD 自动化流程 - 动态配置 Jenkins-s ...
- Gitea 与 Jenkins 的集成实践,打造你的专属 CI/CD 系统
前言 Gitea 是一个用于代码托管的轻量级单体程序,它能与现有的经典应用集成,诸如代码分析工具 SonarQube.持续集成工具 Drone.Jenkins 以及用于工单管理的客户端插件(VSCod ...
- 基于MRS-ClickHouse构建用户画像系统方案介绍
业务场景 用户画像是对用户信息的标签化.用户画像系统通过对收集的各维度数据,进行深度的分析和挖掘,给不同的用户打上不同的标签,从而刻画出客户的全貌.通过用户画像系统,可以对各个用户进行精准定位,从而将 ...
- CI CD系统整合
转载_CI 系统搭建:Git.Gerrit与Jenkins 2014-08-11 20:55 15678人阅读 评论(1) 收藏 举报 分类: 软件集成和项目管理(3) 目录(?)[+] 去年写的这五 ...
- 基于ejbca构建独立ca系统
ejbca,是一个CA(Certificate Authority)系统软件,CA是数字证书认证中心的简称,主要功能是管理数字证书,包括证书的颁发.销毁.更新等,ejbca实现了CA规范,因此可以用来 ...
- Gogs + Drone 实现CI/CD(CD)
前文已经实现CI部分,本文继续以Asp.Net Core实现CD部分. 创建gogs仓库 首先在gogs创建一个空项目drone-ci-demo,本地新建一个asp.net core项目,并且在与.c ...
随机推荐
- gitlab安装笔记一_虚拟机中安装Centos7
(为搭建gitlab环境的准备) 环境:vmware workstation 12 pro 系统: CentOS-7-x86_64-Everything-1804.iso (CentOS-7-Min ...
- linux Apache设置https访问以及加载mod_ssl.so模块以及问题解决
开始之前的话: 1.配置好服务器防火墙的443端口规则: 2.购买好证书文件,我是沃通证书,准备好证书,这里不演示证书的购买和安装. 3.根据服务器类型下载文件,apache一共有4个文件 这里提供沃 ...
- happy machine learning(First One)
从前几天起我就开始了愉快的机器学习,这里记录一下学习笔记,我看的是吴恩达老师的视频,这篇博客将会按吴老师的教学目录来集合各优良文章,以及部分的我的个人总结 1. 监督学习与无监督学习 监督:给定一个 ...
- java源码解析之String类(一)
String是我们接触最多的类,无论是学习中还是工作中,基本每天都会和字符串打交道,从字符串本身的各种拼接.切片.变形,再到和其他基本数据类型的转换,几乎无时无刻都在使用它,今天就让我们揭开Strin ...
- 寻找图的强连通分量:tarjan算法简单理解
1.简介tarjan是一种使用深度优先遍历(DFS)来寻找有向图强连通分量的一种算法. 2.知识准备栈.有向图.强连通分量.DFS. 3.快速理解tarjan算法的运行机制提到DFS,能想到的是通过栈 ...
- 图片加载时间缓慢问题API
一.背景 最近段时间,开发写值工具项目中,出现图片加载问题API,响应时间缓慢:为了优化图片加载问题,我进行图片压缩方法,然后API的图片加载还是慢,最终在自己无意中乱写找到了根本的原因. ...
- Oracle Awr报告_生成
AWR的概念 Oracle数据库是一个使用量很多的数据库,关于Oracle数据库的性能.Oracle10g以后,Oracle提供了一个性能检测的工具:AWR(Automatic Workload Re ...
- TCP/IP网络协议
OSI七层模型 OSI采用了分层的结构化技术,共分七层,物理层.数据链路层.网络层.传输层.会话层.表示层.应用层. TCP/IP模型 OSI模型比较复杂且学术化,所以我们实际使用的TCP/IP模型, ...
- C++ 洛谷 P2921 [USACO08DEC]在农场万圣节Trick or Treat on the Farm 题解
P2921 [USACO08DEC]在农场万圣节Trick or Treat on the Farm 分析: 这棵树上有且仅有一个环 两种情况: 1.讨论一个点在环上,如果在则答案与它指向点相同, 2 ...
- ORM的查询
基于对象的跨表查询(sql里的子查询)(重点) 一对多查询: Book(有外键)--------------->Publish 属于正向查询 按book表里的字段book.publis ...