前文《wydevops——微服务直上K8S云就是这么简单(续1)》对wydevops核心的架构设计做了大致介绍,再此基础上,本文继续介绍保证wydevops解耦开发语言的另一个环节:项目编译,并简要讲解其如何为不同语言提供独立的、可扩展的编译方法和策略。接着继续借助Java-Sample样例讲解面向项目开发人员的ci-cd-config.yaml文件的作用和配置方法,会涉及以下主题:

  • ci-cd-config.yaml配置文件
  • 发布多端口多服务类型的微服务
  • 一次构建多种架构的镜像
  • 在项目级自定义ConfigMap配置
  • 在项目级自定义参数映射文件

1. 项目编译的语言无关性

        这个特性是依靠语言级的项目编译构建扩展来保证的。也即wydevops为不同语言提供了自定义的项目编译的扩展方法,由各语言自行实现具体的编译。对于Java、go这样平台无关的或可跨平台构建的语言,完全通过本地命令即可完成目标架构类型的编译。而对于C/C++这样需要在目标架构的服务器环境下才能完成构建的语言,wydevops推荐的实现思路是(这个思路也同样适用于Jenkins模式下的异构项目编译):

  • 在异构的目标服务器上安装一个专用于该架构下完成项目编译任务的Docker镜像。
  • wydevops可通过SSH连接运行拉起该Docker镜像的一个容器,让其在内部完成指定项目的源码拉取和编译过程,并将编译输出文件存放到指定的外部挂载目录中。
  • wydevops检测到该Docker镜像的容器运行完毕后,会从指定的输出目录中将编译输出文件复制回本地项目的目录中。

    wydevops后续会推出各开发语言用于不同架构下完成项目编译的Docker镜像(需要付费)。

下面我们实际看看wydevops实现的默认编译流程。如下图:

        在wydevops源码中script/pipeline-stages目录下有5个shell文件。每个文件按名称依次对应一个wydevops的构建阶段。打开build.sh文件即可看到上图的内容,其中标记1的红框主要完成的是加载对应阶段的公共级功能扩展点脚本文件。标记2的红框中是wydevops为build阶段提供的6个功能扩展点,这些扩展点的公共级实现都在红框1中加载的那个脚本文件中实现的。

        我们继续打开script/pipeline-stages/common/build-extend-point.sh文件,内容如下:

当加载这个脚本文件时,首先运行的是

loadExtendScriptFileForLanguage "build"

方法。该方法是个外部方法(约定:不是以下划线开头的方法都是外部方法。),在global-params.sh文件中实现的,内容如下:

        这个方法完成了语言级(参数gLanguage, 传入的值是build)build-extend-point.sh文件的加载。java/build-extend-point.sh文件内容如下:

        继续回到上面common/build-extend-point.sh文件处。可以看到build阶段的6个功能扩展点,公共级只实现了两个:initialGlobalParamsForBuildStage和buildProject(扩展点名称后加"_ex"的方法就是对应扩展点的公共级实现)。initialGlobalParamsForBuildStage方法用于解析全参数配置文件(ci-cd.yaml)文件中build配置节的参数。buildProject方法基本是空的,仅仅设置了全局参数gCurrentStageResult的值。那么Java项目的编译是在哪里调用的呢?

        按照build.sh文件中的功能扩展点的调用顺序,wydevops的调用过程如下

首先,调用onBeforeInitialingGlobalParamsForBuildStage扩展点:invokeExtendPointFunc方法在内存中查找是否存在onBeforeInitialingGlobalParamsForBuildStage_ex(公共级)方法,如果存在则调用之;

接着,如果公共级方法不存在或调用完毕则继续查找是否存在_onBeforeInitialingGlobalParamsForBuildStage_ex(语言级)方法,如果存在则调用之;

最后,如果语言级方法不存在或调用完毕则继续查找项目主模块目录中wydevops/shell目录下是否存在onBeforeInitialingGlobalParamsForBuildStage.sh脚本文件,如果存在则使用source方式加载该文件(加载过程中会执行文件中需要运行的方法)。

  继续调用下一个功能扩展点...

...

按照这个调用过程,wydevops最终会依次调用:

initialGlobalParamsForBuildStage_ex(公共级)——完成配置参数读取解析

_onBeforeProjectBuilding_ex(语言级)——完成Java语言项目多模块项目检测(如果是多模块项目则后续在编译时需要从当前目录回退一级目录后再执行编译),并强制将项目配置文件中的spring.profiles.active参数设置为"prod"。

buildProject_ex(公共级)—— 基本是个空方法,仅为gCurrentStageResult参数(用于向外部发送过程通知)设置了默认值。

_buildProject_ex(语言级)——完成Java语言的编译(如果是多模块项目先依次编译每个子模块,最后编译主模块),并根据结果再次设置CurrentStageResult参数的值。具体代码请查阅源码。

         上述详细说明了功能扩展点调用过程,我们从中可以看到各开发语言具备完全独立的、可自行扩展实现项目的编译过程。这也保证了wydevops对于所有开发语言的编译过程都具备强大的适应性。 

        至此,wydevops语言无关性特性讲解完毕了。

2. ci-cd-config.yaml配置文件介绍

        ci-cd-config.yaml是在实际使用过程中开发人员面对的主要配置文件。该文件首次运行项目中的wydevops-run.sh文件时自动生成的(项目中wydevops目录也是自动生成的)。默认生成的目的有两个:首先,是向项目开发人员暴露公司层面全局设置的开发或测试集群(k8s集群或docker集群)的信息。其次,是便于开发人员通过在该配置文件中定义或覆盖wydevops各种参数的默认值,赋予开发人员对wydevops参数进行调整的能力。

       如上图,左边是早期的带有参数配置过滤机制的设计。该设计在wydevops空间中有一个 _ci-cd-config.yaml配置文件(注意它前面有一个下划线),该文件的内容是_ci-cd-template.yaml文件(全参数配置文件)的子集,其作用是约束开发人员只能修改在_ci-cd-configm.yaml文件中的参数,这可以避免开发人员错误的修改到了应由语言级或公司级配置的参数。但是在实际开发中,发现二次合并yaml的时间代价比较大(也可能是我的笔记本性能不够),后来修改成了上图右边的设计:直接将ci-cd-config.yaml文件中的配置合并到_ci-cd-template.yaml文件中。这样赋予了开发人员全参数定义或覆盖能力,带来了潜在的管理风险,但考虑到敏捷的宗旨,因此仍然进行了这个精简变更。

      在具体项目实践中:

公司层面预定义好各语言开发组使用的服务器集群和持久化存储相关信息(主要是_ci-cd-template.yaml文件中deploy配置节的内容);

各语言开发组的团队leader预定义好组内的项目结构规范、配置文件命名规范、网关路由定义规范等规则后,并按这些规则配置好param-mapping目录下参数映射文件,以及_ci-cd-template.yaml中的相关参数(例如:默认构建类型、默认的构建架构、默认的dockerfile系列文件模板、docker镜像中的workdir目录路径、服务内访问配置文件的路径模板、时区信息等)。

项目开发人员大多数情况下不需要进行配置的修改,少数情况下可能会对构建类型、构建架构进行调整。遇到某具体项目,可能需要通过向ci-cd-config.yaml配置文件添加新的参数和值,最终注入到ci-cd.yaml文件中,然后开发人员在项目中的wydevops/shell目录中提供某个功能扩展点的项目级实现,在该实现中读取注入的新参数并进行相应的操作——这种强大灵活的扩展性是wydevops的架构设计如此优秀带来的福利之一。

        这里就不啰嗦的去介绍_ci-cd-template.yaml文件中的参数了。该文件中每个参数都有注释,请大家自行查看。下面开始讲各种参数配置的应用。

3. 发布多端口多服务类型的微服务

        仍以Java-Sample项目为例,打开该项目下的ci-cd-config.yaml文件,在头部添加globalParams配置节,具体配置如下(推荐去ci-cd.yaml文件中复制粘贴回来再进行修改):

        上图的配置告诉wydevops:服务开放了两个端口(8052,8053),并且为8052端口创建Node Port类型的服务,8053端口发布为ClusterIP类型的服务。containerPorts、servicePorts、nodePorts三个参数是按顺序依次绑定的,也即上述配置分为两组:[8052 8052 30052]、[8053 8053 0],其中0是占位用的,组中servicePorts位置处的端口大于0,则为该端口组的创建ClusterIP类型的服务;如果nodePorts位置上的端口也大于0,则为该组端口创建NodePort类型的服务。

        配置说明完毕,我当前的wydevops-run.sh文件内容如下,使用的是nexus仓库。

       特别说明:改动过ci-cd-config.yaml文件,再次运行wydevops前一定记得先删除ci-cd.yaml文件,否则改动不会生效。

        在wydevops-run.sh文件所在目录中打开git bash窗口,执行:bash wydevops-run.sh

一阵刷屏后,显示如上内容即表示成功完成本次部署。

验证结果:

  • 首先,打开浏览器分别访问:

http://localhost/wydevops/v1/sample/hello

http://localhost:30052/wydevops/v1/sample/hello

均返回下图结果:

  • 其次,在ubuntu on windows命令行中输入:kubectl get service -n develop,  返回如下内容:

        从上图可以看到,如我们所愿,8053端口部署为ClusterIP服务了,8052端口部署为NodePort服务了。

        是不是很简单?很敏捷呀?不要忘记点赞和关注。

4. 一次构建多种架构的镜像

        环境准备:

        打开docker desktop,点settings按钮,在打开的界面中选中Docker Engine,如下图所示:

        需要在其配置中添加:"experimental": true,这可配置允许docker跨平台拉取异构的镜像。

        另外,如上图中第二红框,在其"insecure-registries"参数列表中要把nexus的Docker仓库地址,或是harbor的访问地址添加进去,确保docker能顺利访问这些仓库。

       上面的准备工作完成后,打开项目中的wydevops-run.yaml文件,按照下图修改红框中的配置项:

        上面是在本地工作模式下进行多架构同时构建的的配置方式。如果是在Jenkins工作方式下,要修改项目中的ci-cd-config.yaml文件,按照下图添加红框中的配置项:

       因为在Jenkins工作方式下,gitee等源码仓库的webhook回调中不会设置这些参数,因此wydevops将依据项目源码中ci-cd-config.yaml文件中相关配置进行工作。如果是在Jenkins上通过流水线配置界面启动的wydevops,且流水线中有这两个参数的配置值,此时流水线设置的参数值优先级高于源码配置文件中的参数值。

        上述配置将要求wydevops一次性生成两种架构的Docker镜像和两种架构的离线安装包。

特别说明:改动过ci-cd-config.yaml文件,再次运行wydevops前一定记得先删除ci-cd.yaml文件,否则改动不会生效。

        执行wydevops前先删除项目中wydevops/build-out目录,确保后续该目录下的文件都是最新生成的。然后在wydevops-run.sh文件所在目录中打开git bash窗口,执行:bash wydevops-run.sh

        当成功执行完毕后,我们在项目中wydevops/build-out目录下可以看到如下文件和目录:

      在上图中可以看到,在子目录linux-amd64和linux-arm64中各有一个*.tar文件,这是两种架构的Docker镜像导出文件。build-out目录下的两个*.tar.gz文件是离线安装包文件,这两个安装包文件是java-sample-1.0.0子目录压缩得到的,不同的是安装包中docker子目录下的docker镜像导出文件的架构是不同的。

        wydevops是如何知道目标集群应该部署哪种架构的服务呢?wydevops通过SSH连接检测了目标集群节点的架构类型,在需要的时候会将架构匹配的镜像推送到集群使用的Docker仓库中。

        安装包中的set.conf文件是执行helm install安装服务时可以设置的参数列表(--set)方式。

java-sample项目的set.conf文件内容如下:

       因为java-sample项目配置文件(application.yaml和application-prod.yaml)中没有设置有业务级参数(参数格式为:{{ .Values.* }}),所有这里的参数比较少。一旦项目中定义了业务参数,则wydevops会自动识别并在部署对其进行设置。后续文章中会讲到,这里先提一下。

5. 自定义ConfigMap文件与自定义参数映射

        这里为了演示,我把java-sample项目的pom.xml文件打包服务中自定义名称的ConfigMap中。同时演示在项目级定义参数映射机制。

        前文已经介绍过参数映射文件中有将文件打包到ConfigMap中去的配置。我们将对此进行一次验证。先在项目中的wydevops/param-mapping(不存在则创建之)目录下创建文件:configmap-test.config, 其内容如下:

        如上图,define.bindingFiles配置为:将项目中pom.xml文件打包到K8S集群中名为hello-configmap的ConfigMap资源中。

        将pom.xml文件中的project.properties.cicdName1参数值赋值给globalParams.name参数。

        接下来,我们打开项目的pom.xml文件为其添加参数项:project.properties.cicdName1,添加完毕后内容如下:

        最后,打开项目中ci-cd-config.yaml文件,在其中添加如下图红框的内容,完成将名为hello-configmap的ConfigMap资源挂载到服务容器中指定目录上。        

        

(上图中最后一行的目录/app-single/java-sample/data必须在容器中存在。这里为了演示在wydevops源码中script/templates/docker/java/Dockerfile文件中添加mkdir命令创建了该目录)

配置完毕后,删除项目中的ci-cd.yaml文件,并照旧执行: bash wydevops-run.sh

命令成功执行完毕后,我们在ubuntu on windows命令行窗口中执行:

kubectl get pod -n develop

执行结果如下:

获取到上图中pod的名称,再执行下面命令:

 kubectl describe pod java-sample-9cb9b9bf4-sz7wl -n develop

在执行结果中可以看到如下图红框中的内容:

最后,执行命令:kubectl get cm hello-configmap -o yaml -n develop,执行结果如下:

       至此,验证了java-sample项目成功挂载了名为hello-configmap的ConfigMap资源,并且该ConfigMap资源中可以看到成功装载了pom.xml文件。

        这个例子同时也展示参数映射机制中:目标参数只能被赋值一次的规则。如下图,第二次赋值时被禁止了,wydevops会优先处理项目级的参数映射配置。

        另外,正常情况下,新增自定义ConfigMap的标准配置方式是在ci-cd-config.yaml文件中这样定义:

        直接添加configMaps配置项。wydevops强大的yaml文件合并功能,会完美的将新增的配置项追加到wydevops源码中_ci-cd-templates.yaml配置文件中对应的configMaps配置项中(合并时如果name值相同会覆盖,name值不同则追加)。

        好了,今天就写到这里了。后续将继续讲解构建类型的选择(目前为止所有的例子使用的构建类型都是single)、双镜像打包以及docker阶段的相关内容。原创不易,别忘记了关注点赞呀!

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐