Spring Cloud Azure 教程

本文将会带你了解如何使用 Spring Cloud 来简化 Spring Boot 应用与 Azure 服务之间的整合,以及如何利用 Azure Spring Apps 服务在 Azure 上部署、运行和管理应用。本文中的示例 Spring Boot 应用将数据存储在 Azure Cosmos DB 服务中,并在 Public URL 下公开一些 REST 端点。我们可以在本地运行它并连接远程服务,也可以将它部署到云上并在同一虚拟网络下连接这些内部服务。

如果你需要了解 Spring Cloud,可以参阅 “Spring Boot 3 整合 Spring Cloud 开发微服务应用”。也推荐看一看 Spring Cloud Azure 文档,以便对主要概念有一个基本的了解。

架构

我们的架构非常简单。如上所述,我们有一个在 Azure 上运行并连接 Cosmos DB 的 Spring Boot 应用(图中为 account-service)。它提供一些 REST 端点,用于添加、删除或搜索由 Cosmos DB 支持的账户。它还将所需的全部配置(如 Cosmos DB 地址和凭证)存储在 Azure App Configuration 服务中。该应用程序由 Azure Spring Apps 服务管理。架构图如下:

spring-cloud-azure 架构

源码

如果你想自己尝试,可以克隆我的 GitHub 仓库。本文使用的 Spring Boot 应用位于 microservices/account-service 目录中。进入该目录后,只需按照说明操作即可。

在开始之前有一些先决条件。你需要在本地计算机上安装 JDK17+ 和 Maven。你还需要在 Azure 上拥有一个账户,并使用 az CLI 与该账户进行交互。为了在 Azure 上部署应用,我们使用 azure-spring-apps-maven-plugin,该插件需要 az CLI

依赖

首先,来看看所需的 Maven 依赖列表。首先,需要添加 Spring Boot Web Starter,以便通过 Spring MVC 模块启用 REST 支持。为了与 Cosmos DB 整合,我们将使用 Spring Data Repository。Spring Cloud Azure 为此提供了专用 Starter spring-cloud-azure-starter-data-cosmosspring-cloud-azure-starter-actuator 模块是可选的。它会在 /actuator/health 端点中启用 Cosmos DB 的 Health Indicator。之后,添加与 Azure App Configuration 服务整合的 Starter。最后,可以添加 Springdoc OpenAPI,该项目负责生成 REST API 文档。

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>spring-cloud-azure-starter-actuator</artifactId>
  </dependency>
  <dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>spring-cloud-azure-starter-data-cosmos</artifactId>
  </dependency>
  <dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>spring-cloud-azure-starter-appconfiguration-config</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
    <version>2.2.0</version>
  </dependency>
</dependencies>

Spring Cloud 和 Azure Cosmos DB

加入支持 Cosmos DB 的 Spring Data 模块后,就可以定义 Model 类了。Account 类包含三个字符串字段:id(主键)、numbercustomerId(分区 key)。分区 key 负责将数据分成不同的子集,称为逻辑分区。Model 必须使用 @Container 进行注解。注解中的 containerName 参数对应于在 Azure 中创建的 Cosmos DB 容器名称。

@Container(containerName = "accounts")
public class Account {
   @Id
   @GeneratedValue
   private String id;
   private String number;
   @PartitionKey
   private String customerId;

   // getter 和 setter ...
}

现在,在 Azure 中准备好环境。使用 az login CLI 命令登录后,创建资源组。组的名称是 sample-spring-cloud。位置取决于你的偏好。对我来说是 eastus

az group create -l eastus -n sample-spring-cloud

然后,创建一个新的 Azure Cosmos DB 数据库账户。我的账户名称是 sample-pminkows-cosmosdb,放在我们的 sample-spring-cloud 资源组中。保留所有其他参数的默认值。但你可以考虑覆盖某些参数,以降低实例成本。例如,可以使用 --backup-redundancy 参数设置本地备份冗余类型。

az cosmosdb create -n sample-pminkows-cosmosdb -g sample-spring-cloud

启用数据库账户后,就可以创建一个数据库实例。我们的数据库名称是 sampled。当然,它必须放在之前创建的 sample-pminkows-cosmosdb Cosmos DB 账户中。

$ az cosmosdb sql database create \
    -a sample-pminkows-cosmosdb \
    -n sampledb \
    -g sample-spring-cloud

最后,需要在数据库中创建一个容器。容器的名称应与 Model 类中声明的 containerName 字段的值相同。还必须设置分区 Key 路径,即 Account 类中的 customerId 字段。

$ az cosmosdb sql container create \
    -a sample-pminkows-cosmosdb \
    -g sample-spring-cloud \
    -n accounts \
    -d sampledb \
    -p /customerId

Azure 方面一切就绪。回到源码。创建 Spring Data Repository 接口与数据库交互。它必须继承 Spring Cloud Azure 提供的 CosmosRepository 接口。它定义了一个额外的方法,用于通过 customerId 字段进行搜索。

public interface AccountRepository extends CosmosRepository<Account, String> {
   List<Account> findByCustomerId(String customerId);
}

最后,可以创建一个带有端点实现的 @RestController。注入并使用 AccountRepository Bean。

@RestController
@RequestMapping("/accounts")
public class AccountController {

   private final static Logger LOG = LoggerFactory
      .getLogger(AccountController.class);
   private final AccountRepository repository;

   public AccountController(AccountRepository repository) {
      this.repository = repository;
   }

   @PostMapping
   public Account add(@RequestBody Account account) {
      LOG.info("add: {}", account.getNumber());
      return repository.save(account);
   }

   @GetMapping("/{id}")
   public Account findById(@PathVariable String id) {
      LOG.info("findById: {}", id);
      return repository.findById(id).orElseThrow();
   }

   @GetMapping
   public List<Account> findAll() {
      List<Account> accounts = new ArrayList<>();
      repository.findAll().forEach(accounts::add);
      return accounts;
   }

   @GetMapping("/customer/{customerId}")
   public List<Account> findByCustomerId(@PathVariable String customerId) {
      LOG.info("findByCustomerId: {}", customerId);
      return repository.findByCustomerId(customerId);
   }
}

Spring Cloud 和 Azure App Configuration

完成应用的实现后,就可以运行它并连接 Cosmos DB。当然,需要先设置连接 URL 和凭证。切换到 Azure 门户。在主菜单中找到 “Azure Cosmos DB” Service。然后点击你的数据库账户。你会看到如下所示的端点地址。你还可以在 “Containers” 部分看到之前创建的容器。

Azure 门户

为了获取连接 key,需要进入左侧菜单中的 “Data Explorer” 项目。然后选择 “Connect” 标题。你可以在目标窗口中找到 Key。

spring-cloud-azure-cosmosdb

可以使用 spring.cloud.azure.cosmos.* 属性轻松设置所有所需的连接参数。不过,我希望将所有配置设置存储在 Azure 上。Spring Cloud 内置支持 Azure App Configuration 服务。我们已经包含了所需的 Spring Cloud Starter。因此,现在需要启用 Azure App Configuration 服务,并将我们的属性放入存储中。以下是创建名为 sample-spring-cloud-config 的 App Configuration 的命令示例:

$ az appconfig create \
    -g sample-spring-cloud \
    -n sample-spring-cloud-config \
    -l eastus \
    --sku Standard

创建 App Configuration 后,就可以将配置设置放入 Key/Value 表单中。默认情况下,Spring Cloud Azure 会加载以 Key /application/ 开头的配置。我们需要添加三个 Spring Cloud 属性:spring.cloud.azure.cosmos.keyspring.cloud.azure.cosmos.databasespring.cloud.azure.cosmos.endpoint

$ az appconfig kv set \
    -n sample-spring-cloud-config \
    --key /application/spring.cloud.azure.cosmos.key \
    --value <YOUR_PRIMARY_KEY>

$ az appconfig kv set \
    -n sample-spring-cloud-config \
    --key /application/spring.cloud.azure.cosmos.database \
    --value sampledb

$ az appconfig kv set \
    -n sample-spring-cloud-config \
    --key /application/spring.cloud.azure.cosmos.endpoint \
    --value <YOUR_ENDPOINT_URI>

切换到 Azure 门户检查配置设置。我们需要在主仪表板中找到 “App Configuration” 服务。然后进入 sample-spring-cloud-config 详情,选择 “Configuration explorer”(配置资源管理器)菜单项。你的所有应用属性都应该以 /application/ 为前缀。这里还覆盖了一些 Spring Actuator 设置,以启用健康检查详情和其他管理端点。

spring-cloud-azure-app-configuration

就这样。现在,可以运行应用程序了。只需将其连接到 Azure App Configuration 服务。为此,需要获取其连接端点和凭证。你可以转到 “Settings” 部分的 “Access keys” 菜单项。然后复制 “Connection string” 字段中的值,如下图所示。或者,也可以通过执行以下 CLI 命令获得相同信息:az appconfig credential list --name sample-spring-cloud-config

azure 控制台

将该值保存在 APP_CONFIGURATION_CONNECTION_STRING 环境变量中。之后,只需在 src/main/resources 目录中创建 Spring bootstrap.properties 文件,其中包含 spring.cloud.azure.appconfiguration.stores[0].connection-string 属性。

# src/main/resources/bootstrap.properties
spring.cloud.azure.appconfiguration.stores[0].connection-string=${APP_CONFIGURATION_CONNECTION_STRING}

在本地运行 Spring Boot 应用

最后,可以运行示例 Spring Boot 应用。现在,只在本地运行它。因此,它将连接到部署在云上的 Azure App Configuration 和 Cosmos DB。

执行以下 Maven 命令来启动应用程序:

mvn clean spring-boot:run

启动应用后,你会看到它从 Azure Store 加载属性源:

Spring Boot 日志

如果一切正常,你的应用程序将从 Azure App Configuration 加载设置并连接到 Cosmos DB 实例:

spring-cloud-azure 日志

启动应用后,监听本地 8080 端口。可以通过 /swagger-ui.html 路径访问 Swagger UI:

swagger UI

可以使用如下所示的 curl 命令来获取数据:

$ curl -X 'POST' 'http://localhost:8080/accounts' \
    -H 'Content-Type: application/json' \
    -d '{"number": "1234567893","customerId": "1"}'
{"id":"5301e9dd-0556-40b7-9ea3-96975492f00c","number":"1234567893","customerId":"1"}

这样,就可以找到某个 customer 拥有的账户:

curl http://localhost:8080/accounts/customer/1

还可以通过调用 DELETE /account/{id} 端点删除现有账户。此时,却收到了 HTTP 404 Not Found 错误?

HTTP 404 Not Found

来看看发生了什么。如果你看看 AccountController 的实现,就会发现 DELETE 端点的方法,对吧?同时,我添加了一个注解为 @FeatureGate 的方法。该注解由 Spring Cloud Azure 提供。下面的代码片段展示了使用 Azure App Configuration 进行功能管理的过程。事实上,我使用的是 “Feature Gate” 功能,它允许我们只有在 Azure 端启用了某个功能时才调用端点。我们的功能名称是 delete-account

@DeleteMapping("/{id}")
@FeatureGate(feature = "delete-account")
public void deleteById(@PathVariable String id) {
   repository.deleteById(id);
}

现在,我们唯一需要做的就是在 sample-spring-cloud-config App Configuration 中添加一个新功能。

az appconfig feature set -n sample-spring-cloud-config --feature test-2

切换到 Azure 门户。转到 “Operations” 部分的 “Feature manager” 菜单项。如你所见,默认情况下,功能标志是禁用的。这意味着该功能未激活,端点已禁用

spring-cloud-azure Feature 禁用

你可以点击复选框按钮启用该功能,然后重新启动应用。之后,DELETE 端点就可以使用了。

在 Azure 上部署 Spring Cloud 应用

我们可以通过几种不同的方式将示例应用部署到 Azure。这里选择专门针对 Spring Boot 的服务 - Azure Spring Apps

Azure Spring Apps

Azure 门户的安装非常简单。我就不细说了。我们的实例(集群)名称是 sample-spring-cloud-apps。仅此,无需知道更多信息就能在那里部署应用。

sample-spring-cloud-apps

Azure 为部署应用提供了多个 Maven 插件。对于 Azure Spring 应用,我们应该使用 azure-spring-apps-maven-plugin。我们需要在 clusterName 参数中设置 Azure Spring Apps 实例。我们的应用名称是 account-service。我们还应该选择 SKU 并设置 Azure subscription ID(从 SUBSCRIPTION 环境变量加载)。在 Deployment 部分,我们需要定义所需的资源(RAM 和 CPU)、运行实例的数量、Java 版本,并设置一个包含连接到 Azure App Configuration 实例的连接字符串的环境变量。

<plugin>
  <groupId>com.microsoft.azure</groupId>
  <artifactId>azure-spring-apps-maven-plugin</artifactId>
  <version>1.19.0</version>
  <configuration>
    <subscriptionId>${env.SUBSCRIPTION}</subscriptionId>
    <resourceGroup>sample-spring-cloud</resourceGroup>
    <clusterName>sample-spring-cloud-apps</clusterName>
    <sku>Consumption</sku>
    <appName>account-service</appName>
    <isPublic>true</isPublic>
    <deployment>
      <cpu>0.5</cpu>
      <memoryInGB>1</memoryInGB>
      <instanceCount>1</instanceCount>
      <runtimeVersion>Java 17</runtimeVersion>
      <environment>
        <APP_CONFIGURATION_CONNECTION_STRING>
          ${env.APP_CONFIGURATION_CONNECTION_STRING}
        </APP_CONFIGURATION_CONNECTION_STRING>
      </environment>
      <resources>
        <resource>
          <directory>target/</directory>
          <includes>
            <include>*.jar</include>
          </includes>
        </resource>
      </resources>
    </deployment>
  </configuration>
</plugin>

然后,构建应用,并使用以下命令将其部署到 Azure Spring Apps 上:

mvn clean package azure-spring-apps:deploy

你应该会看到类似如下的输出:

Maven 构建输出

这个实例的名字听起来熟悉吗?它其实就是 Kubernetes。Azure Spring Apps 服务使用 Azure Container Apps 运行容器。另一方面,Azure Container Apps 托管在 Kubernetes 集群上。但这些都是细节。重要的是,我们的应用已经部署在 Azure 上。

部署在 Azure 上的应用

我们可以显示 account-service app 的详细信息。该应用在 Public URL 下公开。只需复制链接即可。

account-service app

来看看配置部分。如你所见,它包含连接到 App Configuration 端点的连接字符串。

连接到 App Configuration 端点的连接字符串

我们可以打开 Swagger UI 并执行一些测试调用。

Swagger UI

最后

本文完,但我计划很快再写几篇关于 Spring Boot 和 Azure 的文章!对于 Spring Boot 开发人员来说,Azure 似乎是一个友好的平台。

本文介绍了如何将 Spring Boot 应用与 Cosmos DB 等最流行的 Azure 服务整合。还介绍了配置管理和 App Configuration 服务的功能标志(“Feature Gate”)等主题。最后,通过 Azure Spring Apps 服务在 Kubernetes 上部署了应用。


Ref:https://piotrminkowski.com/2023/12/07/getting-started-with-spring-cloud-azure