部署与容错

在 Kubernetes 上使用 Infinispan 部署 Vert.x 集群应用

本文档将向您展示如何在 Kubernetes 上使用 Infinispan 部署 Vert.x 集群应用。

您将构建什么

您将构建一个 Vert.x 集群应用程序,该程序将

  • 监听对 /hello URI 的 HTTP 请求

  • 提取 HTTP 查询参数 name

  • 回复一个问候语,例如 "Hello <name> from <pod>,其中

    • <name> 是查询参数的值

    • <pod> 是生成问候语的 Kubernetes pod 的名称

它由两个部分(或*微服务*)组成,它们通过 Vert.x *事件总线*进行通信。

*前端*处理 HTTP 请求。它提取 name 参数,向总线上的 greetings 地址发送请求,并将回复转发给客户端。

*后端*消费发送到 greetings 地址的消息,生成问候语并回复给*前端*。

您需要什么

  • 文本编辑器或 IDE

  • Java 11 或更高版本

  • Maven 或 Gradle

  • Minikube 或任何 Kubernetes 集群

  • kubectl 命令行工具

创建项目

*前端*和*后端*项目的代码包含功能等效的 Maven 和 Gradle 构建文件。

依赖项

两个项目都依赖于

Vert.x Infinispan 是 Vert.x 的一个集群管理器,它基于 Infinispan 内存键/值数据存储。在 Vert.x 中,集群管理器用于各种功能。特别是,它提供集群节点的发现/成员管理,并存储*事件总线*订阅数据。

Vert.x Web 是一组构建模块,可轻松创建 HTTP 应用程序。

Vert.x Health Check 是一个组件,它标准化了检查系统不同部分、推导状态并暴露状态的过程。

容器化

为了创建容器,我们将使用 Jib,因为它

  • 它为依赖项、资源和类创建了不同的层,从而节省了构建时间和部署时间

  • 它支持 Maven 和 Gradle

  • 它不需要 Docker 也不需要 Podman

使用 Maven

以下是您应该用于*前端*的 pom.xml 文件的内容

对于*后端*,内容类似

使用 Gradle

假设您使用带有 Kotlin DSL 的 Gradle,以下是您的*前端* build.gradle.kts 文件应有的样子

对于*后端*,内容类似

实现服务

让我们从*后端*服务开始。我们将继续处理*前端*,然后在开发机器上测试它们。

*后端*服务

*后端*服务封装在 BackendVerticle 类中。

它通过环境变量配置

当 Verticle 启动时,它会注册一个*事件总线*消费者,设置一个 Vert.x Web Router 并绑定一个 HTTP 服务器

*事件总线*消费者接收发送到 greetings 地址的消息并格式化回复

Router 通过 HTTP 暴露健康和就绪检查

Vert.x Infinispan 提供开箱即用的集群健康检查。io.vertx.ext.cluster.infinispan.ClusterHealthCheck 验证底层 Infinispan 集群状态。

对于本地测试,main 方法是从 IDE 启动 Verticle 的一种简单方式

启动时,Vert.x Infinispan 使用默认的网络堆栈,该堆栈结合了用于发现的 IP 多播和用于组消息的 TCP 连接。此网络堆栈非常适合在我们的开发机器上进行测试。稍后我们将看到如何切换到适合部署到 Kubernetes 的堆栈。

*前端*服务

*前端*服务封装在 FrontendVerticle 类中。

它通过一个环境变量配置

当 Verticle 启动时,它会设置一个 Vert.x Web Router 并绑定一个 HTTP 服务器

Router/hello URI 定义了一个 *GET* 处理程序,此外它还通过 HTTP 暴露健康和就绪检查

用于 /hello URI 的 HTTP 请求处理程序提取 name 参数,通过*事件总线*发送请求并将回复转发给客户端

对于本地测试,main 方法是从 IDE 启动 Verticle 的一种简单方式

本地测试

您可以启动每个服务

  • 直接从您的 IDE 中,或

  • 使用 Maven:mvn compile exec:java,或者

  • 使用 Gradle: ./gradlew run (Linux, macOS) 或 gradlew run (Windows)。

*前端*服务输出应打印类似于以下内容的消息

2020-07-16 16:29:39,478 [vert.x-eventloop-thread-2] INFO  i.v.howtos.cluster.FrontendVerticle - Server started and listening on port 8080

*后端*

2020-07-16 16:29:40,770 [vert.x-eventloop-thread-2] INFO  i.v.howtos.cluster.BackendVerticle - Server started and listening on port 38621
记下 backend HTTP 服务器端口。默认情况下,它使用随机端口以避免与 frontend HTTP 服务器冲突。
以下示例使用 HTTPie 命令行 HTTP 客户端。如果您的系统尚未安装它,请参阅其安装文档。

首先,让我们向*前端*的 /hello URI 发送一个请求,并将 name 查询参数设置为 Vert.x Clustering

http :8080/hello name=="Vert.x Clustering"

您应该看到类似如下内容

HTTP/1.1 200 OK
content-length: 36

Hello Vert.x Clustering from unknown
POD_NAME 环境变量未定义时,unknown 是*后端*使用的默认 pod 名称。

我们还可以验证*前端*的就绪状态

http :8080/readiness
HTTP/1.1 200 OK
content-length: 65
content-type: application/json;charset=UTF-8

{
    "checks": [
        {
            "id": "cluster-health",
            "status": "UP"
        }
    ],
    "outcome": "UP"
}

以及*后端*

http :38621/readiness
HTTP/1.1 200 OK
content-length: 65
content-type: application/json;charset=UTF-8

{
    "checks": [
        {
            "id": "cluster-health",
            "status": "UP"
        }
    ],
    "outcome": "UP"

部署到 Kubernetes

首先,通过 minikube status 确保 Minikube 已启动。

如果您不使用 Minikube,请验证 kubectl 是否已连接到您的集群。

推送容器镜像

多种方法可以将容器镜像推送到 Minikube。

本文档中,我们将直接推送到集群内的 Docker 守护进程。为此,我们必须将 shell 指向 Minikube 的 Docker 守护进程

eval $(minikube -p minikube docker-env)

然后,在同一个 shell 中,我们可以使用 Jib 构建镜像

  • 使用 Maven: mvn compile jib:dockerBuild,或

  • 使用 Gradle: ./gradlew jibDockerBuild (Linux, macOS) 或 gradlew jibDockerBuild (Windows)。

Jib 不会使用 Docker 守护进程来构建镜像,而只用于推送它。
如果您不使用 Minikube,请参阅 Jib MavenJib Gradle 插件文档,了解将镜像推送到注册表时如何配置它们。

集群应用无头服务

在 Kubernetes 上,Infinispan 不应使用默认的网络堆栈,因为 IP 多播通常不可用。

相反,我们将配置它使用一个依赖于无头服务查找进行发现以及 TCP 连接进行组消息的网络堆栈。

让我们创建一个 clustered-app 无头服务,它选择带有标签 cluster:clustered-app 的成员 Pod

无头服务必须考虑即使尚未就绪的 Pod(publishNotReadyAddresses 设置为 true)。

应用此配置

kubectl apply -f headless-service.yml

然后验证是否成功

kubectl get services clustered-app

您应该看到类似如下内容

NAME            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
clustered-app   ClusterIP   None         <none>        7800/TCP   63m

*前端*部署和服务

现在让我们部署*前端*服务。

我们至少需要两个副本以实现高可用性。

要配置 Vert.x Infinispan,我们需要使用一些系统属性启动 JVM

  • java.net.preferIPv4Stack

  • vertx.jgroups.config:网络堆栈配置文件,设置为 default-configs/default-jgroups-kubernetes.xml

  • jgroups.dns.query:我们刚创建的无头服务的 DNS 名称

然后 Kubernetes 需要知道活跃度、就绪性和启动探针的 URI。

启动探针可以指向就绪 URI,并具有不同的超时设置。

应用此配置

kubectl apply -f frontend/deployment.yml

验证 Pods 是否已成功启动

kubectl get pods

您应该看到类似如下内容

NAME                                  READY   STATUS    RESTARTS   AGE
frontend-deployment-8cfd4d966-lpvsb   1/1     Running   0          4m58s
frontend-deployment-8cfd4d966-tctgv   1/1     Running   0          4m58s

我们还需要一个服务来负载均衡 HTTP 流量。Pods 将通过部署中定义的标签 app:frontend 进行选择

应用此配置

kubectl apply -f frontend/service.yml

验证服务是否已成功创建

kubectl get services frontend

您应该看到类似如下内容

NAME       TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
frontend   LoadBalancer   10.106.16.88   <pending>     80:30729/TCP   62s

如果您使用 Minikube,请打开另一个终端窗口并运行

minikube tunnel

Minikube tunnel 作为单独的进程运行,并将服务暴露给主机操作系统。

如果您再次运行 kubectl get services frontend,则外部 IP 应该已设置

NAME       TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
frontend   LoadBalancer   10.100.254.64   10.100.254.64   80:30660/TCP   30m
记下外部 IP。

Minikube tunnel 需要权限提升。如果您未被授予此权限,您仍然可以通过 *NodePort* 使用 minikube service --url frontend 访问该服务。

如果您不使用 Minikube 并且您的服务未分配外部 IP,请参阅您的集群文档。

*后端*部署

*后端*服务的部署与*前端*服务类似。

请注意,在这种情况下

  • 应创建 3 个副本

  • 容器中将设置 POD_NAME 环境变量

应用此配置

kubectl apply -f backend/deployment.yml

验证 Pods 是否已成功启动

kubectl get pods

您应该看到类似如下内容

NAME                                  READY   STATUS    RESTARTS   AGE
backend-deployment-74d7f45c67-h7h9c   1/1     Running   0          63s
backend-deployment-74d7f45c67-r45bc   1/1     Running   0          63s
backend-deployment-74d7f45c67-r75ht   1/1     Running   0          63s
frontend-deployment-8cfd4d966-lpvsb   1/1     Running   0          15m
frontend-deployment-8cfd4d966-tctgv   1/1     Running   0          15m

远程测试

现在我们可以向*前端*的 /hello URI 发送请求,并将 name 查询参数设置为 Vert.x Clustering

http 10.100.254.64/hello name=="Vert.x Clustering"

您应该看到类似如下内容

HTTP/1.1 200 OK
content-length: 64

Hello Vert.x Clustering from backend-deployment-74d7f45c67-6r2g2

请注意,我们现在可以看到 Pod 的名称而不是默认值(unknown)。

此外,如果您重复发送请求,您将看到 backend 服务以循环方式接收*事件总线*请求。

总结

本文档涵盖了

  • 在 Kubernetes 上使用 Infinispan 部署 Vert.x 集群应用所需的依赖项

  • 使用 Jib 对 Vert.x 服务进行容器化

  • Vert.x Infinispan 集群管理器在本地测试和 Kubernetes 部署的配置