SpringBoot + DDD + Apache Kafka实现最终一致性:在Kubernetes与Istio运维微服务 - itnext


本文是SpringBoot + DDD + Apache Kafka实现最终一致性的教程与源码的运维DevOps部分:
如本文第一部分所述,对于一个现代由多个微服务组成分布式系统,每个微服务都包含一个领域的聚合数据的子集,该系统几乎可以肯定会有一些数据重复。有了这种重复,我们如何保持数据的一致性?在这一由两部分组成的文章中,我们探讨了应对这一挑战的一种可能的解决方案-Apache Kafka和最终一致性模型。
在这篇文章的第二部分,我们将回顾如何部署和在本地开发环境中运行的店面API组件与Kubernetes运行Istio,使用minikube。为简单起见,我们将只运行每个微服务的单个实例。此外,我们不会实现自定义域名,TLS / HTTPS,身份验证和授权,API密钥,也不会限制对任何敏感的操作性API端点或端口的访问,而我们肯定会在实际生产环境中进行所有这些操作。
为了提供操作可见性,我们将在我们的系统中添加Yahoo的CMAK(Apache Kafka的集群管理器),Mongo ExpressKialiPrometheusGrafana
先决条件
这篇文章将假设您对Kubernetes,minikube,Docker和Istio有基本的了解。此外,文章假定您已经安装了minikubekubectlDockerIstio的最新版本。这意味着kubectl,istioctl,docker,和minikube命令都可以从终端运行。
在本次演示中,我使用运行macOS的Apple MacBook Pro作为开发计算机。截至2021年5月,我已经安装了最新版本的Docker桌面,minikube,kubectl和Istio。
 
源代码
这篇文章的源代码是开源的,可以在GitHub上公开获得。使用以下命令克隆GitHub项目:

clone --branch 2021-istio \
    --single-branch --depth 1 \
    https://github.com/garystafford/storefront-demo.git

 
Minikube
minikube是Kubernetes项目的一部分,它是本地的Kubernetes,致力于使Kubernetes的学习和开发变得容易。Minikube可以在macOS,Linux和Windows上快速设置本地Kubernetes集群。鉴于我们将要部署到minikube的Kubernetes资源数量,我建议至少使用3个CPU和4–5 GB的内存。如果您选择部署多个可观察性工具,则如果可以承受的话,您可能希望同时增加这两个资源。在设置此演示时,我将CPU和内存都用尽了几次,从而导致minikube暂时锁定。
minikube --cpus 3 --memory 5g --driver=docker start start

Docker driver 允许您Kubernetes安装到现有的Docker中。如果您使用的是Docker,请注意,您必须至少分配了相等数量的资源给Docker,才能分配给minikube。
在继续之前,请确认minikube已启动并正在运行,并确认kubectlis的当前上下文是minikube。

minikube status
kubectl config current-context

使用eval以下命令将您的shell指向minikube的docker-daemon。您可以使用docker image lsanddocker container ls命令确认正确的上下文,以查看minikube上正在运行的Kubernetes容器。

eval $(minikube -p minikube docker-env)
docker image ls
docker container ls

您还可以从Docker Desktop检查minikube的状态。Minikube作为容器运行,从Docker映像实例化gcr.io/k8s-minikube/kicbase。查看容器的统计信息。
 
Istio
假设您已经下载并配置了Istio,请将其安装到minikube上。我当前安装了Istio 1.10.0,并ISTIO_HOME在“我的我的Zsh” .zshrc文件中设置了环境变量。我还在环境变量中设置了Istio的bin/子目录PATH。该bin/子目录包含istioctl可执行文件。

echo $ISTIO_HOME                                                                
> /Applications/Istio/istio-1.10.0
where istioctl
> /Applications/Istio/istio-1.10.0/bin/istioctl
istioctl version
                                                               
> client version: 1.10.0
  control plane version: 1.10.0
  data plane version: 1.10.0 (4 proxies)

Istio带有几个内置的配置文件。这些配置文件为Istio控制平面和Istio数据平面的边车提供了定制。

istioctl profile list
> Istio configuration profiles:
    default
    demo
    empty
    external
    minimal
    openshift
    preview
    remote

在此演示中,我们将使用默认配置文件,该配置文件将安装istiod并提供一个istio-ingressgateway。我们不需要使用istio-egressgateway,因为所有组件都将本地安装在minikube上。
istioctl install --set profile=default -y
> Istio core installed
 Istiod installed
 Ingress gateways installed
 Installation complete

 

Minikube Tunnel
可以使用以下minikube tunnel命令公开LoadBalancer类型的Kubernetes服务(不要将Spring Boot服务(又称微服务)与Kubernetes Service资源类型混淆)。Minikube隧道必须在单独的终端窗口中LoadBalancer运行才能保持运行。我们之前创建了istio-ingressgateway。运行以下命令,并注意状态EXTERNAL-IP为<pending>。目前没有与我们的关联的外部IP地址LoadBalancer。
kubectl get svc istio-ingressgateway -n istio-system

要关联IP地址,请minikube tunnel在单独的终端选项卡中运行命令。由于它需要打开特权端口80和443才能公开,因此此命令将提示您输入sudo密码。

minikube tunnel

重新运行上一个命令。现在应该有与相关联的外部IP地址LoadBalancer.在我的情况下是127.0.0.1.

kubectl get svc istio-ingressgateway -n istio-system

显示的外部IP地址是我们用来访问我们选择在minikube上公开的资源的地址。
 
Minikube仪表板
再次在单独的终端选项卡中,打开Minikube仪表板(又名Kubernetes仪表板)。
minikube dashboard
该仪表板将为您提供所有已安装的Kubernetes组件的直观概览。
 
命名空间
Kubernetes支持由同一物理群集支持的多个虚拟群集。这些虚拟集群称为名称空间。对于本演示中,我们以四个命名空间来组织我们的部署资源:dev,mongo,kafka,和storefront-kafka-project。
  • dev命名空间是我们将部署我们的店面API的微服务:accounts,orders,和fulfillment。
  • 我们将MongoDB和Mongo Express部署到mongo名称空间。
  • 最后,我们将使用kafka和storefront-kafka-project 名称空间,通过Strimzi(一个Cloud Native Computing Foundation沙箱项目)和CMAK将Apache Kafka部署到minikube 。

kubectl apply -f ./minikube/resources/namespaces.yaml
 

Istio自动边车注入
为了利用Istio的所有功能,网格中的Pod必须运行Istio Sidecar代理。在istio-injection=enabled label命名空间上设置on并启用注入Webhook时,在该命名空间中创建的所有新容器都将自动添加一个sidecar。标注的dev命名空间自动边车诸如,确保我们的店面API的微服务- accounts,orders和fulfillment-将有Istio边车代理自动注入到他们的Pod。

kubectl label namespace dev istio-injection=enabled

 
MongoDB
接下来,将MongoDB和Mongo Express部署到mongominikube上的名称空间。为了确保从Mongo Express成功连接到MongoDB,建议在部署Mongo Express之前给MongoDB一个完全启动的机会。

kubectl apply -f ./minikube/resources/mongodb.yaml -n mongo
sleep 60
kubectl apply -f ./minikube/resources/mongo-express.yaml -n mongo

要确认部署是否成功,请使用以下命令:
kubectl get services -n mongo

或使用Kubernetes仪表板确认部署。
 
Mongo Express用户界面访问
对于应用程序的某些部分(例如,前端),您可能希望将服务公开到群集外部的外部IP地址上。KubernetesServiceTypes允许您指定所需的服务类型。默认值为ClusterIP。
请注意,虽然MongoDB使用ClusterIP,但Mongo Express使用NodePort。通NodePort,服务在每个节点的IP的静态端口(NodePort)上公开。您可以NodePort通过请求从群集外部与服务联系<NodeIP>:<NodePort>。
在单独的终端选项卡中,使用以下命令打开Mongo Express:

minikube service --url mongo-express -n mongo

 
使用Strimzi的Apache Kafka
接下来,我们将使用Strimzi将Apache Kafka和Apache Zookeeper安装到minikube的kafka和storefront-kafka-project 名称空间中。由于Strimzi有一个很好的,易于使用的快速入门指南,因此在本文中,我将不详细介绍完整的安装完成过程。我建议使用他们的指南来了解该过程以及每个命令的作用。然后,使用下面略微修改的Strimzi命令安装Kafka和Zookeeper。
# assuming 0.23.0 is latest version available
curl -L -O https://github.com/strimzi/strimzi-kafka-operator/releases/download/0.23.0/strimzi-0.23.0.zip
unzip strimzi-0.23.0.zip
cd strimzi-0.23.0
sed -i '' 's/namespace: .*/namespace: kafka/' install/cluster-operator/*RoleBinding*.yaml
# manually change STRIMZI_NAMESPACE value to storefront-kafka-project
nano install/cluster-operator/060-Deployment-strimzi-cluster-operator.yaml
kubectl create -f install/cluster-operator/ -n kafka
kubectl create -f install/cluster-operator/020-RoleBinding-strimzi-cluster-operator.yaml -n storefront-kafka-project
kubectl create -f install/cluster-operator/032-RoleBinding-strimzi-cluster-operator-topic-operator-delegation.yaml -n storefront-kafka-project
kubectl create -f install/cluster-operator/031-RoleBinding-strimzi-cluster-operator-entity-operator-delegation.yaml -n storefront-kafka-project
kubectl apply -f ../storefront-demo/minikube/resources/strimzi-kafka-cluster.yaml -n storefront-kafka-project
kubectl wait kafka/kafka-cluster --for=condition=Ready --timeout=300s -n storefront-kafka-project
kubectl apply -f ../storefront-demo/minikube/resources/strimzi-kafka-topics.yaml -n storefront-kafka-project

 
ZK入口
我们要安装Yahoo的CMAK(Apache Kafka的集群管理器),以便为我们提供Kafka的管理界面。但是,CMAK需要访问Zookeeper。您不能直接从CMAK访问Strimzi's Zookeeper;这是为了避免性能和安全性问题。请参阅此GitHub问题,以更好地解释其原因。我们将使用适当命名的Zoo Entrance作为Zookeeper的CMAK的代理,以克服这一挑战。
要安装Zoo Entrance,请查看GitHub项目的安装指南,然后使用以下命令:

git clone https://github.com/scholzj/zoo-entrance.git
cd zoo-entrance
# optional: change my-cluster to kafka-cluster
sed -i '' 's/my-cluster/kafka-cluster/' deploy.yaml
kubectl apply -f deploy.yaml -n storefront-kafka-project

 
Apache Kafka的集群管理器
接下来,安装Yahoo的CMAK(Apache Kafka的集群管理器),为我们提供Kafka的管理界面。运行以下命令以将CMAK部署到storefront-kafka-project名称空间中。

kubectl apply -f ./minikube/resources/cmak.yaml -n storefront-kafka-project

与Mongo Express相似,我们可以使用来访问CMAK的UI NodePort。在单独的终端选项卡中,运行以下命令:
minikube service --url cmak -n storefront-kafka-project

您应该看到类似于Mongo Express的输出。单击提供的链接以访问CMAK。在CMAK中选择“添加群集”,将我们现有的Kafka群集添加到CMAK的管理界面中。将“ Zoo Enterence”的“服务”地址用作“群集Zookeeper主机”值。

zoo-entrance.storefront-kafka-project.svc:2181

完成后,你应该看到我们先前Strimzi创建的三个卡夫卡主题:accounts.customer.change,fulfillment.order.change,和orders.order.change。每个主题将具有三个分区,一个副本和一个代理。您还应该看到_consumer_offsets主题Kafka用于存储有关每个消费者组(groupID)的已提交偏移量的信息topic:partition。
 
店面API微服务
我们终于准备好将Storefront API的微服务安装到dev名称空间中。每个微服务都已预先配置为在各自的名称空间中访问Kafka和MongoDB。
kubectl apply -f ./minikube/resources/accounts.yaml -n dev
kubectl apply -f ./minikube/resources/orders.yaml -n dev
kubectl apply -f ./minikube/resources/fulfillment.yaml -n dev

Spring Boot服务通常需要大约两分钟才能完全启动。从docker.com下载Docker映像所需的时间和启动时间意味着,三个微服务中的每一个都可能需要3-4分钟才能准备好接受API流量。
 
Istio组件
我们希望能够通过Kubernetes的LoadBalancer访问Storefront API的微服务,同时还要利用Istio的所有功能作为服务网格。为此,我们需要部署一个IstioGateway和一个VirtualService。我们还需要部署DestinationRule资源:Gateway描述了一个负载均衡器,该负载均衡器在网格的边缘运行,以接收传入或传出的HTTP / TCP连接。VirtualService定义了一组寻址主机时要应用的流量路由规则。最后,DestinationRule定义策略,该策略适用于路由发生后用于服务的流量。

kubectl apply -f ./minikube/resources/destination_rules.yaml -n dev
kubectl apply -f ./minikube/resources/istio-gateway.yaml -n dev

测试系统并创建样本数据
我提供了一个Python 3脚本,该脚本HTTP GET针对Storefront API以特定顺序运行一系列七个请求。这些调用将验证部署,确认API的Spring Boot服务可以访问Kafka和MongoDB,生成一些初始数据,并根据初始Insert语句自动创建MongoDB数据库集合。

python3 -m pip install -r ./utility_scripts/ requirements.txt -U
python3 ./utility_scripts/refresh.py

 
可观察性工具
Istio使其易于与几种常用工具集成,包括证书管理器,Prometheus,Grafana,Kiali,Zipkin和Jaeger。为了更好地观察我们的Storefront API,我们将安装三个著名的可观察性工具:Kiali,Prometheus和Grafana。幸运的是,这些工具全部包含在Istio中。您可以将这些中的任何一个或全部安装到minikube。我建议一次安装一个工具,以免淹没minikube的CPU和内存资源。

kubectl apply -f ./minikube/resources/prometheus.yaml
kubectl apply -f $ISTIO_HOME/samples/addons/grafana.yaml
kubectl apply -f $ISTIO_HOME/samples/addons/kiali.yaml

部署完成后,要访问这些工具的任何UI,请在istioctl dashboard新的终端窗口中使用以下命令:
istioctl dashboard kiali
istioctl dashboard prometheus
istioctl dashboard grafana

Kiali 
Kiali是用于基于Istio的服务网格的管理控制台。它提供了仪表板,可观察性,并允许您使用强大的配置和验证功能来操作网格。在下面,我们看到Kiali的视图,其中有店面API流量流向Kafka和MongoDB。

 
Prometheus
Prometheus是Cloud Native Computing Foundation项目,是一个系统和服务监视系统。它以给定的时间间隔从已配置的目标收集指标,评估规则表达式,显示结果,并在观察到指定条件时触发警报。
三个Storefront API微服务中的每一个都具有对Micrometer的依赖关系,特别是对micrometer-registry-prometheus。作为仪器仪表的基础,Micrometer允许您使用与供应商无关的接口,以尺寸指标对代码进行仪表检测,并确定监视系统的最后一步。使用Micrometer对核心库代码进行检测,可以将这些库包含在将度量标准传送到不同后端的应用程序中。给定Micrometer Prometheus依赖性,每个微服务都会公开一个/prometheus端点(例如http://127.0.0.1/accounts/actuator/prometheus)
/prometheus端点暴露几十有用的度量,并被配置为通过普罗米修斯筛选。这些指标可以在Prometheus中显示,也可以通过Prometheus在Grafana仪表板中间接显示。我已经定制了Istio的Prometheus版本,并将其包含在项目(prometheus.yaml)中,该项目现在可以显示Storefront API的指标。

scrape_configs:
    - job_name: 'spring_micrometer'
      metrics_path: '/actuator/prometheus'
      scrape_interval: 5s
      static_configs:
        - targets: ['accounts.dev:8080','orders.dev:8080','fulfillment.dev:8080']

 
Grafana
Grafana允许您查询,可视化,警报和了解指标,无论它们存储在哪里。与您的团队一起创建,浏览和共享仪表板,以培养数据驱动的文化。最后,这是Grafana中的Spring Boot仪表板示例。Grafana的社区仪表板页面上提供了更多仪表板。Grafana仪表板使用Prometheus作为其指标数据的来源。
 
店面API端点
三个Storefront API的Spring Boot服务是功能齐全的Spring BootSpring Data REST,启用S​​pring HATEOAS的应用程序。每一个都公开了一组丰富的CRUD端点,用于与微服务的数据实体进行交互。为了更好地理解Storefront API,每个Spring Boot微服务都使用SpringFox,该工具为使用Spring构建的API生成自动JSON API文档。微服务版本还包括Swagger UI附带的springfox-swagger-ui Web jar。Swagger提供了用于生成,可视化和维护API文档的一系列解决方案,使API文档中的手动工作变得简单。
在Web浏览器中,您可以将/swagger-ui/子目录/子路径与三个微服务中的任何一个一起使用,以访问功能齐全的Swagger UI(例如http://127.0.0.1/accounts/swagger-ui/)。
 
结论
在这个由两部分组成的文章中,我们学习了如何使用Spring Boot构建API。我们使用Spring for Apache Kafka Project的发布/订阅模型来确保API的分布式数据完整性。当一个微服务更改了相关数据时,该状态更改会触发状态更改事件,该事件会使用Kafka主题与其他微服务共享。
我们还学习了如何使用minikube在具有Istio的Kubernetes上运行的本地开发环境中部署和运行API。我们添加了经过生产测试的可观察性工具,以提供操作可见性,包括CMAK,Mongo Express,Kiali,Prometheus和Grafana。
 
点击标题见原文,全文完,本文总共由六篇文章组成:见下面链接: