容器云平台No.10~通过gogs+drone+kubernetes实现CI/CD

什么是CI/CD

持续集成(Continous Intergration,CI)是一种软件开发实践,即团队开发成员经常集成它们的工作,通常每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都需要通过自动化的编译、发布、自动化回归测试来验证,从而尽快地发现集成错误。而这些自动化的操作则由CI软件进行执行。

持续部署(Continous Delivery,CD)在持续集成的基础上,将集成后的代码部署到真实运行环境中(本文指部署到kubernetes集群)。交付团队 ->版本控制 ->构建和单元测试 ->自动验收测试 -> 发布

什么是Drone

Drone 是一个基于Docker容器技术的可扩展的持续集成引擎,用于自动化测试、构建、发布。每个构建都在一个临时的Docker容器中执行,使开发人员能够完全控制其构建环境并保证隔离。开发者只需在项目中包含 .drone.yml文件,将代码推送到 git 仓库,Drone就能够自动化的进行编译、测试、发布。

使用drone实现CD/CD

首先来看下丑陋的图


image.png

简单梳理流程:

1、开发人员向git(gitlab/github/gogs)提交代码,代码中必须包含Dockerfile和.drone.yml文件。
2、将代码commit到远程仓库;发布应用时需要填写服务类型、服务名称、资源数量、实例个数等信息
3、gogs触发drone自动构建
4、Drone的CI流水线中包括了自定义脚本,根据准备好的kubernetes的YAML模板,将其中的变量替换成用户输入的选项
生成应用的kubernetes YAML配置文件
5、Drone的CI流水线自动编译代码并打包成docker镜像推送到Harbor镜像仓库
6、更新DNS,插入一条DNS记录,IP地址是ingress节点的IP地址。
7、Drone的CI流水线中自定义脚本调用kubernetes的API,部署应用;更新Ingress的配置,根据新部署的应用的名称,在ingress的配置文件中增加一条路由信息
接下来,开始实战

部署代码仓库gogs

本文使用gogs,当然你可以选择gitlab,github等代码仓库
1、创建gogs.yaml

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: gogs
  labels:
    app: gogs
spec:
  serviceName: gogs
  replicas: 1
  selector:
    matchLabels:
      app: gogs
  template:
    metadata:
      labels:
        app: gogs
    spec:
      terminationGracePeriodSeconds: 180
      containers:
      - name: gogs
        image: gogs/gogs
        imagePullPolicy: Always
        ports:
        - containerPort: 3000
          name: port
        - containerPort: 22
          name: ssh-port
        volumeMounts:
        - name: volume
          mountPath: /data
      volumes:
      - name: volume
        emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: gogs
  labels:
    app: gogs
spec:
  type: NodePort
  ports:
  - port: 3000
    targetPort: 3000
  selector:
    app: gogs

2、执行部署并查看结果

[root@k8s-node001 gogs]# kubectl  apply -f gogs.yaml 
statefulset.apps/gogs created
service/gogs created

[root@k8s-node001 gogs]# kubectl  get po,svc -o wide 
NAME         READY   STATUS    RESTARTS   AGE    IP               NODE          NOMINATED NODE   READINESS GATES
pod/gogs-0   1/1     Running   0          2m2s   100.68.150.197   k8s-node001   <none>           <none>

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE     SELECTOR
service/gogs         NodePort    10.106.102.74   <none>        3000:30526/TCP   2m3s    app=gogs

3、浏览器打开,并配置gogs,然后就可以登录gogs了


image.png

4、登录gogs


image.png

至此,gogs配置完毕。
Tips:本文的gogs,是测试环境,使用卷类型为:emptyDir,生产环境最好单独部署或者使用StorageClass保证数据持久可用性
接下来部署drone

部署CI工具Drone

1、编写drone.yaml文件

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: drone
  labels:
    app: drone
spec:
  serviceName: drone
  replicas: 1
  selector:
    matchLabels:
      app: drone
  template:
    metadata:
      labels:
        app: drone
    spec:
      terminationGracePeriodSeconds: 180
      containers:
      - name: drone
        image: drone/drone:1
        imagePullPolicy: Always
        env:
          - name: DRONE_AGENTS_ENABLED
            value: "true"
          - name: DRONE_GOGS_SERVER
            value: http://192.168.100.181:30526/  # 注意这里填的是gogs的地址
          - name: DRONE_RPC_SECRET
            value: qawsedrftg
          - name: DRONE_SERVER_HOST
            value: drone.company.com
          - name: DRONE_SERVER_PROTO
            value: http
        ports:
        - containerPort: 80
          name: port
        - containerPort: 443
          name: ssl-port
        volumeMounts:
        - name: volume
          mountPath: /data
      volumes:
      - name: volume
        emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: drone
  labels:
    app: drone
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: drone

2、执行部署并查看结果

[root@k8s-node001 drone]# kubectl  apply -f drone.yaml

[root@k8s-node001 drone]# kubectl get po,svc  -o wide
NAME          READY   STATUS    RESTARTS   AGE     IP   NODE          NOMINATED NODE   READINESS GATES
pod/drone-0   1/1     Running   0          4m40s   100.68.150.198   k8s-node001   <none>           <none>

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE     SELECTOR
service/drone        NodePort    10.100.77.138   <none>        80:31681/TCP     4m40s   app=drone

3、现在就可以用浏览器访问http://192.168.100.181:31681 ,使用gogs的账号就可以登录drone了


image.png

4、登录后可以看到,现在并没有任何项目,后续再gogs新建项目,就能看到了


image.png

部署Drone Runner

Runner的作用是询问Drone Server,然后执行pipeline,更多信息请查看官网
1、编写drone-runner.yaml

---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: drone
rules:
- apiGroups:
  - ""
  resources:
  - secrets
  verbs:
  - create
  - delete
- apiGroups:
  - ""
  resources:
  - pods
  - pods/log
  verbs:
  - get
  - create
  - delete
  - list
  - watch
  - update
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: drone
  namespace: default
subjects:
- kind: ServiceAccount
  name: default
  namespace: default
roleRef:
  kind: Role
  name: drone
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: drone-runner
  labels:
    app.kubernetes.io/name: drone-runner
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: drone-runner
  template:
    metadata:
      labels:
        app.kubernetes.io/name: drone-runner
    spec:
      containers:
      - name: drone-runner
        image: drone/drone-runner-kube:latest
        ports:
        - containerPort: 3000
        env:
        - name: DRONE_RPC_HOST
          value: 192.168.100.181:31681  # Drone Server地址
        - name: DRONE_RPC_PROTO
          value: http
        - name: DRONE_RPC_SECRET
          value: qawsedrftg         # Drone Server部署时候填写的secret

2、执行部署并查看结果

[root@k8s-node001 drone]# kubectl  apply -f drone-runner.yaml

[root@k8s-node001 drone]# kubectl  get po
NAME                            READY   STATUS    RESTARTS   AGE
drone-runner-7c64bffb45-dh2dn   1/1     Running   0          11m

至此,实现CI/CD的环境都准备好了,现在来跑一个demo

CI/CD示例

1、gogs新建项目demo


image.png

2、drone上点sync,就可以看到demo项目


image.png

3、激活demo项目,保存


image.png

4、在gogs的demo项目中,添加.drone.yml文件,添加一个pipeline

image.png

5、提交代码,但是不触发CI,Commit的时候填写[CI SKIP]就可以跳过触发CI


image.png

如果这里直接Commit提交代码,就直接触发CI功能,Drone就开始执行这个pipeline了
[CI SKIP]的作用就是如果需要修改多个文件,这时候会很有用;
当然在实际开发过程中,都是把项目clone到本地,编辑好所有文件,再push到代码仓库,这样就不需要[CI SKIP]了
6、我们这里随便修改 README,然后知己commit,不是用[CI SKIP]看下效果


image.png

7、执行结果,这里失败了,后面再解决


image.png

8、如果您commit以后并没有触发Drone,需要在gogs查看webhooks时候正常,如下图


image.png

9、这里我们来解决pipeline执行失败的问题
我们通过drone界面可以看到项目pipeline报错如下,显示runner clone代码失败了

Initialized empty Git repository in /drone/src/.git/
+ git fetch origin +refs/heads/master:
fatal: unable to access 'http://192.168.100.181:3000/scofield/demo.git/': Failed to connect to 192.168.100.181 port 3000: Connection refused

首先看下这个pipeline,很简单,使用镜像alpine执行两条输出语句

kind: pipeline
type: kubernetes
name: default

steps:
- name: greeting
  image: alpine
  commands:
  - echo hello
  - echo world

但是默认情况下,Drone执行pipeline之前会克隆项目,url就是gogs的http地址,这里是http://192.168.100.181:3000/scofield/demo.git 因为我这里测试环境使用NodePort暴露的服务,Drone需要使用http://192.168.100.181:30526/scofield/demo.git 这个地址才能克隆到项目,如果使用ingress暴露gogs服务,这个url就是域名而不是IP,就不会出现这个问题。
那现在需要解决这个问题,我们就自定义clone,修改默认的克隆地址,修改如下,修改完直接commit代码,触发CI

image.png

通过drone页面查看结果,可以看到clone成功


image.png

而且执行的echo命令也成功执行


image.png

至此本文实战结束

总结

本文是“基于Docker及Kubernetes构建的容器云平台”系列第十篇,也是最后一篇,如果您看完了整个系列文章,在此感谢。
通过这十篇文章,您应该可以构建出一个测试环境的容器平台。关于容器云平台更多内容,后续会继续分享,尽请持续关注。


image.png

PS:后续文章会同步到dev.kubeops.net

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350