持续集成CI/CD之CD的完整版最佳实践

高斋晓开卷,独共圣人语。这篇文章主要讲述持续集成CI/CD之CD的完整版最佳实践相关的知识,希望能为你提供帮助。
上一章:??持续集成CI& CD之CI的完整版最佳实践??
CI& CD解读概述
CI/CD 是一种通过在应用开发阶段引入自动化来频繁向客户交付应用的方法。CI/CD 的核心概念是持续集成、持续交付和持续部署。作为一个面向开发和运营团队的解决方案,CI/CD 主要针对在集成新代码时所引发的问题(亦称:"集成地狱")。
具体而言,CI/CD 可让持续自动化和持续监控贯穿于应用的整个生命周期(从集成和测试阶段,到交付和部署)。这些关联的事务通常被统称为"CI/CD 管道",由开发和运维团队以敏捷方式协同支持。
CI 是什么?CI 和 CD 有什么区别?
缩略词 CI / CD 具有几个不同的含义。CI/CD 中的"CI"始终指持续集成,它属于开发人员的自动化流程。成功的 CI 意味着应用代码的新更改会定期构建、测试并合并到共享存储库中。该解决方案可以解决在一次开发中有太多应用分支,从而导致相互冲突的问题。
【持续集成CI/CD之CD的完整版最佳实践】CI/CD 中的"CD"指的是持续交付和/或持续部署,这些相关概念有时会交叉使用。两者都事关管道后续阶段的自动化,但它们有时也会单独使用,用于说明自动化程度。
持续*交付*通常是指开发人员对应用的更改会自动进行错误测试并上传到存储库(如 GitHub 或容器注册表),然后由运维团队将其部署到实时生产环境中。这旨在解决开发和运维团队之间可见性及沟通较差的问题。因此,持续交付的目的就是确保尽可能减少部署新代码时所需的工作量。
持续*部署*(另一种"CD")指的是自动将开发人员的更改从存储库发布到生产环境,以供客户使用。它主要为了解决因手动流程降低应用交付速度,从而使运维团队超负荷的问题。持续部署以持续交付的优势为根基,实现了管道后续阶段的自动化。



CI/CD 既可能仅指持续集成和持续交付构成的关联环节,也可以指持续集成、持续交付和持续部署这三项构成的关联环节。更为复杂的是,有时"持续交付"也包含了持续部署流程。
归根结底,我们没必要纠结于这些语义,您只需记得 CI/CD 其实就是一个流程(通常形象地表述为管道),用于实现应用开发中的高度持续自动化和持续监控。因案例而异,该术语的具体含义取决于 CI/CD 管道的自动化程度。许多企业最开始先添加 CI,然后逐步实现交付和部署的自动化(例如作为云原生应用的一部分)。
CI 持续集成(Continuous Integration)
现代应用开发的目标是让多位开发人员同时处理同一应用的不同功能。但是,如果企业安排在一天内将所有分支源代码合并在一起(称为"合并日"),最终可能造成工作繁琐、耗时,而且需要手动完成。这是因为当一位独立工作的开发人员对应用进行更改时,有可能会与其他开发人员同时进行的更改发生冲突。如果每个开发人员都自定义自己的本地集成开发环境(IDE),而不是让团队就一个基于云的 IDE 达成一致,那么就会让问题更加雪上加霜。
持续集成(CI)可以帮助开发人员更加频繁地(有时甚至每天)将代码更改合并到共享分支或"主干"中。一旦开发人员对应用所做的更改被合并,系统就会通过自动构建应用并运行不同级别的自动化测试(通常是单元测试和集成测试)来验证这些更改,确保这些更改没有对应用造成破坏。这意味着测试内容涵盖了从类和函数到构成整个应用的不同模块。如果自动化测试发现新代码和现有代码之间存在冲突,CI 可以更加轻松地快速修复这些错误。
CD 持续交付(Continuous Delivery)
完成 CI 中构建及单元测试和集成测试的自动化流程后,持续交付可自动将已验证的代码发布到存储库。为了实现高效的持续交付流程,务必要确保 CI 已内置于开发管道。持续交付的目标是拥有一个可随时部署到生产环境的代码库。
在持续交付中,每个阶段(从代码更改的合并,到生产就绪型构建版本的交付)都涉及测试自动化和代码发布自动化。在流程结束时,运维团队可以快速、轻松地将应用部署到生产环境中。
CD 持续部署(Continuous Deployment)
对于一个成熟的 CI/CD 管道来说,最后的阶段是持续部署。作为持续交付——自动将生产就绪型构建版本发布到代码存储库——的延伸,持续部署可以自动将应用发布到生产环境。由于在生产之前的管道阶段没有手动门控,因此持续部署在很大程度上都得依赖精心设计的测试自动化。
实际上,持续部署意味着开发人员对应用的更改在编写后的几分钟内就能生效(假设它通过了自动化测试)。这更加便于持续接收和整合用户反馈。总而言之,所有这些 CI/CD 的关联步骤都有助于降低应用的部署风险,因此更便于以小件的方式(而非一次性)发布对应用的更改。不过,由于还需要编写自动化测试以适应 CI/CD 管道中的各种测试和发布阶段,因此前期投资还是会很大。
CI& CD集成流程架构流程设计



(1)制品库制作;(2)提交部署应用与版本;(3)选择应用部署;(4)查看应用情况;
gitlab-ci构建制品库
制作制品库,使用了gitlab自带的CI/CD,代码编译与镜像制作都使用容器环境构建。
java制品库模板本模板所有编译都采用容器环境,适用于父子结构的java工程;工程结构如下

父工程
|---  子模块1    #  java子模块
|------  docker文件夹  #  存放部署文件
|---------  Dockerfile
|---------  Jenkinsfile
|---------  k8s.yaml
|------  src
...
|---  子模块2
|------  docker文件夹
|---------  Dockerfile
|---------  Jenkinsfile
|---------  k8s.yaml
|------  src
...
|---  .gitlab-ci.yml


运行CI之前,需要在代码库组的CI/CD参数中需要设置??CI_REGISTRY???:docker仓库地址;??CI_REGISTRY_USER???:docker仓库账号; ??CI_REGISTRY_PASSWORD???:docker仓库密码;??CI_NAME_SPACE???:镜像的仓库路径[项目名称空间];??CI_MAVEN_REPO???:maven本地仓库路径;??CI_SETTING??文件类型maven的setting.xml
参数说明 
??MODULES??:是子模块列表以“,”隔开
???MODULE_PREFIX??:用于更正子模块名称不带前缀情况。
#  参考文档:https://docs.gitlab.com/ee/ci/yaml/index.html
#  需要gitlab需要配置如下参数:
#  CI_REGISTRY:docker仓库地址,    CI_REGISTRY_USER:docker仓库账号,    CI_REGISTRY_PASSWORD:docker仓库密码,
#  CI_NAME_SPACE:镜像的仓库路径[项目名称空间],  CI_MAVEN_REPO:maven本地仓库路径,CI_SETTING:文件类型maven的setting.xml
#  java工程只需要修改此模板的variables中的MODULES与MODULE_PREFIX的参数
variables:
    IMAGE_PRE:  $CI_REGISTRY/$CI_NAME_SPACE
    MAVEN_OPTS:  "-Dmaven.repo.local=$CI_MAVEN_REPO"
    #打包多模块镜像以,隔开,eg:soeasy-clm-open,soeasy-clm-message/soeasy-clm-message-server
    MODULES:  $MODULE1,$MODULE2,...,$MODULEn
    MODULE_PREFIX:  $MODULE_PREFIX    #模块前缀

#  全局缓存jar文件
cache:  & global_cache
    paths:
        -  ./$MODULES/target/*.jar
        -  ./$MODULES/**/target/*.jar
    when:  on_success

stages:
    -  java-build
    -  docker-build

job_build_tag_java:
    image:  maven:3.5-jdk-8-alpine
    only:
        -  tags
    stage:  java-build
    #  配置仅仅上传全局jar缓存
    cache:
        < < :  *global_cache
        policy:  push
    script:
        -  cat  "$CI_SETTING"  >   ci_settings.xml
        -  mvn  -version  & &   mvn  clean  package  -pl  $MODULES  -am  -Dmaven.test.skip=true  -s  ci_settings.xml

job_build_tag_docker:
    image:  ming19871211/docker:latest
    only:
        -  tags
    stage:  docker-build
    services:
        -  docker:dind
    #  配置仅仅下载全局缓存
    cache:
        < < :  *global_cache
        policy:  pull
    before_script:
        -  docker  login  $CI_REGISTRY  --username  $CI_REGISTRY_USER  --password  $CI_REGISTRY_PASSWORD
        -  |  #  定义应用版本号
            app_version=$CI_COMMIT_TAG
            if  [  -z  "$app_version"  ];   then
                app_version=$CI_COMMIT_SHORT_SHA
            fi
            export  app_version
    script:
        -  echo  "开始打包docker镜像"
        -  |  #  切割模块,遍历模块
            OLD_IFS="$IFS"
            IFS=","
            module_arr=($MODULES)
            IFS=$OLD_IFS
            for  module  in  $module_arr[@]
            do
                mv  $module/target  $module/docker/
                target_jar_name=$(ls  $module/docker/target/*.jar)  #获取jar路径
                target_jar_name=$target_jar_name##*/  #去掉文件前缀
                module_std=$target_jar_name%.jar  #去掉.jar后缀
                module_std=$module_std%-[0-9].[0-9]*  #去掉maven版本号
                #  解决打包名称不按正规方式命名
                if  [[  !  $module_std  ==  $MODULE_PREFIX*  ]];   then
                    module_std=$module##*/
                fi
                if  [[  !  $module_std  ==  $MODULE_PREFIX*  ]];   then
                    module_std="$MODULE_PREFIX-$module_std"
                fi
                docker  build  -t  $IMAGE_PRE/$module_std:$app_version  --build-arg  JAR_FILE=$target_jar_name  $module/docker
                docker  push  $IMAGE_PRE/$module_std:$app_version
                docker  rmi  $IMAGE_PRE/$module_std:$app_version
            done


运行结果如图



vue制品库模板本模板所有编译都采用容器环境,适用于vue工程;工程结构如下
|---  docker文件夹  #  存放部署文件
|------  Dockerfile
|------  Jenkinsfile
|------  k8s.yaml
|------  ...  #  根据项目需求增加其它处理脚本,如docker启动脚本、初始化配置等等
|---  public
|---  src
|---  vue相关文件
...
|---  .gitlab-ci.yml


运行CI之前,需要在代码库组的CI/CD参数中需要设置??CI_REGISTRY???:docker仓库地址;??CI_REGISTRY_USER???:docker仓库账号; ??CI_REGISTRY_PASSWORD???:docker仓库密码;??CI_NAME_SPACE??:镜像的仓库路径[项目名称空间];
#  参考文档:https://docs.gitlab.com/ee/ci/yaml/index.html
#  需要配置如下参数:
#  CI_REGISTRY:docker仓库地址,    CI_REGISTRY_USER:docker仓库账号,    CI_REGISTRY_PASSWORD:docker仓库密码,
#  CI_NAME_SPACE:镜像的仓库路径[项目所属空间],  若$CI_PROJECT_NAME命名不规范,则手动修改
variables:
    IMAGE:  $CI_REGISTRY/$CI_NAME_SPACE/$CI_PROJECT_NAME
   
#  全局缓存jar文件
cache:  & global_cache
    paths:
        -  node_modules/
        -  dist/
    when:  on_success

stages:
    -  vue-build
    -  docker-build

job_build_tag_vue:
    image:  node:12
    only:
        -  tags
    stage:  vue-build
    #  配置仅仅上传全局node缓存
    cache:
        < < :  *global_cache
        policy:  push
    script:
        -  npm  -v  & &   node  -v  & &   npm  config  set  registry  https://registry.npm.taobao.org  & &   npm  install  & &   npm  run  build 

job_build_tag_docker:
    image:  docker:latest
    only:
        -  tags
    stage:  docker-build
    services:
        -  docker:dind
    #  配置仅仅下载全局缓存
    cache:
        < < :  *global_cache
        policy:  pull
    before_script:
        -  docker  login  $CI_REGISTRY  --username  $CI_REGISTRY_USER  --password  $CI_REGISTRY_PASSWORD
        -  |  #  定义应用版本号
            app_version=$CI_COMMIT_TAG
            if  [  -z  "$app_version"  ];   then
                app_version=$CI_COMMIT_SHORT_SHA
            fi
            export  app_version
    script:
        -  echo  "开始打包docker镜像"
        -  rm  -rf  docker/dist  & &   mv  dist  docker/
        -  docker  build  -t  $IMAGE:$app_version  docker
        -  docker  push  $IMAGE:$app_version
        -  docker  rmi  $IMAGE:$app_version


运行结果如图

应用部署列表与版本跟踪
因为需要发布到生产环境,需要跟踪发布的过程,本实践采用git来跟踪脚本。
本jenkins部署脚本时将成品的docker镜像,通过jenkins直接发布到k8s环境测试或者生产环境。使用git地址存储编写的jenkinsfile脚本,利用git与jenkins自身的功能完成发版的可追溯、可回滚等等。
采用jenkins-pipeline的声明式部署,部署都使用容器化,不依赖主机。相关的文件都使用jenkins系统变量、凭证配置。部署发版的工程结构如下
|---  yaml    #存放k8s部署的yaml文件模块
|---  version-app.sh  #定义部署应用的列表,版本等等
|---  Jenkinsfile  #定义jenkins部署脚本


部署yaml文件模板部分参数占位符说明:??__NAME_SPACE__??:部署空间占位符;
??__DOMAIN_NAME__??:部署应用名称占位符;
??__REPLICAS_NUM__??:部署实例数量占位符;
??__DOCKER_IMAGE__??:docker镜像地址占位符;
java部署模板k8s-java.yaml
apiVersion:  v1
kind:  Namespace
metadata:
    name:  __NAME_SPACE__
    labels:
        name:  __NAME_SPACE__
---
apiVersion:  v1
kind:  Service
metadata:
    name:  __DOMAIN_NAME__
    namespace:  __NAME_SPACE__
spec:
    ports:
    -  name:  app-port
        port:  __CONTAINER_PORT__
        targetPort:  __CONTAINER_PORT__
        protocol:  TCP
    #  当开启管理端口时,外部应用需要访问时打开此注释
    #  -  name:  manage-port
    #      port:  __MANAGE_PORT__
    #      targetPort:  __MANAGE_PORT__
    #      protocol:  TCP
    selector:
        app:  __DOMAIN_NAME__
---
apiVersion:  apps/v1
kind:  Deployment
metadata:
    name:  __DOMAIN_NAME__
    namespace:  __NAME_SPACE__
spec:
    selector:
        matchLabels:
            app:  __DOMAIN_NAME__
    replicas:  __REPLICAS_NUM__
    template:
        metadata:
            labels:
                app:  __DOMAIN_NAME__
        spec:
            initContainers:
            -  name:  init-agent-sidecar
                image:  ming19871211/skywalking-agent:__SKYWALKING_VESION__
                command:
                -  sh
                -  -c
                -  set  -ex; cp  -r  /skywalking/agent/*  /usr/skywalking/agent;
                volumeMounts:
                -  name:  agent
                    mountPath:  /usr/skywalking/agent
            containers:
            -  name:  __DOMAIN_NAME__
                image:  __DOCKER_IMAGE__
                imagePullPolicy:  IfNotPresent  #本地存在就不到远程拉取镜像
                env:  #环境变量设置
                -  name:  TZ
                    value:  Asia/Shanghai
                -  name:  NACOS_NAMESPACE
                    value:  __NACOS_NAMESPACE__
                -  name:  DEPLOY_ENV    #  兼容性配置,后续版本建议删除
                    value:  __NACOS_NAMESPACE__
                -  name:  NACOS_GROUP
                    value:  __NACOS_GROUP__
                -  name:  JAVA_OPTS
                    value:  "__JAVA_OPTS__"
                -  name:  CONTAINER_PORT
                    value:  "__CONTAINER_PORT__"
                -  name:  MANAGE_PORT
                    value:  "__MANAGE_PORT__"
                -  name:  NACOS_URL
                    value:  __NACOS_URL__
                -  name:  DOMAIN_NAME
                    value:  __DOMAIN_NAME__.__NAME_SPACE__
                #  -  name:  DOMAIN_NAME
                #      valueFrom:
                #          fieldRef:
                #              apiVersion:  v1
                #              fieldPath:  status.podIP
                envFrom:
                -  secretRef:
                        name:  __NACOS_AUTH__
                resources:  #资源限制
                    requests:
                        memory:  "128Mi"
                        cpu:  "200m"  #最低需要  0.1个cpu
                    limits:
                        memory:  "__LIMIT_MEMORY__Mi"
                        cpu:  "2000m"
                ports:
                -  containerPort:  __CONTAINER_PORT__
                    name:  app-port
                    protocol:  TCP
                -  containerPort:  __MANAGE_PORT__
                    name:  manage-port
                    protocol:  TCP
                readinessProbe:  #就绪探针
                    httpGet:
                    #    path:  __APP_MANAGE_PATH__/actuator/health/readiness
                    #    port:  __MANAGE_PORT__
                    tcpSocket:
                        port:  __CONTAINER_PORT__
                    initialDelaySeconds:  60
                    periodSeconds:  15
                    timeoutSeconds:  5
                livenessProbe:  #健康检查
                #    httpGet:
                #        path:  __APP_MANAGE_PATH__/actuator/health/liveness
                #        port:  __MANAGE_PORT__
                    tcpSocket:
                        port:  __CONTAINER_PORT__
                    initialDelaySeconds:  60
                    periodSeconds:  15
                    timeoutSeconds:  5
                volumeMounts:
                -  name:  time-config
                    mountPath:  /etc/localtime
                    readOnly:  true
                -  name:  agent
                    mountPath:  /usr/skywalking/agent
                #  增加挂载
                #  -  name:  [PVC_NAME_ALIAS]  #  pod挂载别称
                #      mountPath:  [POD_MOUNT_PATH]  #  pods内挂载路径
                #      subPath:  [PVC_MOUNT_SUBPATH]  #    pvc挂载盘中的子路径,注释这一项标识挂载根路径下
            imagePullSecrets:
            -  name:  __DOCKER_REGISTRY_SECRET__
            nodeSelector:
                isTest:  "true"
            volumes:
            -  name:  time-config
                hostPath:
                    path:  /etc/localtime
            -  name:  agent
                emptyDir: 
            #  增加挂载
            #  -  name:  [PVC_NAME_ALIAS]  #  pod挂载别称
            #      persistentVolumeClaim:
            #          claimName:  [PVC_NAME]  #  对应指定的pvc名称


vue部署模板k8s-vue.yaml
apiVersion:  v1
kind:  Namespace
metadata:
    name:  __NAME_SPACE__
    labels:
        name:  __NAME_SPACE__
---
apiVersion:  v1
kind:  Service
metadata:
    name:  __DOMAIN_NAME__
    namespace:  __NAME_SPACE__
spec:
    ports:
    -  name:  app-port
        port:  80
        targetPort:  80
        protocol:  TCP
    selector:
        app:  __DOMAIN_NAME__
---
apiVersion:  apps/v1   
kind:  Deployment
metadata:
    name:  __DOMAIN_NAME__
    namespace:  __NAME_SPACE__
spec:
    selector:
        matchLabels:
            app:  __DOMAIN_NAME__
    replicas:  __REPLICAS_NUM__ 
    template: 
        metadata:
            labels:
                app:  __DOMAIN_NAME__
        spec:
            initContainers:
            -  name:  init-env-sidecar
                image:  busybox:latest
                command:  [  "sh",  "-c"]
                args:
                -  set  -ex;
                    CONFIG_FILE=$CONFIG_FILE:-"vue-comm.properties";
                    SYS_GLOBAL_CONFIG=$SYS_GLOBAL_CONFIG:-"sys-global-config.properties";
                    wget  --post-data="https://www.songbingjia.com/android/username=$NACOS_USR& password=$NACOS_PWD"  -S  "$NACOS_URL/nacos/v1/auth/users/login"  -O  login-token;
                    access_token=$(grep    -Eo  "accessToken":"([^"]*)"  login-token  |awk  -F  \\":\\"  print  $2);
                    access_token=$access_token/\\"/;
                    rm  -f  /init-env/env.conf;
                    rm  -f  /init-env/env-sys.conf;
                    wget  "$NACOS_URL/nacos/v1/cs/configs?dataId=$CONFIG_FILE& group=$NACOS_GROUP& tenant=$NACOS_NAMESPACE& accessToken=$access_token"  -O    /init-env/env.conf;
                    wget  "$NACOS_URL/nacos/v1/cs/configs?dataId=$SYS_GLOBAL_CONFIG& group=$NACOS_GROUP& tenant=$NACOS_NAMESPACE& accessToken=$access_token"  -O    /init-env/env-sys.conf  ||  return  0;
                    if  [    $?  -eq  0  -a  -f  "/init-env/env-sys.conf"  ];   then
                        echo  -e    "\\n"  > >     /init-env/env.conf;
                        cat  /init-env/env-sys.conf  > >   /init-env/env.conf;
                    fi
                env:  #环境变量设置
                -  name:  NACOS_NAMESPACE
                    value:  __NACOS_NAMESPACE__
                -  name:  NACOS_GROUP
                    value:  __NACOS_GROUP__
                -  name:  SYS_GLOBAL_CONFIG
                    value:  __SYS_GLOBAL_CONFIG__
                -  name:  CONFIG_FILE
                    value:  __CONFIG_FILE__
                -  name:  NACOS_URL
                    value:  __NACOS_URL__
                envFrom:
                -  secretRef:
                        name:  __NACOS_AUTH__
                volumeMounts:
                -  name:  init-env
                    mountPath:  /init-env/
            containers:
            -  name:  __DOMAIN_NAME__
                image:  __DOCKER_IMAGE__
                imagePullPolicy:  IfNotPresent  #本地存在就不到远程拉取镜像
                env:  #环境变量设置
                -  name:  TZ
                    value:  Asia/Shanghai
                -  name:  DOMAIN_NAME
                    value:  __DOMAIN_NAME__.__NAME_SPACE__
                resources:  #资源限制
                    requests:
                        memory:  "128Mi"
                        cpu:  "200m"  #最低需要  0.1个cpu
                    limits:
                        memory:  "__LIMIT_MEMORY__Mi"
                        cpu:  "2000m"
                ports:
                -  containerPort:  80
                readinessProbe:  #就绪探针
                #    httpGet:
                #        path:  /index.html
                #        port:  80
                    tcpSocket:
                        port:  80
                    initialDelaySeconds:  30
                    periodSeconds:  15
                    timeoutSeconds:  5
                livenessProbe:  #健康检查
                #    httpGet:
                #        path:  /index.html
                #        port:  80
                    tcpSocket:
                        port:  80
                    initialDelaySeconds:  30
                    periodSeconds:  15
                    timeoutSeconds:  5
                volumeMounts:
                -  name:  time-config
                    mountPath:  /etc/localtime
                    readOnly:  true
                -  name:  init-env
                    mountPath:  /init-env/
            imagePullSecrets:
            -  name:  __DOCKER_REGISTRY_SECRET__
            nodeSelector:
                isTest:  "true"
            volumes:
            -  name:  time-config
                hostPath:
                    path:  /etc/localtime
            -  name:  init-env
                emptyDir: 


版本定义文件version-app.sh定义部署应用的列表、版本、实例、内存使用、应用类型等等可以操作以下案例定义
#合同应用-后端
export  SOEASY_CLM="alpha1.0"
export  SOEASY_CLM_AI="$SOEASY_CLM"
export  SOEASY_CLM_ARCHIVE="$SOEASY_CLM"
export  SOEASY_CLM_CONTRACT="$SOEASY_CLM"
export  SOEASY_CLM_DATA="https://www.songbingjia.com/android/$SOEASY_CLM"
export  SOEASY_CLM_FILE="$SOEASY_CLM"
export  SOEASY_CLM_FORM="$SOEASY_CLM"
export  SOEASY_CLM_LOG="$SOEASY_CLM"
export  SOEASY_CLM_MESSAGE="$SOEASY_CLM"
export  SOEASY_CLM_SEARCH="$SOEASY_CLM"
export  SOEASY_CLM_WORKFLOW="$SOEASY_CLM"
#合同-前端
export  SOEASY_CLM_UI="alpha1.0"
export  SOEASY_FRONTEND_ADMIN="alpha1.0"

#部署应用参数定义,可选参数以:为分隔符,可选参数可以为空-表示此位置的值为默认值
#eg:[应用名]:[版本号]:[可选:实例数量,默认1]:[可选:工程类型,默认java]:[可选:内存限制大小默认单位M]:[可选:挂载路径]
#内存限制  java默认:2048  vue默认:1024
#挂载路径  挂载pvc名称|容器应用内部地址  ,注意此参数暂无实现,等待有需求再实现
APP_SERVERS="""
"soeasy-clm-ai-server:$SOEASY_CLM_AI"
"soeasy-clm-archive-server:$SOEASY_CLM_ARCHIVE"
"soeasy-clm-contract-server:$SOEASY_CLM_CONTRACT"
"soeasy-clm-data-server:$SOEASY_CLM_DATA"
"soeasy-clm-file-server:$SOEASY_CLM_FILE"
"soeasy-clm-form-server:$SOEASY_CLM_FORM"
"soeasy-clm-log-server:$SOEASY_CLM_LOG"
"soeasy-clm-message-server:$SOEASY_CLM_MESSAGE"
"soeasy-clm-search-server:$SOEASY_CLM_SEARCH"
"soeasy-clm-workflow-server:$SOEASY_CLM_WORKFLOW"
"soeasy-clm-ui:$SOEASY_CLM_UI::vue"
"soeasy-frontend-admin:$SOEASY_FRONTEND_ADMIN::vue"
"""
echo  $APP_SERVERS


Jenkins部署文件本文件以部署到k8s为例,只有一个步骤。
pipeline 
        /*
        ##  系统全局配置  ##
        1.配置docker仓库相关变量  系统环境变量:DOCKER_REGISTRY_ADDR  [docker仓库地址]
        credentials-[Username  with  password]类型:jenkins-docker-registry-creds[docker仓库账号/docker仓库密码]
        2.配置nacos相关变量  定义账号密码对应下面的NACOS_URL
        credentials-[Username  with  password]类型:jenkins-nacos-cd-creds[nacos登录账号/nacos登录密码]
        3.配置k8s相关变量  credentials-[Secret  file]类型:  jenkins-k8s-cd-config[k8s集群访问凭证文件]
        ##  k8s部署环境要求  ##
        在部署节点上增加isTest=true的标签
              nodeSelector:
                isTest:  "true"
        ##  项目任务配置  ##
        配置环境变量:SKYWALKING_BACKEND_SERVICE  SKYWALKING_VERSION=7.0.0  IS_SKYWALKING=true
        编写语法参考:http://groovy-lang.org/semantics.html
        */
        //  如果指定具体的节点执行,请  agent    label  docker-slave 
        agent  any
        options 
                //超时一小时
                timeout(time:  1,  unit:  HOURS)
                //不允许同时执行
                disableConcurrentBuilds()
       
//  #######################需要修改的区域  开始#################################
        environment 
                //  表示java前端应用限制内存大小,单位为M,只能为数字;
                JAVA_LIMIT_MEMORY=2048
                //  表示vue前端应用限制内存大小,单位为M,只能为数字;
                VUE_LIMIT_MEMORY=1024
                //  nacos配置中心配置文件名称(dataId)
                CONFIG_FILE="clm-vue-comm.properties"
                //  nacos配置中心配置文件名称(dataId)  系统全局配置
                SYS_GLOBAL_CONFIG="clm-sys.properties"
                //  docker仓库地址,一般与系统环境变量相同,若相同时手动修改
                DOCKER_REGISTRY_ADDR="$env.DOCKER_REGISTRY_ADDR"
                //  docker仓库账号密码--对应系统环境变量DOCKER_REGISTRY_ADDR
                DOCKER_REGISTRY=credentials(jenkins-docker-registry-creds)
                //  注册中心域名,默认是nacos  一般不需要修改
                NACOS_URL=nacos-headless.talkweb:8848
                //  nacos凭证-对应NACOS_URL
                NACOS_CREDS=credentials(jenkins-nacos-cd-creds)
                //  k8s版本号
                K8S_VERSION=v1.19.16
                //  K8s配置文件路径
                K8S_CONFIG=credentials(jenkins-k8s-cd-config)
                //  k8s中nacos账号密码存储的secret名称
                K8S_NACOS_AUTH="nacos-auth"
                //  k8s中docker仓库信息存储的secret名称
                K8S_DOCKER_REGISTRY="hub-local"
                //  根据需求,xms、xmm已经自动添加  此处不用添加
                //JAVA_OPTS="-Dspring.XXX=XXX  "
       
        parameters 
                //  修改部署的域名空间
                string(name:name_space,  defaultValue:  "soeasy-clm-test",  description:  发布的命名空间,一般区分应用类)
                //  镜像空间
                choice(name:  image_namespace,  choices:  [soeasy-clm],  description:  nacos命名空间)
                //  若只使用talkweb-school空间,不需修改,否则需把空间名称列表写入choices中
                choice(name:  nacos_namespace,  choices:  [soeasy-clm-test],  description:  nacos命名空间)
                //  nacos组
                choice(name:  nacos_group,  choices:  [DEFAULT_GROUP],  description:  nacos组名称)
                /** 
                ######  active  choices联动参数  ######
                1.名称:project,类型:active  choices  parameter 
                Groovy脚本:return  ["梧桐应用","合同应用"]
                2.名称:modules,类型:Active  Choices  Reactive  parameters
                Referenced  parameters:project, 
                Choice  Type:Check  Boxes
                Groovy脚本:
                wutong_servers  =  ["wutong-mse-gateway","wutong-mse-dictionary-server",
                "wutong-idaas-account-server","wutong-idaas-application-server",
                "wutong-idaas-audit-server","wutong-idaas-auth-server","wutong-idaas-vue3"]
                clm_servers  =  []
                if  (project.equals("梧桐应用")) 
                    return  wutong_servers
                else  if  (project.equals("合同应用")) 
                    return  edu_res
                else
                    return  []
    &

    推荐阅读