你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

使用 Tanzu 服务注册表

注意

Azure Spring Apps 是 Azure Spring Cloud 服务的新名称。 虽然该服务有新名称,但一些地方仍会使用旧名称,我们仍在更新屏幕截图、视频和图形等资产。

本文适用于:❌ 基本版/标准版 ✔️ 企业版

本文介绍如何将 VMware Tanzu 服务注册表与 Azure Spring Apps 企业计划结合使用。

Tanzu 服务注册表是商用 VMware Tanzu 组件之一。 此组件可帮助你将服务发现设计模式应用于应用程序。

服务发现是微服务体系结构的主要理念之一。 如果没有服务发现,就必须手动配置服务的每个客户端或采用某种形式的访问约定。 这个过程可能很困难,并且配置和约定在生产环境中可能不可靠。 你可以使用 Tanzu 服务注册表来动态发现和调用应用程序中的注册服务。

使用 Azure Spring Apps 企业计划,无需自行创建或启动服务注册表。 可以通过在创建 Azure Spring Apps 企业计划实例时选择 Tanzu 服务注册表来使用它。

先决条件

  • 已启用 Tanzu 服务注册表的已预配 Azure Spring Apps 企业计划实例。 有关详细信息,请参阅快速入门:使用企业计划生成应用并将其部署到 Azure Spring Apps
  • Azure Spring Apps 企业计划扩展。 使用以下命令删除以前的版本,并安装最新的企业计划扩展。 如果以前安装了 spring-cloud 扩展,请卸载它以避免配置和版本不匹配。
    az extension add --upgrade --name spring
    az extension remove --name spring-cloud
    

创建使用服务注册表的应用程序

在本文中,你将创建两个服务并将其注册到 Azure Spring Apps 服务注册表。 注册后,一个服务将能够使用服务注册表来发现和调用另一个服务。 下图总结了所需的步骤:

图表显示创建、部署和注册服务 A 和服务 B 的步骤。

这些步骤将在以下各节中进行详细说明。

  1. 创建服务 A。
  2. 将服务 A 部署到 Azure Spring Apps 并将其注册到服务注册表。
  3. 创建服务 B 并实现它以调用服务 A。
  4. 部署服务 B 并将其注册到服务注册表。
  5. 通过服务 B 调用服务 A。

创建环境变量

本文使用以下环境变量。 将这些变量设置为创建 Azure Spring Apps 企业计划实例时使用的值。

变量 说明
$RESOURCE_GROUP 资源组名称。
$AZURE_SPRING_APPS_NAME Azure Spring Apps 实例名称。

使用 Spring Boot 创建服务 A

导航到 Spring Initializr 以创建示例服务 A。此链接使用以下 URL 初始化设置。

https://start.spring.io/#!type=maven-project&language=java&packaging=jar&groupId=com.example&artifactId=Sample%20Service%20A&name=Sample%20Service%20A&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.Sample%20Service%20A&dependencies=web,cloud-eureka

以下屏幕截图显示了具有所需设置的 Spring Initializr。

显示所需设置的 Spring Initializr 页的屏幕截图。

接下来,选择 GENERATE 以获取具有以下目录结构的 Spring Boot 示例项目。

├── HELP.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── example
    │   │           └── Sample
    │   │               └── Service
    │   │                   └── A
    │   │                       └── SampleServiceAApplication.java
    │   └── resources
    │       ├── application.properties
    │       ├── static
    │       └── templates
    └── test
        └── java
            └── com
                └── example
                    └── Sample
                        └── Service
                            └── A
                                └── SampleServiceAApplicationTests.java

确认服务注册表客户端(Eureka 客户端)的依赖库配置

接下来,确认项目的 pom.xml 文件包含以下依赖项。 如果缺少该依赖项,请添加。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

实现服务注册表客户端

@EnableEurekaClient 注释添加到 SampleServiceAApplication.java 文件,以将其配置为 Eureka 客户端。

package com.example.Sample.Service.A;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class SampleServiceAApplication {

    public static void main(String[] args) {
        SpringApplication.run(SampleServiceAApplication.class, args);
    }
}

创建用于测试的 REST 终结点

现在可以将服务注册到服务注册表,但在实现服务终结点之前,无法对其进行验证。 若要创建外部服务可以调用的 RESTful 终结点,请使用以下代码将 ServiceAEndpoint.java 文件添加到项目中。

package com.example.Sample.Service.A;
import java.util.Map;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ServiceAEndpoint {

    @GetMapping("/serviceA")
    public String getServiceA(){
        return "This is a result of Service A";
    }

    @GetMapping("/env")
    public Map<String, String> getEnv(){
        Map<String, String> env = System.getenv();
        return env;
    }
}

构建 Spring Boot 应用程序

你已经有一个简单的服务,接下来,通过运行以下命令来编译和生成源代码:

mvn clean package

部署服务 A 并注册到服务注册表

本部分介绍如何将服务 A 部署到 Azure Spring Apps 企业计划并将其注册到服务注册表。

创建 Azure Spring Apps 应用程序

首先,使用以下命令在 Azure Spring Apps 中创建一个应用程序:

az spring app create \
    --resource-group $RESOURCE_GROUP \
    --service $AZURE_SPRING_APPS_NAME  \
    --name serviceA \
    --instance-count 1 \
    --memory 2Gi \
    --assign-endpoint

--assign-endpoint 参数授权公共 IP 进行验证,并允许从外部网络进行访问。

从应用连接到服务注册表

使用 Spring Boot 创建服务实例并在 Azure Spring Apps 中创建应用程序后,部署应用程序并确认操作。 但是,在此之前,必须将应用程序绑定到服务注册表,以便它可以从注册表中获取连接信息。

通常,Eureka 客户端需要在 Spring Boot 应用程序的 application.properties 配置文件中写入以下连接信息设置,以便连接到服务器:

eureka.client.service-url.defaultZone=http://eureka:8761/eureka/

但是,如果直接在应用程序中写入这些设置,那么每次服务注册表服务器更改时都需要重新编辑和重新生成项目。 为避免这项工作,Azure Spring Apps 允许应用程序通过绑定到服务注册表来获取连接信息。 具体来说,将应用程序绑定到服务注册表后,可以从 Java 环境变量中获取服务注册表连接信息 (eureka.client.service-url.defaultZone)。 这样,便可以在应用程序启动时,通过加载环境变量的内容来连接服务注册表。

在实践中,可将以下环境变量添加到 JAVA_TOOL_OPTIONS 变量中:

-Deureka.client.service-url.defaultZone=https://$AZURE_SPRING_APPS_NAME.svc.azuremicroservices.io/eureka/default/eureka

将服务绑定到服务注册表

使用以下命令将服务绑定到 Azure 服务注册表,使其能够连接到服务器。

az spring service-registry bind \
    --resource-group $RESOURCE_GROUP \
    --service $AZURE_SPRING_APPS_NAME \
    --app serviceA

也可以从 Azure 门户设置应用程序绑定,如以下屏幕截图所示:

Azure 门户的屏幕截图,其中显示了“服务注册表”页,并突出显示了了“应用绑定”下拉菜单。

注意

当服务注册表状态发生变化时,这些更改需要几分钟时间才能传播到所有应用程序。

如果更改绑定/取消绑定状态,则需要重新启动或重新部署应用程序。

现在,可以使用以下命令选择在创建新应用时,将应用程序直接绑定到服务注册表:

az spring app create \ 
    --resource-group <resource-group> \ 
    --service <service-name> \ 
    --name <app-name> \ 
    --bind-service-registry

也可以从 Azure 门户设置应用程序绑定,如以下屏幕截图所示:

Azure 门户中“创建应用程序”页的屏幕截图,其中突出显示了“绑定”下拉列表。

将应用程序部署到 Azure Spring Apps

你已经绑定了应用程序,接下来需要将 Spring Boot 项目文件 Sample-Service-A-A-0.0.1-SNAPSHOT.jar 部署到 Azure Spring Apps。 若要进行部署,请使用以下命令:

az spring app deploy \
    --resource-group $RESOURCE_GROUP \
    --service $AZURE_SPRING_APPS_NAME \
    --name serviceA \
    --artifact-path ./target/Sample-Service-A-0.0.1-SNAPSHOT.jar \
    --jvm-options="-Xms1024m -Xmx1024m"

使用以下命令查看部署是否成功。

az spring app list \
    --resource-group $RESOURCE_GROUP \
    --service $AZURE_SPRING_APPS_NAME \
    --output table

此命令会生成类似于以下示例的输出。

Name                      Location       ResourceGroup           Public Url                                                           Production Deployment    Provisioning State    CPU    Memory    Running Instance    Registered Instance    Persistent Storage    Bind Service Registry    Bind Application Configuration Service
------------------------  -------------  ----------------------  -------------------------------------------------------------------  -----------------------  --------------------  -----  --------  ------------------  ---------------------  --------------------  -----------------------  ----------------------------------------
servicea                  southeastasia  $RESOURCE_GROUP         https://$AZURE_SPRING_APPS_NAME-servicea.azuremicroservices.io       default                  Succeeded             1      2Gi       1/1                 N/A                    -                     default                  -

确认服务 A 应用程序正在运行

上一个命令的输出包含服务的公共 URL。 若要访问 RESTful 终结点,请将 /serviceA 追加到 URL,如以下命令所示:

curl https://$AZURE_SPRING_APPS_NAME-servicea.azuremicroservices.io/serviceA

此命令生成以下输出。

This is a result of Service A

服务 A 包括一个显示环境变量列表的 RESTful 终结点。 使用 /env 访问终结点以查看环境变量,如以下命令所示:

curl https://$AZURE_SPRING_APPS_NAME-servicea.azuremicroservices.io/env

此命令生成以下输出。

"JAVA_TOOL_OPTIONS":"-Deureka.client.service-url.defaultZone=https://$AZURE_SPRING_APPS_NAME.svc.azuremicroservices.io/eureka/default/eureka

如你所看到的,eureka.client.service-url.defaultZone 将添加到 JAVA_TOOL_OPTIONS。 通过这种方式,应用程序可以将服务注册到服务注册表,并使其可用于其他服务。

现在可以将服务注册到 Azure Spring Apps 中的服务注册表(Eureka 服务器)。 其他服务现在可以使用服务注册表访问该服务。

实现通过服务注册表访问服务 A 的新服务 B

使用 Spring Boot 实现服务 B

导航到 Spring Initializr,为服务 B 创建一个新项目。此链接使用以下 URL 初始化设置:

https://start.spring.io/#!type=maven-project&language=java&packaging=jar&groupId=com.example&artifactId=Sample%20Service%20B&name=Sample%20Service%20B&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.Sample%20Service%20B&dependencies=web,cloud-eureka

然后,选择 GENERATE 以获取新项目。

将服务 B 实现为服务注册表客户端(Eureka 客户端)

与服务 A 一样,将 @EnableEurekaClient 注释添加到服务 B,以将其配置为 Eureka 客户端。

package com.example.Sample.Service.B;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class SampleServiceBApplication {

    public static void main(String[] args) {
        SpringApplication.run(SampleServiceBApplication.class, args);
    }
}

在服务 B 中实现服务终结点

接下来,实现一个调用服务 A 的新服务终结点 (/invoke-serviceA)。使用以下代码将 ServiceBEndpoint.java 文件添加到项目中。

package com.example.Sample.Service.B;
import java.util.List;
import java.util.stream.Collectors;
import com.netflix.discovery.EurekaClient;
import com.netflix.discovery.shared.Application;
import com.netflix.discovery.shared.Applications;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class ServiceBEndpoint {
    @Autowired
    private EurekaClient discoveryClient;

    @GetMapping(value = "/invoke-serviceA")
    public String invokeServiceA()
    {
        RestTemplate  restTemplate = new RestTemplate();
        String response = restTemplate.getForObject("http://servicea/serviceA",String.class);
        return "INVOKE SERVICE A FROM SERVICE B: " + response;
    }

    @GetMapping(value = "/list-all")
    public List<String> listsAllServices() {
        Applications applications = discoveryClient.getApplications();
        List<Application> registeredApplications = applications.getRegisteredApplications();
        List<String> appNames = registeredApplications.stream().map(app -> app.getName()).collect(Collectors.toList());
        return appNames;
    }
}

为简单起见,此示例使用 RestTemplate。 终结点返回包含另一个字符串 (INVOKE SERVICE A FROM SERVICE B: ") 的响应字符串,以表明它是由服务 B 调用的。

此示例还实现了另一个终结点 (/list-all) 以进行验证。 此实现可确保服务与服务注册表正确通信。 你可以调用此终结点来获取服务注册表中注册的应用程序列表。

此示例调用服务 A 作为 http://servicea。 服务名称是在创建 Azure Spring Apps 应用程序期间指定的名称。 (例如:az spring app create --name ServiceA。)应用程序名称与在服务注册表中注册的服务名称匹配,以便更轻松地管理服务名称。

生成服务 B

使用以下命令生成项目。

mvn clean package

将服务 B 部署到 Azure Spring Apps

使用以下命令在 Azure Spring Apps 中创建应用程序以部署服务 B。

az spring app create \
    --resource-group $RESOURCE_GROUP \
    --service $AZURE_SPRING_APPS_NAME \
    --name serviceB \
    --instance-count 1 \
    --memory 2Gi \
    --assign-endpoint

接下来,使用以下命令将应用程序绑定到服务注册表。

az spring service-registry bind \
    --resource-group $RESOURCE_GROUP \
    --service $AZURE_SPRING_APPS_NAME \
    --app serviceB

接下来,使用以下命令部署服务。

az spring app deploy \
    --resource-group $RESOURCE_GROUP \
    --service $AZURE_SPRING_APPS_NAME \
    --name serviceB \
    --artifact-path ./target/Sample-Service-B-0.0.1-SNAPSHOT.jar \
    --jvm-options="-Xms1024m -Xmx1024m"

接下来,使用以下命令检查应用程序的状态。

az spring app list \
    --resource-group $RESOURCE_GROUP \
    --service $AZURE_SPRING_APPS_NAME \
    --output table

如果服务 A 和服务 B 部署正确,此命令将生成类似于以下示例的输出。

Name      Location       ResourceGroup           Public Url                                                       Production Deployment    Provisioning State    CPU    Memory    Running Instance    Registered Instance    Persistent Storage    Bind Service Registry    Bind Application Configuration Service
--------  -------------  ----------------------  ---------------------------------------------------------------  -----------------------  --------------------  -----  --------  ------------------  ---------------------  --------------------  -----------------------  ----------------------------------------
servicea  southeastasia  SpringCloud-Enterprise  https://$AZURE_SPRING_APPS_NAME-servicea.azuremicroservices.io  default                  Succeeded             1      2Gi       1/1                 1/1                    -                     default                  -
serviceb  southeastasia  SpringCloud-Enterprise  https://$AZURE_SPRING_APPS_NAME-serviceb.azuremicroservices.io  default                  Succeeded             1      2Gi       1/1                 1/1                    -                     default                  -

从服务 B 调用服务 A

上一个命令的输出包含服务的公共 URL。 若要访问 RESTful 终结点,请将 /invoke-serviceA 追加到 URL,如以下命令所示:

curl https://$AZURE_SPRING_APPS_NAME-serviceb.azuremicroservices.io/invoke-serviceA

该命令生成以下输出:

INVOKE SERVICE A FROM SERVICE B: This is a result of Service A

从服务注册表获取一些信息

最后,访问 /list-all 终结点并从服务注册表检索一些信息。 以下命令将检索服务注册表中注册的服务列表。

curl https://$AZURE_SPRING_APPS_NAME-serviceb.azuremicroservices.io/list-all

此命令生成以下输出。

["SERVICEA","EUREKA-SERVER","SERVICEB"]

这样,便可以根据需要从程序中获取详细信息。

创建服务后启用/禁用服务注册表

可以在创建服务后使用 Azure 门户或 Azure CLI 启用和禁用服务注册表。 在禁用服务注册表之前,需要取消所有应用与它的绑定。

使用以下步骤通过 Azure 门户启用或禁用服务注册表:

  1. 导航到服务资源,然后选择“服务注册表”。
  2. 选择“管理”。
  3. 选择或取消选择“启用服务注册表”,然后选择“保存”。
  4. 现在可以在“服务注册表”页上查看服务注册表的状态。

后续步骤