让微服务了解另一个微服务交互名称的最佳实践是什么

What is the best practice to make microservice aware about name of another microservice for interaction

我在 spring 引导中编写了几个微服务,它们相互交互以执行特定任务。我需要使用 Kubernetes 在 AWS 中部署这些微服务。为了让微服务相互交互,一个服务需要知道另一个服务的名称。这是我不确定如何进行的地方。

由于我打算使用 Kubernetes 进行部署,我将为这两个微服务创建 Kubernetes 服务,并且还想利用 Kubernetes 的 DNS 解析。现在我的问题是如何让一个微服务知道 Kubernetes 服务名称。我能想到的一种选择是,将微服务的名称放在 application.properties 中并创建具有相同名称的 Kubernetes 服务,但通过这种方法,我的印象是我正在计划失败。如果将来我的服务名称需要以某种方式更改,那么我还需要记住更改依赖于此的每个微服务中的名称。

我认为这是人们在使用 Kubernetes 进行微服务部署期间可能会遇到的非常常见的情况。那么,执行此操作的最佳做​​法是什么?

一种解决方案是使用 Config map 并在 config map 中添加那些微服务 URL。然后您可以将它们安装在部署 pod 模板中并在您的应用程序中使用它们。

所以将来,如果您需要更改微服务 URL,您必须相应地更改配置映射。

如果你想要微服务地址作为env,那么你的配置映射将是这样的:

apiVersion: v1
kind: ConfigMap
metadata:
  name: service-config
data:
  micro_service_1: "value1"
  micro_service_2: "value2"

或者您可以在某些属性文件中使用它们:

apiVersion: v1
kind: ConfigMap
metadata:
  name: service-config
data:
  service.properties: |
    micro_service_1: "value1"
    micro_service_2: "value2"

然后将它们安装到您的部署 pod 模板规范中:

spec:
  containers:
    - name: demo
      image: alpine
      env:
        - name: MICROSERVICE_1
          valueFrom:
            configMapKeyRef:
              name: service-config
              key: microservice_1
        - name: MICROSERVICE_2
          valueFrom:
            configMapKeyRef:
              name: service-config
              key: microservice_2
      # you will need volumeMounts and volumes if and only if you use service address from properties file. Then you can skip above env part
      volumeMounts:
      - name: config
        mountPath: "/config"
        readOnly: true
  volumes:
    # You set volumes at the Pod level, then mount them into containers inside that Pod
    - name: config
      configMap:
        # Provide the name of the ConfigMap you want to mount.
        name: secret-config
        # An array of keys from the ConfigMap to create as files
        items:
        - key: "service.properties"
          path: "service.properties"

将服务名称作为环境变量传递。可以将它们直接嵌入到客户的 YAML 规范中(如果您使用像 Helm 这样的模板工具,这会稍微容易一些),尽管使用间接 ConfigMap 也可以。

---
apiVersion: v1
kind: Service
metadata:
  name: other-service
spec:
  ports:
    - port: 80          # make the Service use the standard HTTP port
      targetPort: http  # even if the Pod uses something else
...
---
apiVersion: apps/v1
kind: Deployment
spec:
  ...
    env:
      - name: OTHERSERVICE_URL
        value: http://other-service

每种语言都有一些方法来检索环境变量(Python os.environ[]、Node process.env、...),因此无论实现语言如何,您都可以使用这种方法。如果未设置环境变量,请将其默认值设置为对开发人员有用的值,可能是已知端口上的 localhost URL。

在 Spring 引导客户端中,environment variables can be directly used as Spring properties (see also more specific rules for environment variable names) 所以你的 application.yml 文件可以指定

other-service:
  url: http://localhost:12345

然后您的客户端可以配置为

@ConfigurationProperties(prefix="other-service")
@Data
public class OtherServiceClient {
  private String url;
}

不要尝试在此处使用 Spring 属性 文件来配置服务 URL。 (在 Helm 上下文中,您可以在 ConfigMap 中动态构建一个完整的 属性 文件,但环境变量方法更通用。)因为 URL 几乎可以有任何主机名(同样,尤其是在通常构造名称的 Helm 上下文中)您不想重新编译 jar 文件以重新部署到新的地方。

我不太熟悉 kubernates 以及您可以在多大程度上利用 Kubernetes 的 DNS 解析。但是,如果您使用 spring 引导,您可以利用 Spring 云,它提供了一些称为 Service discovery/registry 的 solutions/services可用于查找各种微服务,您可以使用假客户端进行它们之间的通信。

您需要创建 Eureka(netflix Eureka 是 Spring 云下的宠物项目)服务器,您的客户端服务将在其中注册自己(在您的情况下是不同的不同微服务),并且您的微服务将成为该服务器的客户端.

您可以找到 spring.io 文档,其中将为您提供基本的设置示例。

此处https://spring.io/guides/gs/service-registration-and-discovery/

这里还有关于 feign 的声明式 REST 客户端
https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html