Jenkins+kubernetes流水线构建java项目

        在传统的业务环境中,我们的应用部署或者更新都是采用手工的方式,但是在企业内部,应用架构一般都采用微服务,大部分项目都会对应几十个、上百甚至上千个微服务,并且还不仅仅只有一个项目,所以采用收工方式上线是不太现实的事情,特别是随着应用的增多,对应的工作量也变得不可想象。由于上线的过程一般比较固定,大都是提前规定好、比较一致的流程,因此采用工具来完成这类“死板”的工作时比较推荐的方式,同时也能减少手工操作所带来的故障风险。
        本章主要介绍在生产环境中持续集成(Continuous Integration,CI)与持续部署(ContinuousDeployment,CD)的使用,实现Jenkins 流水线脚本自动发布应用到 Kubernetes 集群中,当然 CI/CD是 Devops 中非常重要的一个环节。

一、CI/CD 介绍

        CI/CD 是一种通过在应用开发阶段引入自动化来频繁向客户交付应用的方法。CI/CD 的核心概念是持续集成、持续交付(Continuous Delivery,CD)和持续部署。作为一个面向开发和运营团队 的解决方案,CI/CD 主要针对在集成新代码时所引发的问题(也称“集成地狱”)。
        具体而言,CI/CD 在整个应用生命周期内,(从集成和测试阶段到交付和部署)引入了持续自动化和持续监控,这些关联的事物通常被称为“CI/CD 管道”,由开发和运维团队以敏捷方式协同支持。

1.持续集成(CI)

        现代应用开发的目标是让多位开发人员同时开发同一个应用的不同功能。但是,如果企业安排在一天内将所有分支源代码合并在一起,最终可能导致工作烦琐、耗时,而且需要手动完成。这是因为当一位独立工作的开发人员对应用进行更改时,有可能会有其他开发人员同时进行更改,从而引发冲突。

        持续集成可以帮助开发人员更加频繁地将代码更改合并到共享分支或主干中。一旦开发人员对应用所做的更改被合并,系统就会通过自动构建应用并运行不同级别的自动化测试(通常是单元测试和集成测试)来验证这些更改,确保更改没有对应用造成破坏。这意味着测试内容涵盖了从类和函数到构成整个应用的不同模块,如果自动化测试发现新代码和现有代码之间有冲突,持续集成可以更加轻松快速地修复这些错误。

2.持续交付(CD)

        完成持续集成中构建单元测试和集成测试的自动化流程后,通过持续交付可以自动将已验证的代码发布到存储库。为了实现高效的持续交付流程务必要确保持续交付已内置于开发管道。持续交付的目标是拥有一个可随时部署到生产环境的代码库。
        在持续交付中,每个阶段(从代码更改的合并到生产就绪型构建版本的交付)都涉及测试自动化和代码发布自动化。在流程结束时,运维团队可以快速、轻松地将应用部署到生产环境中。

3.持续部署(CD)

        对于一个成熟的 CI/CD 管道来说,最后的阶段是持续部署。作为持续交付(自动将生产就绪型构建版本发布到代码存储库)的延伸,持续部署可以自动将应用发布到生产环境中。由于生产之前的管道阶段没有手动门控,因此持续部署在很大程度上都得依赖精心设计的测试自动化。
        实际上,持续部署意味着开发人员对应用的更改在编写后的几分钟内就能生效,这更加便于持续接收和整合用户反馈。总而言之,所有这些 CI/CD 的关联步骤都有助于降低应用的部署风险因此更便于以小件的方式(非一次性)发布对应用的更改。不过,由于还需要编写自动化测试以适应 CI/CD 管道中的各种测试和发布阶段,因此前期投资会很大。

4.CI 和 CD 的区别

        CI/CD 中的 CI 即持续集成,它属于开发人员的自动化流程。成功的 CI 意味着应用代码的最新更改会定期构建、测试并合并到共享存储中。该解决方案可以解决在一次开发中有太多应用分支,从而导致相互冲突的问题。CI/CD 中的 CD诣的是持续交付或持续部署,这些相关概念有时会交叉使用。两者都事关管道后续阶段的自动化,但它们有时也会单独使用,用于说明自动化程度。
        持续交付通常是指开发人员对应用的更改会自动进行错误测试并上传到存储库(如 Gitlab 或容器注册表),然后由运维团队将其部署到实时生产环境中,旨在解决开发和运维团队之间可见性及沟通较差的问题,因此持续交付的目的就是确保尽可能减少部署新代码时所需的工作量。
        持续部署指的是自动将开发人员的更改从代码库发布到生产环境中以供客户使用,它主要为解决因手动流程降低应用交付速度,从而使运维团队超负荷的问题。持续部署以持续交付的优势为根基,实现了管道后续阶段的自动化。
        CI/CD 既可能仅指持续集成和持续交付构成的关联环节,也可以指持续集成、持续交付和持续部署这 3个方面构成的关联环节。更为复杂的是有时持续交付也包含持续部署流程。
        纠缠于这些语义其实没有必要,只需记得 CI/CD 实际上就是一个流程(通常表述为管道),用于在更大程度上实现应用开发的持续自动化和持续监控。

二、项目环境

1.项目介绍

        kubernetes 目前是最为流行的应用运行环境,应用以容器的形态运行在平台之上,可以实现一些动态的策略,保证服务的 SLA。因此 Devops 也必须适应这种新形态应用的部署的方式。而对 Devops 来讲其实容器化的出现以及容器平台的出现,其实让 DevOps 更为简单了。在使用 Jenkins kubernetes 插件的时候,你就会对流水线的认知更加深刻。

        总结起来具有以下优势:

  • 容器化平台的动态创建 slave 的方式节约了系统的资源,构建结束后可自行销毁。
  • 容器化配置同一流水线的不同的步骤运行环境,且在一定程度上实现隔离。
  • kubernetes Pod 的多容器共享 volume 的机制,让各个流水线共享操作的中间产物。
  • 模块化的配置流水线的方式,可以对流水线不同版本的工具进行统一的配置管理。

        传统的 kubernetes 的操作方式是在一个环境下配置所有的工具,导致对 Jenkins master/slave的环境配置要求较大。而到了容器的平台之上,不同的环境的操作可以天然的隔离到不同的容器之中,而且可以像搭积木一样实现流水线分工,还能通过存储共享的方案实现互相之间中间产物的传递,可以说真正的将流水线的设计提现的淋漓尽致。

2.设备清单

三、安装流水线环境

1.安装kubernetes集群

2.安装jenkins

本案例账号密码

admin

admin

3.安装Gitlab

本案例账号密码

root

pwd12345

4.安装Harbor

本案例账号密码

admin

Harbor12345

四、添加凭据

        在使用 Jenkins、GitLab、Harbor、Kubemetes 打造 DcvOps 平台实现 CI/CD 时,需要涉及很多证书、账号和密码、公钥和私钥的配置,这些凭证需要放在一个统一的地方管理,并且.能在整个流水线中使用,而 Jenkms 提供的 Credentials 插件可以满足以上要求,并且在流水线中也不会泄露相关的加密信息。所以 Harbor 的账号和密码、GltLab 的私钥、Kubernetes的证书均使用,Jenkins 的 Credentials 管理。

1.添加Kubernetes 证书

        在安装和维护 Kubernetes 集群时,都是使用 kubect1 操作集群,而 kubect1 操作集群需要-个KUBECONFIG 文件,我们使用 Jenkins 控制 Kubernetes 时,也是使用该文件,所以该文件需要放置在Credentials 中,之后可以被 Jenkins 的 Kubernetes 插件使用。首先需要找到集群中的 KUBECONFIG,一般是 kubectl 节点的~/.kube/confg 文件,或者是 KUBECONFIG
环境变量所指向的文件,例如/etc/kubernetes/admin.conf 文件

(1)准备 config 文件

将 kubernetes 的 master 主机中 config 文件拷贝出来放到本地主机上。

(2)上传 config 文件

Dashboard-->Manage Jenkins-->Credentials

点击 system 的“全局”域,并添加凭据

 注意:
ID:study-k8s-kubeconfig

描述:k8s study 环境 kubeconfig

(3)用上一步中生成的凭据创建 kubernetes 连接

Dashboard-->Manage Jenkins-->Clouds-->Clouds, 点击“New cloud为kubernetes集群设置名称:kubernetes-study.

2.配置 Harbor 账号和密码 

(1)在 jenkins 中找到凭据项

Dashboard-->Manage Jenkins-->Credentials

(2)添加 Harbor 凭据

填写 harbor 用户的账号密码
本案例的账号密码为 admin 和 Harbor12345

设置 ID 为“HARBOR_ACCOUNT"

3.最后的所有凭据 

 4.配置Agent

(1)什么是 Agent

        Jenkins Agent 是 Jenkins 的一个插件,它的作用是跨平台地在分布式环境中构建和执行任务。它可以在不同的操作系统和架构上运行,并且可以由Jenkins Master 上的特定 Jenkins Job 来指定程序和参数,以便在 Agent 上执行。Jenkins Agent 可以在计算机上实时唤醒或远程连接来执行任务。

(2)Jenkins Agent 的作用
  • 分布式构建:分布式构建是指将一个单一任务分摊到多个计算机上执行,以提高构建速度和效率。Jenkins Agent 用于在不同的节点上分别执行单元测试、编译和构建部分、测试任务等。
  • 管理远程计算机:JenkinsAgent 可以远程连接到目标计算机,实现管理和监控远程计算机的功能。例如,可以使用 Agent 在远程计算机上执行命令、上传文件或下载日志等操作。
  • 自动化测试:Jenkins Agent 可以用于自动化测试环境中。例如,在 Android 应用测试中,可以使用 Jenkins Agent 在通过 Android 模拟器启动测试设备,然后执行自动化测试任务。
(3)添加代理

Dashboard-->Manage Jenkins-->Security

找到代理项,设置端口为 50000

备注:
        有了这个代理,在 kubernetes 上为节点做个标签(本案例的标签为“build=true”),之后的jenkinsfile 的 agent 就会根据这个标签创建 Pod。

五、自动化构建java项目

1.在 Harbor 中添加项目,名称为 kubernetes

2.所有的 docker 主机(包括 kubernetes 主机)设置 harbor 仓库

(1)设置各个主机的 私有仓库
cat /etc/docker/daemon.json 
{
"exec-opts":["native.cgroupdriver=systemd"],
"registry-mirrors":["https://cf-workers-docker-io-8jv.pages.dev"],
"insecure-registries":["192.168.10.106"]
}
(2)重启 docker 进程 
systemctl daemon-reload
systemctl restart docker
(3)测试私有仓库 
docker tag centos:7 192.168.10.106/kubernetes/centos:7
docker login -u admin -p Harbor12345 http://192.168.10.106docker push 192.168.10.106/kubernetes/centos:7

 3.创建 java 测试用例

在 gitlab 中添加项目
项目来自 https://gitee.com
https://gitee.com/kgc-wjq/spring-boot-project.git

 4.定义jenkinsfile

        jenkinsfile 定义流水线的步骤包括拉取代码、执行构建、生成镜像、更新 Kubernetes 资源等。本案例将 jenkinsfile 放置于项目源代码一并管理,也可以单独放置于一个 Git 仓库进行管理。
        接下来在 GitLab 的源代码中添加 jenkinsfile。首先单击代码首页的“十’,然后单击 Upload file上传编辑好的文件,文件名字为 Jenkinsfile文件内容参考本文件附件 Jenkins

5.编写dockerfile

        接下来在 GitLab 的源代码中添加 Dockerfile。首先单击代码首页的“十’,然后单击 Upload file上传编辑好的文件,文件名字为 Dockerfile,Dockerfile 需要和 Jenkinsfile 在同一级目录下。该dockerfile 用来创建一个 java 的镜像,并且在该镜像中放置构建好的 maven 项目的 jar 包。

Dockerfile 的内容如下:

 6.定义 kubernetes 资源

(1)在kubernetes 中为 node1 做标签
[root@master ~]# ku label node node1 build=true
node/node1 labeled

备注:
为 agent Pod 调度到指定的节点 

(2)创建命名空间
[root@master ~]# ku create namespace kubernetes
namespace/kubernetes created
(3)创建 secret 保存 harbor 的认证信息 
[root@master ~]# ku create secret docker-registry harborkey --docker-server=192.168.10.106 --docker-username=admin --docker-password=Harbor12345 --docker-email=3315715079@qq.com -n kubernetes
secret/harborkey created
 (4)编写应用的Deployment

这里创建一个 nginx 的应用程序,用来运行 spring-boot 项目

[root@master ~]# cat spring-boot-project.yaml 
---
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: spring-boot-project
  name: spring-boot-project
  namespace: kubernetes
spec:
  ports:
  - name: web
    port: 8761
    protocol: TCP
    targetPort: 8761
  selector:
    app: spring-boot-project
  sessionAffinity: None
  type: NodePort
status:
  loadBalancer: {}
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  creationTimestamp: null
  name: spring-boot-project
  namespace: kubernetes
spec:
  rules:
  - host: spring-boot-project.test.com
    http:
      paths:
      - backend:
          service:
            name: spring-boot-project
            port: 
              number: 8761
        path: /
        pathType: ImplementationSpecific
status:
  loadBalancer: {}
---
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: spring-boot-project
  name: spring-boot-project
  namespace: kubernetes
spec:
  replicas: 1
  selector:
    matchLabels:
      app: spring-boot-project
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: spring-boot-project
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - spring-boot-project
              topologyKey: kubernetes.io/hostname
            weight: 100
      containers:
      - env:
        - name: TZ
          value: Asia/Shanghai
        - name: LANG
          value: C.UTF-8
        image: nginx:1.7.9
        imagePullPolicy: IfNotPresent
        lifecycle: {}
        name: spring-boot-project
        ports:
        - containerPort: 8761
          name: web
          protocol: TCP
        resources:
          limits:
            cpu: 994m
            memory: 1170Mi
          requests:
            cpu: 10m
            memory: 55Mi
      dnsPolicy: ClusterFirst
      imagePullSecrets:
      - name: harborkey
      restartPolicy: Always
      securityContext: {}
      serviceAccountName: default
 (5)创建该资源(该资源会调度到 node01 或 node02)
[root@master ~]# ku create -f spring-boot-project.yaml 
service/spring-boot-project created
ingress.networking.k8s.io/spring-boot-project created
deployment.apps/spring-boot-project created
[root@master ~]# ku get pod -n kubernetes
NAME                                   READY   STATUS              RESTARTS   AGE
spring-boot-project-6656bb496b-klcxg   0/1     ContainerCreating   0          2s

7.创建 jenkins 任务 

(1)新建 Item

项目名称:spring-boot-project
项目类型:Pipline

(2)创建一个 SCM 项目

在 Pipline(流水线)区域输入 Git 仓库地址,分支为 master,保存

 (3)单击 Build Now 开始构建

注意:
        创建完成后,单击 Build Now(由于 Jenkins 参数由 Jenkinsfile 生成,因此第一次执行流水线会失败),第一次构建结束后,可以看到 Build Now变成了 Build with Parameters。单击 Build withParameters 后,可以读取到 Git 仓库的分支,之后可以选择分支手动构建。

(4)查看svc
[root@master ~]# ku get svc -n kubernetes
NAME                  TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
spring-boot-project   NodePort   10.96.13.141   <none>        8761:30502/TCP   6m32s
(5)访问测试

http://192.168.10.101:31298/

8.设置 jenkins 的自动触发

(1)设置“构建触发器”

项目-->配置-->构建触发器,勾选项目的 webhook

(2)设置“构建触发器”的高级选项

(3)复制出token 值和 webhook URL

Token:
8e87a846cxXXXXXXX2d6505XXXXX


webhook URL:
http://192.168.10.104:8080/jenkins/project/spring-boot-project

9.设置 Gitlab 的触发机制

(1)找到 Admin 选项

单击 Menu-->Admin

(2)设置网络允许外发请求

Menu-->Admin-->Settings-->Network-->Outbound requests

(3)设置0utbound request

(4)设置项目的webhook 参数

打开自己创建的项目,Settings-->Webhooks
填写前面步骤中生成的 webhook 的 URL 和 Token
最后点击页面底部的 Add Webhook 按钮

(5)点击测试按钮测试

六、项目总结

        本节课提供了 Jenkins 在 kubernetes 环境中的使用方案,该方案是利用 Jenkins kubernetes 插件的方式运行流水线,并可以自己动态构建所需要的流水线运行环境。使用 wcredential 凭据管理的方式使用 Jenkins 凭据,减少敏感信息的明文存储。并可以使用 groovy 脚本配合声明式 pipline 配置来进行更加复杂的操作。

上一篇:宠物咖啡馆在线体验:SpringBoot技术的应用


下一篇:Vue中使px自动转化为rem配置(h5适配问题)