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 服务管理。架构图如下:
源码
如果你想自己尝试,可以克隆我的 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-cosmos
。spring-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
(主键)、number
和 customerId
(分区 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” 部分看到之前创建的容器。
为了获取连接 key,需要进入左侧菜单中的 “Data Explorer” 项目。然后选择 “Connect” 标题。你可以在目标窗口中找到 Key。
可以使用 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.key
、spring.cloud.azure.cosmos.database
和 spring.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 设置,以启用健康检查详情和其他管理端点。
就这样。现在,可以运行应用程序了。只需将其连接到 Azure App Configuration 服务。为此,需要获取其连接端点和凭证。你可以转到 “Settings” 部分的 “Access keys” 菜单项。然后复制 “Connection string” 字段中的值,如下图所示。或者,也可以通过执行以下 CLI 命令获得相同信息:az appconfig credential list --name sample-spring-cloud-config
。
将该值保存在 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 加载属性源:
如果一切正常,你的应用程序将从 Azure App Configuration 加载设置并连接到 Cosmos DB 实例:
启动应用后,监听本地 8080 端口。可以通过 /swagger-ui.html
路径访问 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 错误?
来看看发生了什么。如果你看看 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” 菜单项。如你所见,默认情况下,功能标志是禁用的。这意味着该功能未激活,端点已禁用
你可以点击复选框按钮启用该功能,然后重新启动应用。之后,DELETE
端点就可以使用了。
在 Azure 上部署 Spring Cloud 应用
我们可以通过几种不同的方式将示例应用部署到 Azure。这里选择专门针对 Spring Boot 的服务 - Azure Spring Apps。
Azure 门户的安装非常简单。我就不细说了。我们的实例(集群)名称是 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
你应该会看到类似如下的输出:
这个实例的名字听起来熟悉吗?它其实就是 Kubernetes。Azure Spring Apps 服务使用 Azure Container Apps 运行容器。另一方面,Azure Container Apps 托管在 Kubernetes 集群上。但这些都是细节。重要的是,我们的应用已经部署在 Azure 上。
我们可以显示 account-service
app 的详细信息。该应用在 Public URL 下公开。只需复制链接即可。
来看看配置部分。如你所见,它包含连接到 App Configuration 端点的连接字符串。
我们可以打开 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