将 Stork 与 Kubernetes 一起使用
本指南将介绍如何在 Kubernetes 中使用 Stork 进行服务发现和负载均衡。
如果您是 Stork 的新手,请阅读 Stork 入门指南。
此技术被认为是预览版。 在预览版本中,不保证向后兼容性和在生态系统中的存在性。特定的改进可能需要更改配置或 API,并且我们正在计划使其成为稳定版本。欢迎在我们的 邮件列表 或我们的 GitHub 问题跟踪器 中提出问题并提供反馈。 有关可能的完整状态列表,请查看我们的常见问题解答条目。 |
先决条件
要完成本指南,您需要
-
大约 15 分钟
-
一个 IDE
-
已安装 JDK 17+ 并正确配置了
JAVA_HOME
-
Apache Maven 3.9.9
-
一个正常工作的容器运行时(Docker 或 Podman)
-
如果您想使用它,可以选择 Quarkus CLI
-
如果您想构建本机可执行文件(或者如果您使用本机容器构建,则为 Docker),可以选择安装 Mandrel 或 GraalVM 并进行适当的配置
-
可以访问 Kubernetes 集群(Minikube 是一个可行的选项)
架构
在本指南中,我们将使用部署在 Kubernetes 集群中的几个组件
-
一个简单的蓝色服务。
-
一个简单的红色服务。
-
color-service
是 Kubernetes 服务,它是 Blue 和 Red 实例的入口点。 -
一个使用 REST 客户端调用蓝色或红色服务的客户端服务。服务发现和选择委托给 Stork。

为了简单起见,所有内容都将在 Kubernetes 集群的同一命名空间中部署。
解决方案
我们建议您遵循后续章节中的说明,一步一步地创建应用程序。但是,您可以直接查看完整的示例。
克隆 Git 仓库:git clone https://github.com/quarkusio/quarkus-quickstarts.git
,或下载 存档。
解决方案位于 stork-kubernetes-quickstart
目录中。
发现与选择
在深入之前,我们需要讨论发现与选择。
-
服务发现是指定位服务实例的过程。它会生成一个可能为空(如果没有服务匹配请求)或包含多个服务实例的服务实例列表。
-
服务选择,也称为负载均衡,从发现过程返回的列表中选择最佳实例。结果是单个服务实例,或者在找不到合适的实例时抛出异常。
Stork 同时处理发现和选择。但是,它不处理与服务的通信,只提供一个服务实例。Quarkus 中的各种集成从该服务实例中提取服务的位置。
引导项目
使用您喜欢的方式,创建一个导入 quarkus-rest-client、quarkus-rest 和 quarkus-smallrye-stork 扩展的 Quarkus 项目
对于 Windows 用户
-
如果使用 cmd,(不要使用反斜杠
\
并将所有内容放在同一行上) -
如果您使用 Powershell,请将
-D
参数括在双引号中,例如"-DprojectArtifactId=stork-kubernetes-quickstart"
在生成的项目中,还要添加以下依赖项
<dependency>
<groupId>io.smallrye.stork</groupId>
<artifactId>stork-service-discovery-kubernetes</artifactId>
</dependency>
<dependency>
<groupId>io.smallrye.stork</groupId>
<artifactId>stork-load-balancer-random</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes-client</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-container-image-jib</artifactId>
</dependency>
implementation("io.smallrye.stork:stork-service-discovery-kubernetes")
implementation("io.smallrye.stork:stork-load-balancer-random")
implementation("io.quarkus:quarkus-kubernetes")
implementation("io.quarkus:quarkus-kubernetes-client")
implementation("io.quarkus:quarkus-container-image-jib")
stork-service-discovery-kubernetes
提供了 Kubernetes 的服务发现实现。stork-load-balancer-random
提供了随机负载均衡器的实现。quarkus-kubernetes
允许我们在每次构建时生成 Kubernetes 清单。quarkus-kubernetes-client
扩展允许在原生模式下使用 Fabric8 Kubernetes 客户端。而 quarkus-container-image-jib
允许使用 Jib 构建容器镜像。
在 Kubernetes 中部署蓝色和红色服务
现在我们已经有了公共注册表中提供的服务容器镜像,我们需要将它们部署到 Kubernetes 集群中。
以下文件包含在集群中部署 Blue 和 Red 服务并使其可访问所需的所有 Kubernetes 资源
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: development
name: endpoints-reader
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["endpoints", "pods"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: stork-rb
namespace: development
subjects:
- kind: ServiceAccount
# Reference to upper's `metadata.name`
name: default
# Reference to upper's `metadata.namespace`
namespace: development
roleRef:
kind: Role
name: endpoints-reader
apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: Service
metadata:
annotations:
app.quarkus.io/commit-id: f747f359406bedfb1a39c57392a5b5a9eaefec56
app.quarkus.io/build-timestamp: 2022-03-31 - 10:36:56 +0000
labels:
app.kubernetes.io/name: color-service
app.kubernetes.io/version: "1.0"
name: color-service (1)
spec:
ports:
- name: http
port: 80
targetPort: 8080
selector:
app.kubernetes.io/version: "1.0"
type: color-service
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
app.quarkus.io/commit-id: f747f359406bedfb1a39c57392a5b5a9eaefec56
app.quarkus.io/build-timestamp: 2022-03-31 - 10:36:56 +0000
labels:
color: blue
type: color-service
app.kubernetes.io/name: blue-service
app.kubernetes.io/version: "1.0"
name: blue-service (2)
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: blue-service
app.kubernetes.io/version: "1.0"
template:
metadata:
annotations:
app.quarkus.io/commit-id: f747f359406bedfb1a39c57392a5b5a9eaefec56
app.quarkus.io/build-timestamp: 2022-03-31 - 10:36:56 +0000
labels:
color: blue
type: color-service
app.kubernetes.io/name: blue-service
app.kubernetes.io/version: "1.0"
spec:
containers:
- env:
- name: KUBERNETES_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: quay.io/quarkus/blue-service:1.0
imagePullPolicy: Always
name: blue-service
ports:
- containerPort: 8080
name: http
protocol: TCP
---
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
app.quarkus.io/commit-id: 27be03414510f776ca70d70d859b33e134570443
app.quarkus.io/build-timestamp: 2022-03-31 - 10:38:54 +0000
labels:
color: red
type: color-service
app.kubernetes.io/version: "1.0"
app.kubernetes.io/name: red-service
name: red-service (2)
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/version: "1.0"
app.kubernetes.io/name: red-service
template:
metadata:
annotations:
app.quarkus.io/commit-id: 27be03414510f776ca70d70d859b33e134570443
app.quarkus.io/build-timestamp: 2022-03-31 - 10:38:54 +0000
labels:
color: red
type: color-service
app.kubernetes.io/version: "1.0"
app.kubernetes.io/name: red-service
spec:
containers:
- env:
- name: KUBERNETES_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: quay.io/quarkus/red-service:1.0
imagePullPolicy: Always
name: red-service
ports:
- containerPort: 8080
name: http
protocol: TCP
---
apiVersion: networking.k8s.io/v1
kind: Ingress (3)
metadata:
annotations:
app.quarkus.io/commit-id: f747f359406bedfb1a39c57392a5b5a9eaefec56
app.quarkus.io/build-timestamp: 2022-03-31 - 10:46:19 +0000
labels:
app.kubernetes.io/name: color-service
app.kubernetes.io/version: "1.0"
color: blue
type: color-service
name: color-service
spec:
rules:
- host: color-service.127.0.0.1.nip.io
http:
paths:
- backend:
service:
name: color-service
port:
name: http
path: /
pathType: Prefix
此列表中有几个有趣的部分
1 | Kubernetes Service 资源 color-service ,Stork 将会发现它。 |
2 | color-service Kubernetes 服务背后的 Red 和 Blue 服务实例。 |
3 | 一个 Kubernetes Ingress 资源,使 color-service 可以从集群外部通过 color-service.127.0.0.1.nip.io URL 访问。请注意,Stork 不需要 Ingress,但它有助于检查架构是否已就位。 |
在项目根目录创建一个名为 kubernetes-setup.yml
的文件,并包含上述内容,然后运行以下命令将所有资源部署到 Kubernetes 集群。别忘了创建一个专用的命名空间
kubectl create namespace development
kubectl apply -f kubernetes-setup.yml -n=development
如果一切顺利,Color 服务将在 http://color-service.127.0.0.1.nip.io 上可用。您应该会随机收到 Hello from Red!
和 Hello from Blue!
的响应。
Stork 不限于 Kubernetes,并与其他服务发现机制集成。 |
REST 客户端接口和前端 API
到目前为止,我们还没有使用 Stork;我们只是部署了我们将要发现、选择和调用的服务。
我们将使用 REST 客户端调用服务。创建 src/main/java/org/acme/MyService.java
文件,内容如下
package org.acme;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
/**
* The REST Client interface.
*
* Notice the `baseUri`. It uses `stork://` as URL scheme indicating that the called service uses Stork to locate and
* select the service instance. The `my-service` part is the service name. This is used to configure Stork discovery
* and selection in the `application.properties` file.
*/
@RegisterRestClient(baseUri = "stork://my-service")
public interface MyService {
@GET
@Produces(MediaType.TEXT_PLAIN)
String get();
}
这是一个直接的 REST 客户端接口,只包含一个方法。但是,请注意 baseUri
属性:* stork://
后缀指示 REST 客户端将服务实例的发现和选择委托给 Stork,* URI 的 my-service
部分是我们将在应用程序配置中使用的服务名称。
它不改变 REST 客户端的使用方式。创建 src/main/java/org/acme/FrontendApi.java
文件,内容如下
package org.acme;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
/**
* A frontend API using our REST Client (which uses Stork to locate and select the service instance on each call).
*/
@Path("/api")
public class FrontendApi {
@RestClient MyService service;
@GET
@Produces(MediaType.TEXT_PLAIN)
public String invoke() {
return service.get();
}
}
它像往常一样注入并使用 REST 客户端。
Stork 配置
现在我们需要配置 Stork 以使用 Kubernetes 来发现服务的 red 和 blue 实例。
在 src/main/resources/application.properties
中,添加
quarkus.stork.my-service.service-discovery.type=kubernetes
quarkus.stork.my-service.service-discovery.k8s-namespace=development
quarkus.stork.my-service.service-discovery.application=color-service
quarkus.stork.my-service.load-balancer.type=random
stork.my-service.service-discovery
指示我们将使用哪种类型的服务发现来定位 my-service
服务。在我们的例子中,它是 kubernetes
。如果您的 Kubernetes 集群访问是通过 Kube 配置文件配置的,则无需配置对它的访问。否则,请使用 quarkus.stork.my-service.service-discovery.k8s-host
属性设置正确的 Kubernetes URL。quarkus.stork.my-service.service-discovery.application
包含 Stork 将要请求的 Kubernetes 服务的名称。在我们的例子中,这是 color-service
,对应于由 Red 和 Blue 实例支持的 kubernetes 服务。最后,quarkus.stork.my-service.load-balancer.type
配置服务选择。在我们的例子中,我们使用 random
负载均衡器。
在 Kubernetes 集群中部署 REST 客户端接口和前端 API
系统已基本完成。我们只需要将 REST 客户端接口和客户端服务部署到集群。在 src/main/resources/application.properties
中,添加
quarkus.container-image.registry=<public registry>
quarkus.kubernetes-client.trust-certs=true
quarkus.kubernetes.ingress.expose=true
quarkus.kubernetes.ingress.host=my-service.127.0.0.1.nip.io
quarkus.container-image.registry
包含要使用的容器注册表。quarkus.kubernetes.ingress.expose
指示服务将可以从集群外部访问。quarkus.kubernetes.ingress.host
包含访问服务的 URL。我们正在使用 nip.io 通配符进行 IP 地址映射。
有关更自定义的配置,您可以查看 部署到 Kubernetes 指南
构建和推送容器镜像
得益于我们使用的扩展,我们可以使用 Jib 构建容器镜像,同时还可以启用在构建应用程序时生成 Kubernetes 清单。例如,以下命令将在 target/kubernetes/
目录中生成 Kubernetes 清单,并为项目构建和推送容器镜像
./mvnw package -Dquarkus.container-image.build=true -Dquarkus.container-image.push=true
将客户端服务部署到 Kubernetes 集群
生成的清单可以从项目根目录使用 kubectl 应用到集群
kubectl apply -f target/kubernetes/kubernetes.yml -n=development
请注意,如果您使用 Stork 的椭圆曲线密钥并遇到类似 请注意,内部将注册 您可以在 BouncyCastle 或 BouncyCastle FIPS 部分的描述中注册此提供程序。 |
我们完成了!那么,让我们看看它是否有效。
打开浏览器,导航到 http://my-service.127.0.0.1.nip.io/api。
或者,如果您愿意,可以在另一个终端中运行
> curl http://my-service.127.0.0.1.nip.io/api
...
> curl http://my-service.127.0.0.1.nip.io/api
...
> curl http://my-service.127.0.0.1.nip.io/api
...
响应应该在 Hello from Red!
和 Hello from Blue!
之间随机交替。
您可以将此应用程序编译为原生可执行文件
quarkus build --native
./mvnw install -Dnative
./gradlew build -Dquarkus.native.enabled=true
然后,您需要构建一个基于原生可执行文件的容器镜像。为此,请使用相应的 Dockerfile
> docker build -f src/main/docker/Dockerfile.native -t quarkus/stork-kubernetes-quickstart .
发布新镜像到容器注册表后。您可以将 Kubernetes 清单重新部署到集群。