閱讀英文

共用方式為


快速入門:使用 Bicep 建立 Service Fabric 叢集

Azure Service Fabric 是一個分散式系統平台,可讓您輕鬆封裝、部署及管理可調整和可信賴的微服務與容器。 Service Fabric 叢集是一組透過網路連線的虛擬機器,您可以將微服務部署到其中並進行管理。 本文說明如何使用 Bicep 在 Azure 中部署 Service Fabric 測試叢集。

Bicep 是使用宣告式語法來部署 Azure 資源的特定領域語言 (DSL)。 其提供簡潔的語法、可靠的類型安全,並支援程式碼重複使用。 Bicep 能夠為您在 Azure 中的基礎結構即程式碼解決方案,提供最佳的製作體驗。

這個有五個節點的 Windows 叢集會使用自我簽署憑證來加以保護,因此僅適用於教學目的 (而不適用於生產工作負載)。 我們會使用 Azure PowerShell 來部署 Bicep 檔案。

必要條件

如果您沒有 Azure 訂用帳戶,請在開始前建立免費帳戶

安裝 Service Fabric SDK 和 PowerShell 模組

若要完成本快速入門,您需要安裝 Service Fabric SDK 和 PowerShell 模組

下載範例 Bicep 檔案和憑證協助程式指令碼

複製或下載 Azure Resource Manager 快速入門範本存放庫。 或者,從本機的 service-fabric-secure-cluster-5-node-1-nodetype 資料夾複製下列所會用到的檔案:

登入 Azure

登入 Azure,並指定要用來建立 Service Fabric 叢集的訂用帳戶。

# Sign in to your Azure account
Login-AzAccount -SubscriptionId "<subscription ID>"

建立儲存在 Key Vault 中的自我簽署憑證

Service Fabric 使用 X.509 憑證來保護叢集和提供應用程式安全性功能,並使用 Key Vault 來管理這些憑證。 若要成功建立叢集,就需要有叢集憑證以便啟用節點對節點的通訊。 為了建立此快速入門測試叢集,我們將建立自我簽署的憑證來驗證叢集。 生產工作負載所需要的憑證,必須使用已正確設定的 Windows Server 憑證服務來建立,或是來自已核准憑證授權單位 (CA) 中的憑證也可以。

# Designate unique (within cloudapp.azure.com) names for your resources
$resourceGroupName = "SFQuickstartRG"
$keyVaultName = "SFQuickstartKV"

# Create a new resource group for your Key Vault and Service Fabric cluster
New-AzResourceGroup -Name $resourceGroupName -Location SouthCentralUS

# Create a Key Vault enabled for deployment
New-AzKeyVault -VaultName $keyVaultName -ResourceGroupName $resourceGroupName -Location SouthCentralUS -EnabledForDeployment

# Generate a certificate and upload it to Key Vault
.\scripts\New-ServiceFabricClusterCertificate.ps1

指令碼會提示您輸入下列資訊 (請務必修改下列範例值中的 CertDNSNameKeyVaultName):

  • 密碼:Password!1
  • CertDNSName: sfquickstart.southcentralus.cloudapp.azure.com
  • KeyVaultName: SFQuickstartKV
  • KeyVaultSecretName:clustercert

完成時,指令碼就會提供部署所需的參數值。 請務必將這些值儲存在下列變數中,因為這些是部署所需的項目:

$sourceVaultId = "<Source Vault Resource Id>"
$certUrlValue = "<Certificate URL>"
$certThumbprint = "<Certificate Thumbprint>"

檢閱 Bicep 檔案

此快速入門中使用的 Bicep 檔案是來自 Azure 快速入門範本

@description('Location of the Cluster')
param location string = resourceGroup().location

@description('Name of your cluster - Between 3 and 23 characters. Letters and numbers only')
param clusterName string

@description('Remote desktop user Id')
param adminUsername string

@description('Remote desktop user password. Must be a strong password')
@secure()
param adminPassword string

@description('VM image Publisher')
param vmImagePublisher string = 'MicrosoftWindowsServer'

@description('VM image offer')
param vmImageOffer string = 'WindowsServer'

@description('VM image SKU')
param vmImageSku string = '2019-Datacenter'

@description('VM image version')
param vmImageVersion string = 'latest'

@description('Input endpoint1 for the application to use. Replace it with what your application uses')
param loadBalancedAppPort1 int = 80

@description('Input endpoint2 for the application to use. Replace it with what your application uses')
param loadBalancedAppPort2 int = 8081

@description('The store name where the cert will be deployed in the virtual machine')
@allowed([
  'My'
])
param certificateStoreValue string = 'My'

@description('Certificate Thumbprint')
param certificateThumbprint string

@description('Resource Id of the key vault, is should be in the format of /subscriptions/<Sub ID>/resourceGroups/<Resource group name>/providers/Microsoft.KeyVault/vaults/<vault name>')
param sourceVaultResourceId string

@description('Refers to the location URL in your key vault where the certificate was uploaded')
param certificateUrlValue string

@description('Protection level.Three values are allowed - EncryptAndSign, Sign, None. It is best to keep the default of EncryptAndSign, unless you have a need not to')
@allowed([
  'None'
  'Sign'
  'EncryptAndSign'
])
param clusterProtectionLevel string = 'EncryptAndSign'

@description('Instance count for node type')
param nt0InstanceCount int = 5

@description('The drive to use to store data on a cluster node.')
@allowed([
  'OS'
  'Temp'
])
param nodeDataDrive string = 'Temp'

@description('The VM size to use for cluster nodes.')
param nodeTypeSize string = 'Standard_D2_v3'

param tenantId string
param clusterApplication string
param clientapplication string

var dnsName = clusterName
var vmName = 'vm'
var virtualNetworkName = 'VNet'
var addressPrefix = '10.0.0.0/16'
var nicName = 'NIC'
var lbIPName = 'PublicIP-LB-FE'
var overProvision = false
var nt0applicationStartPort = 20000
var nt0applicationEndPort = 30000
var nt0ephemeralStartPort = 49152
var nt0ephemeralEndPort = 65534
var nt0fabricTcpGatewayPort = 19000
var nt0fabricHttpGatewayPort = 19080
var subnet0Name = 'Subnet-0'
var subnet0Prefix = '10.0.0.0/24'
var subnet0Ref = resourceId('Microsoft.Network/virtualNetworks/subnets/', virtualNetworkName, subnet0Name)
var supportLogStorageAccountName = '${uniqueString(resourceGroup().id)}2'
var applicationDiagnosticsStorageAccountName = '${uniqueString(resourceGroup().id)}3'
var lbName = 'LB-${clusterName}-${vmNodeType0Name}'
var lbIPConfig0 = resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations/', lbName, 'LoadBalancerIPConfig')
var lbPoolID0 = resourceId('Microsoft.Network/loadBalancers/backendAddressPools', lbName, 'LoadBalancerBEAddressPool')
var lbProbeID0 = resourceId('Microsoft.Network/loadBalancers/probes', lbName, 'FabricGatewayProbe')
var lbHttpProbeID0 = resourceId('Microsoft.Network/loadBalancers/probes', lbName, 'FabricHttpGatewayProbe')
var lbNatPoolID0 = resourceId('Microsoft.Network/loadBalancers/inboundNatPools', lbName, 'LoadBalancerBEAddressNatPool')
var vmNodeType0Name = toLower('NT1${vmName}')
var vmNodeType0Size = nodeTypeSize

resource supportLogStorageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
  name: supportLogStorageAccountName
  location: location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'Storage'
  tags: {
    resourceType: 'Service Fabric'
    clusterName: clusterName
  }
  properties: {}
}

resource applicationDiagnosticsStorageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
  name: applicationDiagnosticsStorageAccountName
  location: location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'Storage'
  tags: {
    resourceType: 'Service Fabric'
    clusterName: clusterName
  }
  properties: {}
}

resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-09-01' = {
  name: virtualNetworkName
  location: location
  tags: {
    resourceType: 'Service Fabric'
    clusterName: clusterName
  }
  properties: {
    addressSpace: {
      addressPrefixes: [
        addressPrefix
      ]
    }
    subnets: [
      {
        name: subnet0Name
        properties: {
          addressPrefix: subnet0Prefix
        }
      }
    ]
  }
}

resource lbIP 'Microsoft.Network/publicIPAddresses@2023-09-01' = {
  name: lbIPName
  location: location
  tags: {
    resourceType: 'Service Fabric'
    clusterName: clusterName
  }
  properties: {
    dnsSettings: {
      domainNameLabel: dnsName
    }
    publicIPAllocationMethod: 'Dynamic'
  }
}

resource lb 'Microsoft.Network/loadBalancers@2023-09-01' = {
  name: lbName
  location: location
  tags: {
    resourceType: 'Service Fabric'
    clusterName: clusterName
  }
  properties: {
    frontendIPConfigurations: [
      {
        name: 'LoadBalancerIPConfig'
        properties: {
          publicIPAddress: {
            id: lbIP.id
          }
        }
      }
    ]
    backendAddressPools: [
      {
        name: 'LoadBalancerBEAddressPool'
        properties: {}
      }
    ]
    loadBalancingRules: [
      {
        name: 'LBRule'
        properties: {
          backendAddressPool: {
            id: lbPoolID0
          }
          backendPort: nt0fabricTcpGatewayPort
          enableFloatingIP: false
          frontendIPConfiguration: {
            id: lbIPConfig0
          }
          frontendPort: nt0fabricTcpGatewayPort
          idleTimeoutInMinutes: 5
          probe: {
            id: lbProbeID0
          }
          protocol: 'Tcp'
        }
      }
      {
        name: 'LBHttpRule'
        properties: {
          backendAddressPool: {
            id: lbPoolID0
          }
          backendPort: nt0fabricHttpGatewayPort
          enableFloatingIP: false
          frontendIPConfiguration: {
            id: lbIPConfig0
          }
          frontendPort: nt0fabricHttpGatewayPort
          idleTimeoutInMinutes: 5
          probe: {
            id: lbHttpProbeID0
          }
          protocol: 'Tcp'
        }
      }
      {
        name: 'AppPortLBRule1'
        properties: {
          backendAddressPool: {
            id: lbPoolID0
          }
          backendPort: loadBalancedAppPort1
          enableFloatingIP: false
          frontendIPConfiguration: {
            id: lbIPConfig0
          }
          frontendPort: loadBalancedAppPort1
          idleTimeoutInMinutes: 5
          probe: {
            id: resourceId('Microsoft.Network/loadBalancers/probes', lbName, 'AppPortProbe1')
          }
          protocol: 'Tcp'
        }
      }
      {
        name: 'AppPortLBRule2'
        properties: {
          backendAddressPool: {
            id: lbPoolID0
          }
          backendPort: loadBalancedAppPort2
          enableFloatingIP: false
          frontendIPConfiguration: {
            id: lbIPConfig0
          }
          frontendPort: loadBalancedAppPort2
          idleTimeoutInMinutes: 5
          probe: {
            id: resourceId('Microsoft.Network/loadBalancers/probes', lbName, 'AppPortProbe2')
          }
          protocol: 'Tcp'
        }
      }
    ]
    probes: [
      {
        name: 'FabricGatewayProbe'
        properties: {
          intervalInSeconds: 5
          numberOfProbes: 2
          port: nt0fabricTcpGatewayPort
          protocol: 'Tcp'
        }
      }
      {
        name: 'FabricHttpGatewayProbe'
        properties: {
          intervalInSeconds: 5
          numberOfProbes: 2
          port: nt0fabricHttpGatewayPort
          protocol: 'Tcp'
        }
      }
      {
        name: 'AppPortProbe1'
        properties: {
          intervalInSeconds: 5
          numberOfProbes: 2
          port: loadBalancedAppPort1
          protocol: 'Tcp'
        }
      }
      {
        name: 'AppPortProbe2'
        properties: {
          intervalInSeconds: 5
          numberOfProbes: 2
          port: loadBalancedAppPort2
          protocol: 'Tcp'
        }
      }
    ]
    inboundNatPools: [
      {
        name: 'LoadBalancerBEAddressNatPool'
        properties: {
          backendPort: 3389
          frontendIPConfiguration: {
            id: lbIPConfig0
          }
          frontendPortRangeEnd: 4500
          frontendPortRangeStart: 3389
          protocol: 'Tcp'
        }
      }
    ]
  }
}

resource vmNodeType0 'Microsoft.Compute/virtualMachineScaleSets@2023-09-01' = {
  name: vmNodeType0Name
  location: location
  sku: {
    name: vmNodeType0Size
    capacity: nt0InstanceCount
    tier: 'Standard'
  }
  tags: {
    resourceType: 'Service Fabric'
    clusterName: clusterName
  }
  properties: {
    overprovision: overProvision
    upgradePolicy: {
      mode: 'Automatic'
    }
    virtualMachineProfile: {
      extensionProfile: {
        extensions: [
          {
            name: 'ServiceFabricNodeVmExt_vmNodeType0Name'
            properties: {
              type: 'ServiceFabricNode'
              autoUpgradeMinorVersion: true
              protectedSettings: {
                StorageAccountKey1:  supportLogStorageAccount.listKeys().keys[0].value
                StorageAccountKey2: supportLogStorageAccount.listkeys().keys[1].value
              }
              publisher: 'Microsoft.Azure.ServiceFabric'
              settings: {
                clusterEndpoint: cluster.properties.clusterEndpoint
                nodeTypeRef: vmNodeType0Name
                dataPath: '${((nodeDataDrive == 'OS') ? 'C' : 'D')}:\\\\SvcFab'
                durabilityLevel: 'Silver'
                nicPrefixOverride: subnet0Prefix
                certificate: {
                  thumbprint: certificateThumbprint
                  x509StoreName: certificateStoreValue
                }
              }
              typeHandlerVersion: '1.0'
            }
          }
          {
            name: 'VMDiagnosticsVmExt_vmNodeType0Name'
            properties: {
              type: 'IaaSDiagnostics'
              autoUpgradeMinorVersion: true
              protectedSettings: {
                storageAccountName: applicationDiagnosticsStorageAccountName
                storageAccountKey: listKeys(applicationDiagnosticsStorageAccount.id, '2021-01-01').keys[0].value
                storageAccountEndPoint: 'https://${environment().suffixes.storage}'
              }
              publisher: 'Microsoft.Azure.Diagnostics'
              settings: {
                WadCfg: {
                  DiagnosticMonitorConfiguration: {
                    overallQuotaInMB: '50000'
                    EtwProviders: {
                      EtwEventSourceProviderConfiguration: [
                        {
                          provider: 'Microsoft-ServiceFabric-Actors'
                          scheduledTransferKeywordFilter: '1'
                          scheduledTransferPeriod: 'PT5M'
                          DefaultEvents: {
                            eventDestination: 'ServiceFabricReliableActorEventTable'
                          }
                        }
                        {
                          provider: 'Microsoft-ServiceFabric-Services'
                          scheduledTransferPeriod: 'PT5M'
                          DefaultEvents: {
                            eventDestination: 'ServiceFabricReliableServiceEventTable'
                          }
                        }
                      ]
                      EtwManifestProviderConfiguration: [
                        {
                          provider: 'cbd93bc2-71e5-4566-b3a7-595d8eeca6e8'
                          scheduledTransferLogLevelFilter: 'Information'
                          scheduledTransferKeywordFilter: '4611686018427387904'
                          scheduledTransferPeriod: 'PT5M'
                          DefaultEvents: {
                            eventDestination: 'ServiceFabricSystemEventTable'
                          }
                        }
                      ]
                    }
                  }
                }
                StorageAccount: applicationDiagnosticsStorageAccountName
              }
              typeHandlerVersion: '1.5'
            }
          }
        ]
      }
      networkProfile: {
        networkInterfaceConfigurations: [
          {
            name: '${nicName}-0'
            properties: {
              ipConfigurations: [
                {
                  name: '${nicName}-0'
                  properties: {
                    loadBalancerBackendAddressPools: [
                      {
                        id: lbPoolID0
                      }
                    ]
                    loadBalancerInboundNatPools: [
                      {
                        id: lbNatPoolID0
                      }
                    ]
                    subnet: {
                      id: subnet0Ref
                    }
                  }
                }
              ]
              primary: true
            }
          }
        ]
      }
      osProfile: {
        adminPassword: adminPassword
        adminUsername: adminUsername
        computerNamePrefix: vmNodeType0Name
        secrets: [
          {
            sourceVault: {
              id: sourceVaultResourceId
            }
            vaultCertificates: [
              {
                certificateStore: certificateStoreValue
                certificateUrl: certificateUrlValue
              }
            ]
          }
        ]
      }
      storageProfile: {
        imageReference: {
          publisher: vmImagePublisher
          offer: vmImageOffer
          sku: vmImageSku
          version: vmImageVersion
        }
        osDisk: {
          managedDisk: {
            storageAccountType: 'StandardSSD_LRS'
          }
          caching: 'ReadOnly'
          createOption: 'FromImage'
        }
      }
    }
  }
  dependsOn: [
    virtualNetwork
    lb
  ]
}

resource cluster 'Microsoft.ServiceFabric/clusters@2023-11-01-preview' = {
  name: clusterName
  location: location
  tags: {
    resourceType: 'Service Fabric'
    clusterName: clusterName
  }
  properties: {
    azureActiveDirectory: {
      clientApplication: clientapplication
      clusterApplication: clusterApplication
      tenantId: tenantId
    }
    certificate: {
      thumbprint: certificateThumbprint
      x509StoreName: certificateStoreValue
    }
    diagnosticsStorageAccountConfig: {
      blobEndpoint: reference(supportLogStorageAccount.id, '2021-01-01').primaryEndpoints.blob
      protectedAccountKeyName: 'StorageAccountKey1'
      queueEndpoint: reference(supportLogStorageAccount.id, '2021-01-01').primaryEndpoints.queue
      storageAccountName: supportLogStorageAccountName
      tableEndpoint: reference(supportLogStorageAccount.id, '2021-01-01').primaryEndpoints.table
    }
    fabricSettings: [
      {
        parameters: [
          {
            name: 'ClusterProtectionLevel'
            value: clusterProtectionLevel
          }
        ]
        name: 'Security'
      }
    ]
    managementEndpoint: 'https://${lbIP.properties.dnsSettings.fqdn}:${nt0fabricHttpGatewayPort}'
    nodeTypes: [
      {
        name: vmNodeType0Name
        applicationPorts: {
          endPort: nt0applicationEndPort
          startPort: nt0applicationStartPort
        }
        clientConnectionEndpointPort: nt0fabricTcpGatewayPort
        durabilityLevel: 'Silver'
        ephemeralPorts: {
          endPort: nt0ephemeralEndPort
          startPort: nt0ephemeralStartPort
        }
        httpGatewayEndpointPort: nt0fabricHttpGatewayPort
        isPrimary: true
        vmInstanceCount: nt0InstanceCount
      }
    ]
    reliabilityLevel: 'Silver'
    upgradeMode: 'Automatic'
    vmImage: 'Windows'
  }
}

output location string = location
output name string = cluster.name
output resourceGroupName string = resourceGroup().name
output resourceId string = cluster.id
output clusterProperties object = cluster.properties

Bicep 檔案中定義了多個 Azure 資源:

自訂參數檔案

開啟 azuredeploy.parameters.json 並編輯參數值,以便:

  • clusterName 符合您在建立叢集憑證時為 CertDNSName 提供的值
  • adminUserName 是預設 GEN-UNIQUE 權杖以外的某個值
  • adminPassword 是預設 GEN-PASSWORD 權杖以外的某個值
  • certificateThumbprintsourceVaultResourceIdcertificateUrlValue 全都是空白字串 ("")

例如:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "clusterName": {
      "value": "sfquickstart"
    },
    "adminUsername": {
      "value": "testadm"
    },
    "adminPassword": {
      "value": "Password#1234"
    },
    "certificateThumbprint": {
      "value": ""
    },
    "sourceVaultResourceId": {
      "value": ""
    },
    "certificateUrlValue": {
      "value": ""
    }
  }
}

部署 Bicep 檔案

在變數中儲存您的 Bicep 檔案路徑和參數檔案,然後部署 Bicep 檔案。

$templateFilePath = "<full path to main.bicep>"
$parameterFilePath = "<full path to azuredeploy.parameters.json>"

New-AzResourceGroupDeployment `
    -ResourceGroupName $resourceGroupName `
    -TemplateFile $templateFilePath `
    -TemplateParameterFile $parameterFilePath `
    -CertificateThumbprint $certThumbprint `
    -CertificateUrlValue $certUrlValue `
    -SourceVaultResourceId $sourceVaultId `
    -Verbose

檢閱已部署的資源

部署完成之後,請在輸出中尋找 managementEndpoint 值,然後在網頁瀏覽器中開啟該網址,以在 Service Fabric Explorer 中檢視您的叢集。

顯示新叢集的 Service Fabric Explorer 的螢幕擷取畫面。

您也可以從 Azure 入口網站的 [服務總管資源] 刀鋒視窗中尋找 Service Fabric Explorer 端點。

顯示 Service Fabric Explorer 端點的 [Service Fabric 資源] 刀鋒視窗螢幕擷取畫面。

清除資源

不再需要時,請使用 Azure 入口網站、Azure CLI 或 Azure PowerShell 來刪除資源群組及其資源。

az group delete --name exampleRG

接下來,從本機存放區移除叢集憑證。 列出已安裝的憑證,以尋找叢集的指紋:

Get-ChildItem Cert:\CurrentUser\My\

接著移除憑證:

Get-ChildItem Cert:\CurrentUser\My\{THUMBPRINT} | Remove-Item

下一步

若要了解如何使用 Visual Studio Code 建立 Bicep 檔案,請參閱: