ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

从一张图看Devops全流程

2021-04-18 08:52:38  阅读:242  来源: 互联网

标签:tasks NAME 流程 Devops APPLICATION 图看 build openshift name


一、持续交付工具链全图

图片

上图源自网络。上图很清晰地列出了CD几个阶段使用的工具。


CD的工具链很长,但并不是每个模块所有工具都那么流行;换言之,我们在每个模块用好一种工具就足够了。


Build

在SCM的模块中:Git系列用的比较多,如Gitlab;


在CI模块中:Jenkins显然是最流行的;


在Build模块中:Maven、docker用的较多;


Test

在Testing模块中:Junit、Jmeter用的较多;


Deploy

在配置管理模块中:前些年Puppet比较火,这两年Ansible用的比较多;、


在Artifact管理中:Dockerhub是在线的,docker registry是离线的。Openshift的集成镜像仓库用的就是docker registry技术。Quay是CoreOS的镜像仓库工具,有在线也有离线的,相信后续会被整合到Openshift中。

Run

在Cloud/IaaS/PaaS模块中:这两年PaaS的活跃程度超过IaaS,我接触比较多的是其中的Openshift。


在编排模块中:K8S目前是主流,无可争议。


在BI/Monitoring/Logging中:EFK之前用的比较多,但大家普遍看好普罗米修斯。



二、红帽的Devops全图

上图是一个比较典型的Devops流程。包括产品立项、需求分析、应用设计、开发、测试、持续发布、生产运维、回顾阶段。


其中,Openshift可以涵盖中间5个阶段,CloudForms可以覆盖第七个阶段。只有第一个阶段目前红帽产品堆栈无法覆盖。


我们将整个流程进一步技术细节化:

Eclipse IDE工具红帽官网可以下载;Gitlab、Nexus、Jenkins、Openscap、EFK这些工具,红帽官网提供安加固过的容器镜像。


而整个流程串起来,可以通过Jenkins和S2I一起完成的。关于这方面,主要有两种方式:在源码外构建pipeline部署、在源码中构建pipeline部署。



三、在源码外构建pipeline部署应用--流程说明


在源码外构建pipeline的方式,是jenkins的pipeline调用Openshift的S2I、BC、DC等。代码构建是在Openshift中完成;

图片


本实验是根据EAP的基础镜像,构建一个基于Maven编译的应用,编译成功后,生成应用镜像,并在OCP中部署这个应用。


在在本实验中,应用代码地址库链接、应用名称的变量,通过OCP的应用模板导入;bc和dc的操作,均由ocp完成。在bc阶段,项目中会有build pod,

图片

在dc阶段,项目中会有deploy pod。

图片

为了能够通过pipeline显示阶段,在OCP中引入jenkins plugin,jenkins plugin的脚本定义了build和deploy两个阶段。而两个阶段的任务执行,分别是调用bc和dc。

图片

因此,整个代码构建和部署,实际上均由OCP完成。Jenkins只是用来显示执行阶段。也可以根据需要,增加审批流。



两个yaml文件


创建两个yaml文件,一个是openshift-tasks-no-trigger.yaml,一个是pipeline-bc.yaml。


第一个文件创建jkp-tasks引用的bc、dc、routes、rc等资源。

第二个文件创建一个pipeline,定义应用的build和deploy阶段。


第一个文件:

apiVersion: v1

kind: Template

labels:

  template: openshift-tasks-no-trigger

模板名称

metadata:

  name: openshift-tasks-no-trigger

objects:

- apiVersion: v1

  kind: ImageStream

  metadata:

    labels:

      application: ${APPLICATION_NAME}

    name: ${APPLICATION_NAME}

创建的应用image stream名称

- apiVersion: v1

  kind: Service

  metadata:

    annotations:

      description: The web server's http port.

    labels:

      application: ${APPLICATION_NAME}

    name: ${APPLICATION_NAME}

  spec:

    ports:

    - port: 8080

      targetPort: 8080

    selector:

      deploymentConfig: ${APPLICATION_NAME}

- apiVersion: v1

  id: ${APPLICATION_NAME}-http

  kind: Route

  metadata:

    annotations:

      description: Route for application's http service.

    labels:

      application: ${APPLICATION_NAME}

    name: ${APPLICATION_NAME}

  spec:

    to:

      name: ${APPLICATION_NAME}

- apiVersion: v1

  kind: BuildConfig

  metadata:

    labels:

      application: ${APPLICATION_NAME}

    name: ${APPLICATION_NAME}

  spec:

    output:

      to:

        kind: ImageStreamTag

        name: ${APPLICATION_NAME}:latest

将build成功的镜像打成latest的image stream tag。

    source:

      git:

        ref: ${SOURCE_REF}

        uri: ${SOURCE_URL}

      type: Git

    strategy:

      sourceStrategy:

        forcePull: true

        from:

          kind: ImageStreamTag

          name: jboss-eap70-openshift:1.4

          namespace: openshift

构建应用的基础镜像

      type: Source

    triggers:

    - github:

        secret: kJZLvfQr3hZg

      type: GitHub

    - generic:

        secret: kJZLvfQr3hZg

      type: Generic

    - imageChange: {}

      type: ImageChange

    - type: ConfigChange

- apiVersion: v1

  kind: DeploymentConfig

  metadata:

    labels:

      application: ${APPLICATION_NAME}

    name: ${APPLICATION_NAME}

  spec:

    replicas: 1

    selector:

      deploymentConfig: ${APPLICATION_NAME}

    strategy:

      resources: {}

      rollingParams:

        intervalSeconds: 1

        maxSurge: 25%

        maxUnavailable: 25%

        timeoutSeconds: 600

        updatePeriodSeconds: 1

      type: Rolling

    template:

      metadata:

        labels:

          application: ${APPLICATION_NAME}

          deploymentConfig: ${APPLICATION_NAME}

        name: ${APPLICATION_NAME}

      spec:

        containers:

        - env:

          - name: MY_POD_IP

            valueFrom:

              fieldRef:

                apiVersion: v1

                fieldPath: status.podIP

          - name: OPENSHIFT_KUBE_PING_LABELS

            value: application=${APPLICATION_NAME}

          - name: OPENSHIFT_KUBE_PING_NAMESPACE

            valueFrom:

              fieldRef:

                fieldPath: metadata.namespace

          - name: HORNETQ_CLUSTER_PASSWORD

            value: kJZLvfQr3hZg

          - name: JGROUPS_CLUSTER_PASSWORD

            value: kJZLvfQr3hZg

          image: ${APPLICATION_NAME}

          imagePullPolicy: Always

          livenessProbe:

            failureThreshold: 3

            httpGet:

              path: /ws/demo/healthcheck

              port: 8080

              scheme: HTTP

            initialDelaySeconds: 45

            periodSeconds: 45

            successThreshold: 1

            timeoutSeconds: 1

          name: ${APPLICATION_NAME}

          ports:

          - containerPort: 8778

            name: jolokia

            protocol: TCP

          - containerPort: 8080

            name: http

            protocol: TCP

          - containerPort: 8888

            name: ping

            protocol: TCP

          readinessProbe:

            failureThreshold: 3

            httpGet:

              path: /ws/demo/healthcheck

              port: 8080

              scheme: HTTP

            initialDelaySeconds: 20

            periodSeconds: 5

            successThreshold: 1

            timeoutSeconds: 1

        terminationGracePeriodSeconds: 60

    triggers:

    - type: ConfigChange

parameters:

- description: The name for the application.

  name: APPLICATION_NAME

  required: true

  value: tasks

提示输入应用名称

- description: Git source URI for application

  name: SOURCE_URL

  required: true

  value: https://github.com/lbroudoux/openshift-tasks

提示输入源码地

- description: Git branch/tag reference

  name: SOURCE_REF

  value: master

提示输入源码 branch地址


第二个文件

apiVersion: v1

kind: BuildConfig

metadata:

  annotations:

    pipeline.alpha.openshift.io/uses: '[{"name": "jkp-tasks", "namespace": "", "kind": "DeploymentConfig"}]'

  labels:

    name: jkp-tasks-pipeline

  name: jkp-tasks-pipeline

spec:

  strategy:

    jenkinsPipelineStrategy:

      jenkinsfile: |-

        node('maven') {

            stage 'build'

            openshiftBuild(buildConfig: 'jkp-tasks', showBuildLogs: 'true')

定义构建阶段,构建阶段是触发应用的buildConfig

            stage 'deploy'

            openshiftDeploy(deploymentConfig: 'jkp-tasks')

定义构建阶段,构建阶段是触发应用的deploymentConfig

        }

    type: JenkinsPipeline

  triggers:

  - github:

      secret: CzgPZAZ5m2

    type: GitHub

  - generic:

      secret: CzgPZAZ5m2

    type: Generic


实验验证


根据yaml文件创建应用模板:

图片


图片

模板执行成功以后,应用的bc、dc、rc、vip、routes、is等资源就已经创建好了:

[root@master ~]# oc get all

NAME                     TYPE      FROM         LATEST

buildconfigs/jkp-tasks   Source    Git@master   1


NAME                 TYPE      FROM          STATUS    STARTED         DURATION

builds/jkp-tasks-1   Source    Git@bd32abb   Running   2 minutes ago   


NAME                     DOCKER REPO                                            TAGS      UPDATED

imagestreams/jkp-tasks   docker-registry.default.svc:5000/ocp-tasks/jkp-tasks             


NAME                          REVISION   DESIRED   CURRENT   TRIGGERED BY

deploymentconfigs/jkp-tasks   1          1         1         config


NAME               HOST/PORT                              PATH      SERVICES    PORT      TERMINATION   WILDCARD

routes/jkp-tasks   jkp-tasks-ocp-tasks.apps.example.com             jkp-tasks   <all>                   None


NAME                    READY     STATUS             RESTARTS   AGE

po/jkp-tasks-1-build    1/1       Running            0          2m

po/jkp-tasks-1-deploy   1/1       Running            0          2m

po/jkp-tasks-1-kj8ds    0/1       ImagePullBackOff   0          2m


NAME             DESIRED   CURRENT   READY     AGE

rc/jkp-tasks-1   1         1         0         2m


NAME            CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE

svc/jkp-tasks   172.30.58.78   <none>        8080/TCP   2m

接下来,创建jenkins pipeline:


pipeline创建成功以后,触发pipeline执行:

Pipeline已经启动:


此时会生成bc pod。查看build pod的log,build pod会先拉build image的镜像,再拉代码,然后进行build,成功以后push到OCP的内部镜像仓库。

图片

图片

pom和jar包下完完毕以后后,开始build:

图片

然后将成功的war包拷贝到EAP的部署目录中:

图片

最后将build成功的应用镜像推送到集成镜像库:

图片

至此,build阶段完成。


接下来,启动deploy过程:

图片

查看jenkins的日志,deploy的阶段,就是触发dc,很快,dc执行完毕,应用部署成功。

图片

图片

查看maven的日志,maven pod在此流程中,并不做编译工作,只是监听(该pod是为了pipeline的执行为存在):


应用部署成功以后,查看routes:

通过浏览器,可以访问部署好的镜像:



方法总结


此种武器主要利用OCP的S2I进行构建,只是通过Jenkins进行阶段显示。Jenkins的build调用OCP应用的bc、deploy调用的OCP应用的dc。当然,我们也可以根据需要增加审批流程,或者将pipeline做得更复杂。


此这种方法的好处在于配置灵活。支持多用开发语言(在base image中增加不通的编译器即可)。通常情况下,红帽Openshift的CI/CD会推荐使用这种方式。


但是对于在很早以前就已经使用Jenkins做CI/CD的客户,可能会有一些学习成本。


四、在源码内构建pipeline


实验中,我们部署的是一个基于JBoss EAP base image的应用,应用代码位于git代码库。

图片

在上图中,jenkins贯穿整个CI/CD,其中包括:

获取源码----->编译----->生成应用(war包)---->拉取base image---->将应用(war包)与base image合并---->生成App Image---->部署App image。


在本实验中,涉及两个重要的配置文件:openshift-tasks-jenkinsfile和Jenkinsfile。


openshift-tasks-jenkinsfile是创建Jenkins master(执行openshift-tasks-jenkinsfile的模板时,如果项目中没有jenkins的master,会自动触发部署)。

图片


而部署openshift-tasks-jenkins file模板的时候,会提示输APPLICATION_NAME、DEV_PROJECT、SOURCE_URL、SOURCE_REF这几个变量,这些变量会被注入到模板中的BuildConfig部分,并进行覆盖。

图片


openshift-tasks-jenkinsfile的BuildConfig部分定义了Jenkins file的地址。

图片


openshift-tasks-jenkinsfile带着这几个参数,继续触发Jenkin file并注入参数。Jenkins file第一行注明了调用maven,因此会触发部署jenkins maven slave pod。


接下来,在jenkins slave pod中,根据Jenkins file定义的应用的'build'、test、deployInDev三个阶段进行执行,应用的bc和dc也在Jenkins File中生成,最终完成一应用的构建。


接下来,我们先看:openshift-tasks-jenkinsfile完整的文件内容:

apiVersion: v1

kind: Template

labels:

  template: openshift-tasks-jenkinsfile

metadata:

  name: openshift-tasks-jenkinsfile

模板的名称

objects:

- apiVersion: v1

  kind: BuildConfig

BC阶段的定义

  metadata:

    annotations:

      pipeline.alpha.openshift.io/uses: '[{"name": "jkf-tasks", "namespace": "", "kind": "DeploymentConfig"}]'

    labels:

      application: ${APPLICATION_NAME}-jenkinsfile

    name: ${APPLICATION_NAME}-jenkinsfile

  spec:

    source:

      git:

        ref: ${SOURCE_REF}

        uri: ${SOURCE_URL}

      type: Git

    strategy:

      jenkinsPipelineStrategy:

        jenkinsfilePath: Jenkinsfile

      type: JenkinsPipeline

      type: Generic

截至到目前,Jenkinsfile的bc定义完成。jenkinsPipelineStrategy和 jenkinsfilePath指定了这个bc阶段会调用的jenkins file的路径。

    triggers:

    - github:

        secret: kJZLvfQr3hZg

      type: GitHub

    - generic:

        secret: kJZLvfQr3hZg

      type: Generic

parameters:

- description: The name for the application.

  name: APPLICATION_NAME

  required: true

  value: jkf-tasks

通过模板部署应用的时候,提示输入应用的名称,默认名称是jkf-tasks

- description: The name of Dev project

  name: DEV_PROJECT

  required: true

  value: ocp-tasks

通过模板部署应用的时候,提示输入Dev project的名称,默认名称是ocp-tasks

- description: Git source URI for application

  name: SOURCE_URL

  required: true

  value: https://github.com/lbroudoux/openshift-tasks

通过模板部署应用的时候,提示输入SOURCE_URL的名称,默认名称是https://github.com/lbroudoux/openshift-tasks

- description: Git branch/tag reference

  name: SOURCE_REF

  value: master
通过模板部署应用的时候,提示输入SOURCE_REF的名称,默认名称是master。


接来下,查看Jenkins file完整的文件内容:

node('maven') {

代码构建调用maven

  // define commands

  def mvnCmd = "mvn"

  // injection of environment variables is not done so set them here...

在此阶段注入参数变量对以下默认参数数值进行覆盖(从openshift-tasks-jenkinsfile template部署的时候,输入的参数变量带过来):

  def sourceRef = "master"

  def sourceUrl = "https://github.com/lbroudoux/openshift-tasks"

  def devProject = "ocp-tasks"

  def applicationName = "jkf-tasks"

以上代码定义了编译方式,使用maven、定义了源码的地址、在Openshift上的项目(构建在哪发生)、生成应用的名称。

  stage 'build'

    git branch: sourceRef, url: sourceUrl

    sh "${mvnCmd} clean install -DskipTests=true"

以上代码定义了pipeline的构建阶段。调用mvn clean先清理编译环境,然后用mvn install进行构建。

  stage 'test'

    sh "${mvnCmd} test"

以上代码定义了代码测试阶段

  stage 'deployInDev'

    sh "rm -rf oc-build && mkdir -p oc-build/deployments"

    sh "cp target/openshift-tasks.war oc-build/deployments/ROOT.war"

    // clean up. keep the image stream

以上代码定义了在dev阶段部署操作:将编译好的war包,拷贝到 oc-build/deployments目录下

   sh "oc project ${devProject}"

以上代码调用oc client,切换项目。

    sh "oc delete bc,dc,svc,route -l application=${applicationName} -n ${devProject}"

    // create build. override the exit code since it complains about existing imagestream

以上代码清空项目中的内容。

    sh "oc new-build --name=${applicationName} --image-stream=jboss-eap70-openshift --binary=true --labels=application=${applicationName} -n ${devProject} || true"

    // build image

以上代码根据jboss-eap70-openshift的base image,创建bc

    sh "oc start-build ${applicationName} --from-dir=oc-build --wait=true -n ${devProject}"

以上代码执行构建,即根据上一步指定的base image,加上本地oc-build目录下的内容(ROOT.war),生成应用的镜像。

    // deploy image

    sh "oc new-app ${applicationName}:latest -n ${devProject}"

    sh "oc expose svc/${applicationName} -n ${devProject}"

}

以上代码根据上一步生成的镜像,部署应用,并为应用创建root。


当然,在做maven编译的时候,需要用到pom文件,由于内容较多,不再贴出来,地址:https://github.com/stonezyg/openshift-tasks/blob/master/pom.xml。


方案验证


为了方便理解,将所有操作步骤贴出:


首先,根据yaml文件创建openshift-tasks-jenkins file模板。

#oc create -f https://raw.githubusercontent.com/lbroudoux/openshift-tasks/master/app-template-jenkinsfile.yaml -n ocp-tasks

图片


接下来,通过模板部署jenkins master:

图片

提示输入参数变量,这些参数,就是最终会传到Jenkinsfile的jenkins slave pod中的。这里,我们使用默认参数值。

图片

图片

接下来,在项目中,会部署一个Jenkins的 master pod:

图片

图片

我们可以设置Jenkins Master所指向的slave pod的地址:registry.access.redhat.com/openshift3/jenkins-slave-maven-rhel7



图片


而Pipeline也被创建成功(根据jenkins file中的定义)

接下来,手工触发Pipeline:

图片

接下来,我们关注Jenkins上的日志输出,由于信息较多,我只列出关键内容:

获取代码:

图片

下载maven相关的pom文件:

图片

下载构建需要的jar包:

图片

下载完所需内容以后,进行Build,我们可以看一下build主任务:

图片

Build成功:

图片

接下来进入test阶段,下面内容可以看出,test阶段是调用mvn test的命令:

图片

test成功:

图片

接下来是的devInDev阶段:

图片

在这个阶段,Jenkins会调用openshift的命令,创建bc和dc:

图片

部署应用并为应用创建routes:

图片

截至到目前,pipeline执行完毕,应用也部署成功。


我们将视角切换到Openshift的界面,pipeline已经执行成功。

图片

接下来,我们通过浏览器访问应用的routes:

图片

可以看到应用部署已经成功:

图片


方法总结


此种武器主要利用Jenkins进行代码的构建、应用的部署。对于较为复杂的应用编译,使用此种方法较为合适。另外,很多IT程度较高的客户,在docker大火之前,就已经基于Jenkins实现CI/CD了。这种情况下,如果新引入Openshift平台,使用此方法较可以延续以前的IT运维习惯,学习成本也相对较低(不需要大量修改现有的Jenkins)。


此这种方法的劣势在于对于Slave Pod有一定要求,不同于开发语言,需要使用不同的slave pod。此外,很多时候,我们也需要对slave pod的镜像做一定的定制,如增加一些rpm包等。


标签:tasks,NAME,流程,Devops,APPLICATION,图看,build,openshift,name
来源: https://blog.51cto.com/u_15127570/2714633

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有