你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
如何使用 IaC 工具创建连接
只需单击几下或使用几个命令,服务连接器就能帮助用户将其计算服务连接到目标后端服务。 当从开始阶段进入生产阶段时,用户还需要在其 CI/CD 管道中从使用手动配置过渡到使用基础结构即代码 (IaC) 模板。
本指南介绍如何将联网的 Azure 服务转换为 IaC 模板。
先决条件
- 本指南假定你已了解服务连接器 IaC 限制。
解决方案概述
将基础结构转化为 IaC 模板通常涉及两个主要部分:预配源服务和目标服务的逻辑,以及建立连接的逻辑。 若要实现预配源服务和目标服务的逻辑,有两个选项:
- 从头开始创建模板
- 从 Azure 导出模板并对其进行优化
若要实现生成连接的逻辑,有三个选项:
- 使用服务连接器并在应用程序配置中存储配置
- 在模板中使用服务连接器
- 使用模板逻辑直接配置源服务和目标服务
这些不同选项的组合可以生成不同的解决方案。 由于服务连接器的 IaC 限制,我们建议按照以下顺序实现以下解决方案。 若要应用这些解决方案,必须了解 IaC 工具和模板创建语法。
解决方案 | 预配源和目标 | 生成连接 | 适用场景 | 优点 | 缺点 |
---|---|---|---|---|---|
1 | 从头开始创建 | 使用服务连接器并在应用程序配置中存储配置 | 在允许实时流量之前,对云资源进行有效性检查 | - 模板简单易读 - 服务连接器带来额外的价值 - 服务连接器不会引入 IaC 问题 |
- 需要额外的依赖项才能从应用程序配置读取配置 - 检查云资源有效性的成本 |
2 | 从头开始创建 | 使用服务连接器 | 在允许实时流量之前,对云资源进行有效性检查 | - 模板简单易读 - 服务连接器带来额外的价值 |
- 检查云资源有效性的成本 |
3 | 从头开始创建 | 直接在模板中配置源服务和目标服务 | 没有对云资源进行有效性检查 | - 模板简单易读 | - 服务连接器功能不可用 |
4 | 导出和优化 | 使用服务连接器并在应用程序配置中存储配置 | 在允许实时流量之前,对云资源进行有效性检查 | - 资源与云中的资源完全相同 - 服务连接器带来额外的价值 - 服务连接器不会引入 IaC 问题 |
- 需要额外的依赖项才能从应用程序配置读取配置 - 检查云资源有效性的成本 - 仅支持 ARM 模板 - 了解和优化模板所需的工作 |
5 | 导出和优化 | 使用服务连接器 | 在允许实时流量之前,对云资源进行有效性检查 | - 资源与云中的资源完全相同 - 服务连接器带来额外的价值 |
- 检查云资源有效性的成本 - 仅支持 ARM 模板 - 了解和优化模板所需的工作 |
6 | 导出和优化 | 直接在模板中配置源服务和目标服务 | 没有对云资源进行有效性检查 | - 资源与云中的资源完全相同 | - 仅支持 ARM 模板 - 了解和优化模板的工作 - 服务连接器功能不可用 |
创作模板
以下部分介绍如何使用 Bicep 创建 Web 应用和存储帐户,并将它们与系统分配的标识连接起来。 它展示了如何使用服务连接器和模板逻辑来实现这一点。
预配源服务和目标服务
从头开始创建
从头开始创建模板是预配源服务和目标服务的首选和推荐方式,因为这种方式易于上手,而且可使模板简单易读。 下面是一个示例,该示例使用一组最少的参数创建一个 Web 应用和一个存储帐户。
// This template creates a webapp and a storage account.
// In order to make it more readable, we use only the minimal set of parameters to create the resources.
param location string = resourceGroup().location
// App Service plan parameters
param planName string = 'plan_${uniqueString(resourceGroup().id)}'
param kind string = 'linux'
param reserved bool = true
param sku string = 'B1'
// Webapp parameters
param webAppName string = 'webapp-${uniqueString(resourceGroup().id)}'
param linuxFxVersion string = 'PYTHON|3.8'
param identityType string = 'SystemAssigned'
param appSettings array = []
// Storage account parameters
param storageAccountName string = 'account${uniqueString(resourceGroup().id)}'
// Create an app service plan
resource appServicePlan 'Microsoft.Web/serverfarms@2022-09-01' = {
name: planName
location: location
kind: kind
sku: {
name: sku
}
properties: {
reserved: reserved
}
}
// Create a web app
resource appService 'Microsoft.Web/sites@2022-09-01' = {
name: webAppName
location: location
properties: {
serverFarmId: appServicePlan.id
siteConfig: {
linuxFxVersion: linuxFxVersion
appSettings: appSettings
}
}
identity: {
type: identityType
}
}
// Create a storage account
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: storageAccountName
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
}
导出和优化
如果要预配的资源与云中的资源完全相同,那么从 Azure 导出模板可能是另一个可选方案。 这种方法的两个前提是:资源存在于 Azure 中,并且 IaC 使用 ARM 模板。 Export template
按钮通常位于 Azure 门户的边栏底部。 导出的 ARM 模板反映了资源的当前状态,包括服务连接器配置的设置。 通常需要了解资源属性来优化导出的模板。
生成连接逻辑
使用服务连接器并在应用程序配置中存储配置
使用应用程序配置来存储配置自然支持 IaC 方案。 因此,建议尽可能使用此方法生成 IaC 模板。
有关简单的门户说明,请参阅此应用程序配置教程。 要将此功能添加到 bicep 文件中,请在服务连接器有效负载中添加应用程序配置 ID。
resource webApp 'Microsoft.Web/sites@2022-09-01' existing = {
name: webAppName
}
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = {
name: storageAccountName
}
resource appConfiguration 'Microsoft.AppConfiguration/configurationStores@2023-03-01' existing = {
name: appConfigurationName
}
resource serviceConnector 'Microsoft.ServiceLinker/linkers@2022-05-01' = {
name: connectorName
scope: webApp
properties: {
clientType: 'python'
targetService: {
type: 'AzureResource'
id: storageAccount.id
}
authInfo: {
authType: 'systemAssignedIdentity'
}
configurationInfo: {
configurationStore: {
appConfigurationId: appConfiguration.id
}
}
}
}
使用服务连接器
如果服务连接器 IaC 限制对你的方案不会产生负面影响,那么使用服务连接器在源服务和目标服务之间创建连接是首选和推荐的方法。 服务连接器简化了模板并提供了附加功能(例如连接运行状况验证),这些功能在直接通过模板逻辑构建连接时不可用。
// The template builds a connection between a webapp and a storage account
// with a system-assigned identity using Service Connector
param webAppName string = 'webapp-${uniqueString(resourceGroup().id)}'
param storageAccountName string = 'account${uniqueString(resourceGroup().id)}'
param connectorName string = 'connector_${uniqueString(resourceGroup().id)}'
// Get an existing webapp
resource webApp 'Microsoft.Web/sites@2022-09-01' existing = {
name: webAppName
}
// Get an existing storage
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = {
name: storageAccountName
}
// Create a Service Connector resource for the webapp
// to connect to a storage account using system identity
resource serviceConnector 'Microsoft.ServiceLinker/linkers@2022-05-01' = {
name: connectorName
scope: webApp
properties: {
clientType: 'python'
targetService: {
type: 'AzureResource'
id: storageAccount.id
}
authInfo: {
authType: 'systemAssignedIdentity'
}
}
}
有关创建服务连接器资源时所需属性和值的格式,请查看如何提供正确的参数。 还可以预览和下载 ARM 模板,以便在 Azure 门户中创建服务连接器资源时参考。
使用模板逻辑
对于服务连接器 IaC 限制比较重要的情况,可以考虑直接使用模板逻辑建立连接。 下面的模板是一个示例,展示了如何使用系统分配的标识将存储帐户连接到 Web 应用。
// The template builds a connection between a webapp and a storage account
// with a system-assigned identity without using Service Connector
param webAppName string = 'webapp-${uniqueString(resourceGroup().id)}'
param storageAccountName string = 'account${uniqueString(resourceGroup().id)}'
param storageBlobDataContributorRole string = 'ba92f5b4-2d11-453d-a403-e96b0029c9fe'
// Get an existing webapp
resource webApp 'Microsoft.Web/sites@2022-09-01' existing = {
name: webAppName
}
// Get an existing storage account
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = {
name: storageAccountName
}
// Operation: Enable system-assigned identity on the source service
// No action needed as this is enabled when creating the webapp
// Operation: Configure the target service's endpoint on the source service's app settings
resource appSettings 'Microsoft.Web/sites/config@2022-09-01' = {
name: 'appsettings'
parent: webApp
properties: {
AZURE_STORAGEBLOB_RESOURCEENDPOINT: storageAccount.properties.primaryEndpoints.blob
}
}
// Operation: Configure firewall on the target service to allow the source service's outbound IPs
// No action needed as storage account allows all IPs by default
// Operation: Create role assignment for the source service's identity on the target service
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
scope: storageAccount
name: guid(resourceGroup().id, storageBlobDataContributorRole)
properties: {
roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', storageBlobDataContributorRole)
principalId: webApp.identity.principalId
}
}
在直接使用模板逻辑建立连接时,了解服务连接器对每种身份验证类型执行的操作至关重要,因为模板逻辑等效于服务连接器后端操作。 下表展示了针对每种身份验证类型,需要转换为模板逻辑的操作详细信息。
身份验证类型 | 服务连接器操作 |
---|---|
机密/连接字符串 | - 在源服务的应用设置上配置目标服务的连接字符串 - 在目标服务上配置防火墙以允许源服务的出站 IP |
系统分配的托管标识 | - 在源服务的应用设置上配置目标服务的终结点 - 在目标服务上配置防火墙以允许源服务的出站 IP - 在源服务上启用系统分配的标识 - 在目标服务上为源服务标识创建角色分配 |
用户分配的托管标识 | - 在源服务的应用设置上配置目标服务的终结点 - 在目标服务上配置防火墙以允许源服务的出站 IP - 将用户分配的标识绑定到源服务 - 在目标服务上为用户分配的标识创建角色分配 |
服务主体 | - 在源服务的应用设置上配置目标服务的终结点 - 在源服务的应用设置上配置服务主体的 appId 和机密 - 在目标服务上配置防火墙以允许源服务的出站 IP - 在目标服务上为服务主体创建角色分配 |