纵向扩展 Service Fabric 群集非主要节点类型

本文介绍如何在尽量减少停机时间的情况下纵向扩展 Service Fabric 群集非主要节点类型。 Service Fabric 群集节点不支持就地 SKU 升级,因为此类操作可能导致数据和可用性丢失。 建议用于纵向扩展 Service Fabric 节点类型的最安全且最可靠的方法是:

  1. 向 Service Fabric 群集添加一个新节点类型,该节点类型由升级(或修改)后的虚拟机规模集 SKU 和配置提供支持。 此步骤还涉及为规模集设置新的负载均衡器、子网和公共 IP。

  2. 原始规模集和已升级的规模集同时运行后,通过将应用程序的放置约束设置为新节点类型来迁移工作负载。

  3. 验证群集是否正常,然后删除原始规模集(和相关资源)以及已删除节点的节点状态。

以下内容引导你完成将示例群集的非主要节点类型 VM 的 VM 大小和操作系统更新为银级持久性的过程,该持久性由包含五个节点(用作辅助节点类型)的单个规模集提供支持。 使用 Service Fabric 系统服务的主要节点类型将保持不变。 我们将升级非主要节点类型:

  • 将 VM 大小从 Standard_D2_V2 升级到 Standard D4_V2;
  • 从 VM 操作系统 Windows Server 2019 Datacenter 升级到 Windows Server 2022 Datacenter。

警告

在生产群集上尝试执行此过程之前,建议先研究示例模板并对测试群集验证此过程。

如果群集状态为不正常,请不要尝试对非主要节点类型执行纵向扩展过程,因为这只会导致群集更不稳定。 我们将利用纵向扩展 Service Fabric 群集主要节点类型指南中所用的分步 Azure 部署模板。 但是,我们将修改这些模板,使其不特定于主要节点类型。 可以在 GitHub 上获取这些模板。

设置测试群集

接下来让我们设置初始 Service Fabric 测试群集。 首先,下载用于完成此方案的 Azure 资源管理器示例模板。

然后,登录到 Azure 帐户。

# Sign in to your Azure account
Connect-AzAccount -Environment AzureChinaCloud -SubscriptionId "<subscription ID>"

接下来,打开 parameters.json 文件并将 clusterName 的值更新为某个唯一值(在 Azure 中)。

以下命令将引导你生成新的自签名证书并部署测试群集。 如果你已有一个想要使用的证书,请跳到使用现有证书部署群集

生成自签名证书并部署群集

首先,分配 Service Fabric 群集部署所需的变量。 根据具体的帐户和环境调整 resourceGroupNamecertSubjectNameparameterFilePathtemplateFilePath 的值:

# Assign deployment variables
$resourceGroupName = "sftestupgradegroup"
$certOutputFolder = "c:\certificates"
$certPassword = "Password!1" | ConvertTo-SecureString -AsPlainText -Force
$certSubjectName = "sftestupgrade.chinanorth.cloudapp.chinacloudapi.cn"
$parameterFilePath = "C:\parameters.json"
$templateFilePath = "C:\Initial-TestClusterSetup.json"

注意

在运行该命令来部署新的 Service Fabric 群集之前,请确保 certOutputFolder 位置存在于你的本地计算机上。 接下来部署 Service Fabric 测试群集:

# Deploy the initial test cluster
New-AzServiceFabricCluster `
    -ResourceGroupName $resourceGroupName `
    -CertificateOutputFolder $certOutputFolder `
    -CertificatePassword $certPassword `
    -CertificateSubjectName $certSubjectName `
    -TemplateFile $templateFilePath `
    -ParameterFile $parameterFilePath

部署完成后,在本地计算机上找到 .pfx 文件 ($certPfx) 并将其导入到证书存储中:

cd c:\certificates
$certPfx = ".\sftestupgradegroup20200312121003.pfx"
Import-PfxCertificate `
     -FilePath $certPfx `
     -CertStoreLocation Cert:\CurrentUser\My `
     -Password (ConvertTo-SecureString Password!1 -AsPlainText -Force)

该操作会返回证书指纹。现在,在连接到新群集以及检查其运行状况时可以使用该指纹。 (请跳过以下部分,其中介绍的是替代的群集部署方法。)

使用现有证书部署群集

另外,你还可以使用现有 Azure Key Vault 证书来部署测试群集。 为此,需要获取对 Key Vault 和证书指纹的引用

# Key Vault variables
$certUrlValue = "https://sftestupgradegroup.vault.azure.cn/secrets/sftestupgradegroup20200309235308/dac0e7b7f9d4414984ccaa72bfb2ea39"
$sourceVaultValue = "/subscriptions/########-####-####-####-############/resourceGroups/sftestupgradegroup/providers/Microsoft.KeyVault/vaults/sftestupgradegroup"
$thumb = "BB796AA33BD9767E7DA27FE5182CF8FDEE714A70"

接下来,指定群集的资源组名称,并设置 templateFilePathparameterFilePath 位置:

注意

指定的资源组必须已存在,并且与 Key Vault 位于同一区域。

$resourceGroupName = "sftestupgradegroup"
$templateFilePath = "C:\Initial-TestClusterSetup.json"
$parameterFilePath = "C:\parameters.json"

最后,运行以下命令以部署初始测试群集:

# Deploy the initial test cluster
New-AzResourceGroupDeployment `
    -ResourceGroupName $resourceGroupName `
    -TemplateFile $templateFilePath `
    -TemplateParameterFile $parameterFilePath `
    -CertificateThumbprint $thumb `
    -CertificateUrlValue $certUrlValue `
    -SourceVaultValue $sourceVaultValue `
    -Verbose

连接到新群集并检查运行状况

连接到群集,并确保其所有五个节点均正常运行(将 clusterNamethumb 变量替换为你自己的值):

# Connect to the cluster
$clusterName = "sftestupgrade.chinanorth.cloudapp.chinacloudapi.cn:19000"
$thumb = "BB796AA33BD9767E7DA27FE5182CF8FDEE714A70"
Connect-ServiceFabricCluster `
    -ConnectionEndpoint $clusterName `
    -KeepAliveIntervalInSec 10 `
    -X509Credential `
    -ServerCertThumbprint $thumb  `
    -FindType FindByThumbprint `
    -FindValue $thumb `
    -StoreLocation CurrentUser `
    -StoreName My
# Check cluster health
Get-ServiceFabricClusterHealth

完成上述操作后,便可以开始执行升级过程了。

使用已升级的规模集部署新的非主要节点类型

若要升级(垂直缩放)某个节点类型,首先需要部署由新的规模集和支持资源提供支持的新节点类型。 与原始规模集一样,新规模集将标记为非主要 (isPrimary: false)。 如果你想要纵向扩展主要节点类型,请参阅纵向扩展 Service Fabric 群集主要节点类型。 在以下部分创建的资源最终会成为群集中新的节点类型,而原始节点类型资源则会被删除。

使用升级的规模集更新群集模板

下面是原始群集部署模板中用来添加新节点类型和支持性资源的逐节修改。

Step1-AddPrimaryNodeType.json 模板文件中已经为你完成了此步骤所需的大部分更改。 但是,还必须做出一项额外的更改,使该模板文件适用于非主要节点类型。 以下部分将详细解释这些更改,并标注了必须做出更改的位置。

注意

请确保所用名称不同于原始非主要节点类型的原始节点类型、规模集、负载均衡器、公共 IP 和子网,因为在此过程的一个后续步骤中会删除这些资源。

在现有虚拟网络中创建一个新的子网

{
    "name": "[variables('subnet1Name')]",
    "properties": {
        "addressPrefix": "[variables('subnet1Prefix')]"
    }
}

创建具有唯一 domainNameLabel 的一个新公共 IP

{
    "apiVersion": "[variables('publicIPApiVersion')]",
    "type": "Microsoft.Network/publicIPAddresses",
    "name": "[concat(variables('lbIPName'),'-',variables('vmNodeType1Name'))]",
    "location": "[variables('computeLocation')]",
    "properties": {
        "dnsSettings": {
            "domainNameLabel": "[concat(variables('dnsName'),'-','nt1')]"
        },
        "publicIPAllocationMethod": "Dynamic"
    },
    "tags": {
        "resourceType": "Service Fabric",
        "clusterName": "[parameters('clusterName')]"
    }
}

为公共 IP 创建一个新的负载均衡器

"dependsOn": [
    "[concat('Microsoft.Network/publicIPAddresses/',concat(variables('lbIPName'),'-',variables('vmNodeType1Name')))]"
]

创建一个新的虚拟机规模集(包含升级的 VM 和 OS SKU)

节点类型引用

"nodeTypeRef": "[variables('vmNodeType1Name')]"

VM SKU

"sku": {
    "name": "[parameters('vmNodeType1Size')]",
    "capacity": "[parameters('nt1InstanceCount')]",
    "tier": "Standard"
}

OS SKU

"imageReference": {
    "publisher": "[parameters('vmImagePublisher1')]",
    "offer": "[parameters('vmImageOffer1')]",
    "sku": "[parameters('vmImageSku1')]",
    "version": "[parameters('vmImageVersion1')]"
}

另外,请确保包含工作负荷所需的任何其他扩展。

将新的非主要节点类型添加到群集

现在,新节点类型 (vmNodeType1Name) 具有其自身的名称、子网、IP、负载均衡器和规模集,可以重复使用原始节点类型中的所有其他变量(例如 nt0applicationEndPortnt0applicationStartPortnt0fabricTcpGatewayPort)。

在现有模板文件中,isPrimary 参数已根据纵向扩展 Service Fabric 群集主要节点类型指南中所述设置为 true。 将非主要节点类型的 isPrimary 更改为 false

"name": "[variables('vmNodeType1Name')]",
"applicationPorts": {
    "endPort": "[variables('nt0applicationEndPort')]",
    "startPort": "[variables('nt0applicationStartPort')]"
},
"clientConnectionEndpointPort": "[variables('nt0fabricTcpGatewayPort')]",
"durabilityLevel": "Bronze",
"ephemeralPorts": {
    "endPort": "[variables('nt0ephemeralEndPort')]",
    "startPort": "[variables('nt0ephemeralStartPort')]"
},
"httpGatewayEndpointPort": "[variables('nt0fabricHttpGatewayPort')]",
"isPrimary": false,
"reverseProxyEndpointPort": "[variables('nt0reverseProxyEndpointPort')]",
"vmInstanceCount": "[parameters('nt1InstanceCount')]"

实现模板和 parameters 文件中的所有更改后,转到下一部分获取 Key Vault 引用并将更新部署到群集。

获取 Key Vault 引用

若要部署已更新的配置,你需要多次引用 Key Vault 中存储的群集证书。 查找这些值的最简单方法是使用 Azure 门户。 需要:

  • 群集证书的 Key Vault URL。 在 Azure 门户上你的 Key Vault 中,选择“证书”><所需的证书>>“机密标识符”:

    $certUrlValue="https://sftestupgradegroup.vault.azure.cn/secrets/sftestupgradegroup20200309235308/dac0e7b7f9d4414984ccaa72bfb2ea39"
    
  • 群集证书的指纹。 (如果已连接到初始群集来检查其运行状况,则可能已获取此指纹。)在 Azure 门户上的同一证书边栏选项卡(“证书”><所需的证书>)中,复制“X.509 SHA-1 指纹(十六进制)”:

    $thumb = "BB796AA33BD9767E7DA27FE5182CF8FDEE714A70"
    
  • Key Vault 的资源 ID。 在 Azure 门户上你的 Key Vault 中,选择“属性”>“资源 ID”:

    $sourceVaultValue = "/subscriptions/########-####-####-####-############/resourceGroups/sftestupgradegroup/providers/Microsoft.KeyVault/vaults/sftestupgradegroup"
    

部署已更新的模板

根据需要调整 templateFilePath 并运行以下命令:

# Deploy the new node type and its resources
$templateFilePath = "C:\Step1-AddPrimaryNodeType.json"
New-AzResourceGroupDeployment `
    -ResourceGroupName $resourceGroupName `
    -TemplateFile $templateFilePath `
    -TemplateParameterFile $parameterFilePath `
    -CertificateThumbprint $thumb `
    -CertificateUrlValue $certUrlValue `
    -SourceVaultValue $sourceVaultValue `
    -Verbose

部署完成后,再次检查群集运行状况,并确保两种节点类型的所有节点都正常运行。

Get-ServiceFabricClusterHealth

将工作负载迁移到新节点类型

等待所有应用程序都已移动到新节点类型并且运行正常。

禁用原始节点类型规模集中的节点

在所有种子节点都迁移到新规模集后,你可以禁用原始规模集的节点。

# Disable the nodes in the original scale set.
$nodeType = "nt0vm"
$nodes = Get-ServiceFabricNode
Write-Host "Disabling nodes..."
foreach($node in $nodes)
{
  if ($node.NodeType -eq $nodeType)
  {
    $node.NodeName
    Disable-ServiceFabricNode -Intent RemoveNode -NodeName $node.NodeName -Force
  }
}

使用 Service Fabric Explorer 监视原始规模集中的节点从“正在禁用”状态到“已禁用”状态的转换进度。 等待所有节点进入“已禁用”状态。

停止已禁用节点上的数据

现在,你可以停止已禁用节点上的数据。

# Stop data on the disabled nodes.
foreach($node in $nodes)
{
  if ($node.NodeType -eq $nodeType)
  {
    $node.NodeName
    Start-ServiceFabricNodeTransition -Stop -OperationId (New-Guid) -NodeInstanceId $node.NodeInstanceId -NodeName $node.NodeName -StopDurationInSeconds 10000
  }
}

删除原始节点类型并清理其资源

我们已准备好删除原始节点类型及其关联的资源,以结束垂直缩放过程。

删除原始规模集

首先删除节点类型的支持规模集。

$scaleSetName = "nt0vm"
$scaleSetResourceType = "Microsoft.Compute/virtualMachineScaleSets"
Remove-AzResource -ResourceName $scaleSetName -ResourceType $scaleSetResourceType -ResourceGroupName $resourceGroupName -Force

删除原始 IP 和负载均衡器资源

你现在可以删除原始 IP 和负载均衡器资源。 在此步骤中,你还将更新 DNS 名称。

注意

如果你已在使用“标准”SKU 公共 IP 和负载均衡器,则此步骤是可选的。 这种情况下,你在同一个负载均衡器下可以有多个规模集/节点类型。 运行以下命令,根据需要修改 $lbname 值。

# Delete the original IP and load balancer resources
$lbName = "LB-sftestupgrade-nt0vm"
$lbResourceType = "Microsoft.Network/loadBalancers"
$ipResourceType = "Microsoft.Network/publicIPAddresses"
$oldPublicIpName = "PublicIP-LB-FE-nt0vm"
$newPublicIpName = "PublicIP-LB-FE-nt1vm"
$oldPublicIP = Get-AzPublicIpAddress -Name $oldPublicIpName  -ResourceGroupName $resourceGroupName
$nonPrimaryDNSName = $oldNonPrimaryPublicIP.DnsSettings.DomainNameLabel
$nonPrimaryDNSFqdn = $oldNonPrimaryPublicIP.DnsSettings.Fqdn
Remove-AzResource -ResourceName $lbName -ResourceType $lbResourceType -ResourceGroupName $resourceGroupName -Force
Remove-AzResource -ResourceName $oldPublicIpName -ResourceType $ipResourceType -ResourceGroupName $resourceGroupName -Force
$PublicIP = Get-AzPublicIpAddress -Name $newPublicIpName  -ResourceGroupName $resourceGroupName
$PublicIP.DnsSettings.DomainNameLabel = $nonPrimaryDNSName
$PublicIP.DnsSettings.Fqdn = $nonPrimaryDNSFqdn
Set-AzPublicIpAddress -PublicIpAddress $PublicIP

从原始节点类型中删除节点状态

原始节点类型节点的“运行状况状态”现在会显示“错误”。 从群集中删除其节点状态。

# Remove state of the obsolete nodes from the cluster
$nodeType = "nt0vm"
$nodes = Get-ServiceFabricNode
Write-Host "Removing node state..."
foreach($node in $nodes)
{
  if ($node.NodeType -eq $nodeType)
  {
    $node.NodeName
    Remove-ServiceFabricNodeState -NodeName $node.NodeName -Force
  }
}

Service Fabric Explorer 现在应当仅反映新节点类型 (nt1vm) 的五个节点,所有节点的“运行状况状态”值均为“正常”。 接下来,我们将通过更新模板以反映最新的更改并重新进行部署来修正这个问题。

更新部署模板以反映刚刚纵向扩展的非主要节点类型

Step3-CleanupOriginalPrimaryNodeType.json 模板文件中已经为你完成了此步骤所需的大部分更改。 但是,还必须做出一项额外的更改,使该模板文件适用于非主要节点类型。 以下部分将详细解释这些更改,并标注了必须做出更改的位置。

更新群集管理终结点

更新部署模板上的群集 managementEndpoint 以引用新的 IP(方法是将“vmNodeType0Name”更新为“vmNodeType1Name”)。

  "managementEndpoint": "[concat('https://',reference(concat(variables('lbIPName'),'-',variables('vmNodeType1Name'))).dnsSettings.fqdn,':',variables('nt0fabricHttpGatewayPort'))]",

删除原始节点类型引用

从部署模板的 Service Fabric 资源中删除原始节点类型引用。

在现有模板文件中,isPrimary 参数已根据纵向扩展 Service Fabric 群集主要节点类型指南中所述设置为 true。 将非主要节点类型的 isPrimary 更改为 false

"name": "[variables('vmNodeType0Name')]",
"applicationPorts": {
    "endPort": "[variables('nt0applicationEndPort')]",
    "startPort": "[variables('nt0applicationStartPort')]"
},
"clientConnectionEndpointPort": "[variables('nt0fabricTcpGatewayPort')]",
"durabilityLevel": "Bronze",
"ephemeralPorts": {
    "endPort": "[variables('nt0ephemeralEndPort')]",
    "startPort": "[variables('nt0ephemeralStartPort')]"
},
"httpGatewayEndpointPort": "[variables('nt0fabricHttpGatewayPort')]",
"isPrimary": false,
"reverseProxyEndpointPort": "[variables('nt0reverseProxyEndpointPort')]",
"vmInstanceCount": "[parameters('nt0InstanceCount')]"

将运行状况策略配置为忽略现有错误

(仅适用于“白银”和更高级别持续性的群集)更新模板中的群集资源,并通过在群集资源属性下添加“applicationDeltaHealthPolicies”,将运行状况策略配置为忽略 fabric:/System 应用程序运行状况,如下所示。 以下策略会忽略现有错误,但不允许新的运行状况错误。

"upgradeDescription":  
{ 
 "forceRestart": false, 
 "upgradeReplicaSetCheckTimeout": "10675199.02:48:05.4775807", 
 "healthCheckWaitDuration": "00:05:00", 
 "healthCheckStableDuration": "00:05:00", 
 "healthCheckRetryTimeout": "00:45:00", 
 "upgradeTimeout": "12:00:00", 
 "upgradeDomainTimeout": "02:00:00", 
 "healthPolicy": { 
   "maxPercentUnhealthyNodes": 100, 
   "maxPercentUnhealthyApplications": 100 
 }, 
 "deltaHealthPolicy":  
 { 
   "maxPercentDeltaUnhealthyNodes": 0, 
   "maxPercentUpgradeDomainDeltaUnhealthyNodes": 0, 
   "maxPercentDeltaUnhealthyApplications": 0, 
   "applicationDeltaHealthPolicies":  
   { 
       "fabric:/System":  
       { 
           "defaultServiceTypeDeltaHealthPolicy":  
           { 
                   "maxPercentDeltaUnhealthyServices": 0 
           } 
       } 
   } 
 } 
}

删除原始节点类型的支持资源

从 ARM 模板和参数文件中删除与原始节点类型相关的所有其他资源。 删除以下内容:

    "vmImagePublisher": {
      "value": "MicrosoftWindowsServer"
    },
    "vmImageOffer": {
      "value": "WindowsServer"
    },
    "vmImageSku": {
      "value": "2019-Datacenter"
    },
    "vmImageVersion": {
      "value": "latest"
    },

部署已完成的模板

最后,部署修改后的 Azure 资源管理器模板。

# Deploy the updated template file
$templateFilePath = "C:\Step3-CleanupOriginalPrimaryNodeType"
New-AzResourceGroupDeployment `
    -ResourceGroupName $resourceGroupName `
    -TemplateFile $templateFilePath `
    -TemplateParameterFile $parameterFilePath `
    -CertificateThumbprint $thumb `
    -CertificateUrlValue $certUrlValue `
    -SourceVaultValue $sourceVaultValue `
    -Verbose

注意

此步骤将需要一段时间,通常最长为两个小时。 升级会更改“InfrastructureService”的设置,因此需要重启节点。 在这种情况下,将忽略 forceRestart。 参数 upgradeReplicaSetCheckTimeout 指定 Service Fabric 等待分区进入安全状态(如果尚未进入安全状态)的最长时间。 一旦节点上的所有分区都已通过安全检查,Service Fabric 就会在该节点上继续升级。 可将参数 upgradeTimeout 的值减至 6 小时,但若要获得最高安全性,应使用 12 小时。

部署完成后,在 Azure 门户中验证 Service Fabric 资源的“状态”是否为“就绪”。 验证你是否可以访问新的 Service Fabric Explorer 终结点、“群集运行状况状态”是否为“正常”,以及任何已部署的应用程序是否都能正常运行。

现在,你已垂直缩放了一个群集非主要节点类型!

后续步骤