前面我们介绍了使用 Zadig 交付一个非常简单的应用示例,接下来我们来介绍下微服务项目如何在 Zadig 下进行交付。
微服务示例
我们这里使用到开源项目是 https://github.com/GoogleCloudPlatform/microservices-demo,该开源项目名叫 Online Boutique(https://onlineboutique.dev/),是一个云原生微服务演示应用程序,其中包含 11 个微服务,该应用程序是一个基于 Web 的电子商务应用程序,用户可以在其中浏览商品、将它们添加到购物车并购买它们。
基于该项目针对 Zadig 做了优化修改,项目地址:https://github.com/cnych/microservices-demo
该项目由 11 个使用不同语言编写的微服务组成,它们通过 gRPC 相互通信。架构如下所示。
微服务架构
每个服务的功能描述如下表所示。
服务功能
Zadig 项目
接下来我们来使用 Zadig 来交付该微服务项目,使用方式和前面基本类似。
首先新建一个名为 microservices-demo 的项目,项目类型为 K8s YAML 项目。
新建项目
点击立即新建按钮,然后进入项目初始化页面。
项目初始化
点击下一步进入到服务配置页面,我们知道服务模板可以通过手动创建、代码仓库中同步或者现有 K8s 资源中导入而来。我们这里服务模板在代码仓库中,所以选择从代码库中进行同步,选择对应的代码仓库、分支和对应的资源清单目录,然后点击同步按钮即可将对应的服务同步到 Zadig 中来。
同步服务
可以看到我们这里同步过来后包含了 12 个服务,每个服务的模板也都直接展示出来了,但是由于是通过仓库同步的,模板是只读模式,右侧会自动读取到服务对应的镜像信息。
注意:Zadig 读取资源清单后,会以 K8s YAML 中的容器名作为唯一的 key 进行去重,所以在编写 K8s YAML 的时候不要让容器名重复,否则导入后会丢失服务。
服务模板
点击右侧读取到的镜像服务组件后面的添加构建按钮,前往配置该服务的镜像是如何进行构建的。
首先需要添加服务代码源信息,我们这里的代码在 GitLab 上面,所以添加对应的代码仓库以及分支信息。我们这里的所有服务代码都位于代码仓库根目录下面的 src 目录下。
代码结构
这属于典型的 Monorepo 类型的仓库(单体),而里面的每个服务我们也并未配置成 submodule,所以每个服务构建的时候均要将整个代码仓库 Clone 下来,但其实我们只需要其中的一个服务即可,Git 是支持这种操作的,比如我们现在只想要获取 adservice 这个服务的数据,可以通过下面的方式来获取。
$ mkdir microservices-demo && cd microservices-demo
$ git init
$ git remote add origin git .k8s.local:course/microservices-demo.git
$ git config core.sparsecheckout true
$ git sparse-checkout set "src/adservice"
$ git pull --depth 1 origin main
remote: Enumerating objects: 307, done.
remote: Counting objects: 100% (307/307), done.
remote: Compressing objects: 100% (234/234), done.
remote: Total 307 (delta 72), reused 185 (delta 39), pack-reused 0
Receiving objects: 100% (307/307), 9.55 MiB | 5.28 MiB/s, done.
Resolving deltas: 100% (72/72), done.
From git.k8s.local:course/microservices-demo
* branch main -> FETCH_HEAD
* [new branch] main -> origin/main
$ ls -la src
total 0
drwxr-xr-x 3 cnych staff 96 Jul 15 14:10 .
drwxr-xr-x 4 cnych staff 128 Jul 15 14:10 ..
drwxr-xr-x 12 cnych staff 384 Jul 15 14:10 adservice
通过上面的方式可以只获取指定目录的代码,但是遗憾的是 Zadig 目前并不支持该功能,或许后续会支持吧!
代码源配置后,最主要的是添加通用构建脚本。
构建服务
我们这里其实就是配置如何构建镜像,对应的脚本如下所示:
#!/bin/bash
set -e
cd $WORKSPACE/$REPONAME_0/src/adservice
docker build -t $IMAGE -f Dockerfile .
docker push $IMAGE
首先需要进入到当前服务的代码根目录下面,我们这里使用的是 cd $WORKSPACE/$REPONAME_0/src/adservice 命令,其中的 $WORKSPACE、$REPONAME_0、$IMAGE 均为内置的构建变量,$WORKSPACE 表示工作根目录,而 $REPONAME_0 表示配置的第一个代码仓库的名称,也就是 microservices-demo。
构建变量
进入到服务根目录下面后,我们只需要执行 docker build 命令构建镜像即可,每个服务的根目录下面均配置了 Dockerfile 文件,构建的镜像使用变量 $IMAGE 代替,会使用添加的默认的镜像仓库。
默认的镜像命名规则如下所示,我们也可以自行定制。
镜像命令规则
构建配置完过后,记得保存构建,用同样的方式配置所有服务的构建。
服务配置完成后下一步开始加入环境,同样默认情况下会自动创建一套 dev 和 qa 的环境以及 3 条工作流。
加入环境
加入环境后就可以看到对应的 3 条工作流了,点击完成即可。
工作流
执行工作流
这样项目就创建成功了,现在我们先在 dev 环境来运行工作流。点击执行工作流,在服务中可以选择我们要构建的服务,可以选择一个也可以选择多个服务。
执行任务
同样任务执行后会执行配置的通用脚本,然后将对应的服务部署到 K8s 集群中去。
任务详情
将所有的服务执行完成后在环境页面可以看到所有服务的状态和最新镜像信息。
dev环境
每个服务都正常部署到 dev 环境后,查看对应的 Pod 状态:
$ kubectl get pods -n microservices-demo-env-dev
NAME READY STATUS RESTARTS AGE
adservice-5b5b97cf59-b7d6g 1/1 Running 0 21m
cartservice-7d66bd5c4-wxd6v 1/1 Running 0 15m
checkoutservice-6dbc8cdc46-fqrnx 1/1 Running 0 14m
currencyservice-54fccf7b9f-c29h5 1/1 Running 0 13m
emailservice-844b6c9b58-j5smc 1/1 Running 0 13m
frontend-649699cc5-s5ggp 1/1 Running 0 12m
loadgenerator-565cdbb5dc-6dtrb 1/1 Running 0 5m42s
paymentservice-fd8f95f79-4889n 1/1 Running 0 11m
productcatalogservice-775db476b6-l4s2t 1/1 Running 0 6m47s
recommendationservice-79f558bc9b-jx69n 1/1 Running 0 6m47s
redis-cart-f9bdd7959-qtc9n 1/1 Running 0 34m
shippingservice-f789c4494-ktbnz 1/1 Running 0 6m43s
$ kubectl get svc -n microservices-demo-env-dev
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
adservice ClusterIP 10.96.40.23 <none> 9555/TCP 41m
cartservice ClusterIP 10.110.0.136 <none> 7070/TCP 41m
checkoutservice ClusterIP 10.109.209.29 <none> 5050/TCP 41m
currencyservice ClusterIP 10.98.43.229 <none> 7000/TCP 41m
emailservice ClusterIP 10.101.67.47 <none> 5000/TCP 41m
frontend ClusterIP 10.96.37.222 <none> 80/TCP 41m
frontend-external LoadBalancer 10.109.168.181 192.168.0.53 80:30090/TCP 41m
paymentservice ClusterIP 10.105.223.48 <none> 50051/TCP 41m
productcatalogservice ClusterIP 10.102.112.64 <none> 3550/TCP 41m
recommendationservice ClusterIP 10.99.127.143 <none> 8080/TCP 41m
redis-cart ClusterIP 10.111.15.205 <none> 6379/TCP 41m
shippingservice ClusterIP 10.104.122.207 <none> 50051/TCP 41m
该服务最后是通过 frontend-external 这个 LoadBalancer 类型的 Service 来暴露的服务,我们可以直接通过分配的 IP 192.168.0.53 来访问服务了。
frontend external
触发器
同样我们也可以给服务添加触发器来触发任务,在工作流编辑页面点击左侧的触发器添加,勾选 Webhook -> 添加配置,我们可以先添加一个只针对 adservice 这个服务的触发器,选择对应的代码库、要部署的服务,最关键的是文件目录部分的配置,也就是代码仓库中的什么文件变更才会触发我们的任务,我们的配置为:
src/adservice/
!.md
!.gitignore
该段配置的表示当代码仓库中 src/adservice/ 目录下面的代码有变更,并且不是 .md 或者 .gitignore 文件则会触发任务。
触发器
配置后记得保存。现在我们可以去修改下 adservice 服务中的代码,修改代码 src/adservice/src/main/java/hipstershop/AdService.java,比如我们将 177 行的 50%修改为 60%,然后提交代码到 main 分支。
修改代码
当我们将上述代码 push 到 main 分支后,Zadig 就立即触发了一次新的任务。
webhook trigger
该任务执行成功后我们可以去查看该产品的页面是否生效。
验证修改
到这里我就实现了该微服务项目的持续构建,同样的我们可以去手动创建一个环境来进行交付,操作方式一样的。
测试用例
此外我们还可以来新建一些测试用例,在测试页面点击新建测试按钮即可开始创建测试用例。
新建测试
比如我们这里对一个 go 服务做一次简单的测试,在依赖的软件包中可以选择对应的依赖,如果没有对应的软件包,则可以新建一个。
软件依赖
比如我们需要一个 1.17 版本的 go 环境,可以通过 系统设置 -> 软件包管理 新建一个软件包。
新建软件包
然后我们重新去创建一个测试用例,选择相应的依赖,同样配置对应的代码源和测试脚本。
测试脚本
创建后可以用同样的方式来执行该测试用例。
执行测试
测试详情页面和工作流的任务页面基本上一致。
测试详情
同样也可以看到对应的测试报告。
测试报告
此外我们还可以将自动化测试和工作流关联起来,当日常运行工作流更新环境后,会自动执行自动化测试。可以实现只要环境有变更,就第一时间对其做自动化测试。
关联工作流
关联后启动工作流任务就可以看到有该测试用例了。
测试用例
工作流
Zadig 还会为我们的构建数据进行统计,提供构建效能、部署效能等数据。
构建效能
到这里我们就完成了使用 Zadig 来对微服务项目进行持续集成和交付,当然在实际的生产环境中和具体的项目业务有关系,这就需要能够结合实际需求去实践了。