越来越多的网站开始支持 IPv6,即使是哪些只提供 api 服务的站点也需要支持 IPv6,比如苹果应用商店中的 app 早就强制要求服务器端支持 IPv6 了。
笔者在前文《Azure Load Balancer : 简介》中介绍了通过 Azure 门户站点创建基础的 Azure Load Balancer 配置,本文将接着介绍如何创建支持 IPv6 的 Azure Load Balancer。

关于 IPv6 的一些限制

让我们先来了解一下 Azure Load Balancer 在 IPv6 支持方面的一些限制(完整的限制列表请参考这里):

  • 无法在 Azure 门户中添加 IPv6 负载均衡规则。 只能通过模板、CLI 或 PowerShell 创建规则。
  • 无法将现有 VM 升级为使用 IPv6 地址。 为此必须部署新 VM。
  • 无法将公共 IPv6 地址分配给 VM, 只能分配给负载均衡器。

这三条限制看起来让人很沮丧!其中第一条意味着我们没办法通过 UI 简单的创建支持 IPv6 的 Load Balancer;第二条则让老机器失去了升级的机会;第三条则把 IPv6 的支持完全绑死到了 Load Balancer 上!

换个角度看问题也许能让人心情愉快些:
不支持 UI 操作就是逼着我们写脚本,刚好可以朝着基础架构即代码的方向前进!
不支持现有虚机的升级,可以抛掉历史的包袱轻装上阵!
不支持将公共 IPv6 地址分配给 VM,那就只用在 Load Balancer 上维护 IPv6 的配置!

使用 PowerShell 脚本创建 Load Balancer

既然无法通过 Azure 门户站点上的 UI 创建支持 IPv6 的 Load Balancer,笔者就选择通过 PowerShell 脚本完成这个任务, 我们来创建一个具有两台后端虚机的 Load Balancer,下面是脚本中的主要逻辑。

定义脚本中所需的变量
为了能更好的重用该脚本,笔者把所需的变量都定义到了脚本的开头处,虽然变量的数目很多,但是只要修改 prodNamePrefix、userName、sshPublicKey 和 location 等几个关键变量的值脚本就可以工作了:

# 资源名称的前缀
$prodNamePrefix = "Nick"
$lowerProdNamePrefix = $prodNamePrefix.ToLower()

# vm user name
$userName = "nick"
# vm user public key
$sshPublicKey = "xxxxxxxxxx"

# resource loacation
$location = "japaneast"
# resource group name
$rgName = $prodNamePrefix + "LBGroup"
...

创建 Resource Group、虚拟网络及其虚拟子网

# 创建 Resource Group
New-AzureRmResourceGroup -Name $rgName -location $location

# 虚拟网络及其虚拟子网
$backendSubnet = New-AzureRmVirtualNetworkSubnetConfig `
                 -Name $subnetName `
                 -AddressPrefix $subnetPrefix
$vnet = New-AzureRmvirtualNetwork -Name $vnetName `
                                  -ResourceGroupName $rgName `
                                  -Location $location `
                                  -AddressPrefix $vnetPrefix `
                                  -Subnet $backendSubnet

创建 Load Balancer

# 创建 Load Balancer 的公共 IP
$publicIPv4 = New-AzureRmPublicIpAddress `
              -Name $publicIpv4Name `
              -ResourceGroupName $rgName `
              -Location $location `
              -AllocationMethod Static `
              -IpAddressVersion IPv4 `
              -DomainNameLabel $dnsLabelv4
$publicIPv6 = New-AzureRmPublicIpAddress `
              -Name $publicIpv6Name `
              -ResourceGroupName $rgName `
              -Location $location `
              -AllocationMethod Dynamic `
              -IpAddressVersion IPv6 `
              -DomainNameLabel $dnsLabelv6

# 创建 Load Balancer 的 Frontend IP
$FEIPConfigv4 = New-AzureRmLoadBalancerFrontendIpConfig `
                -Name $frontendV4Name `
                -PublicIpAddress $publicIPv4
$FEIPConfigv6 = New-AzureRmLoadBalancerFrontendIpConfig `
                -Name $frontendV6Name `
                -PublicIpAddress $publicIPv6

# 创建 Load Balancer 的 Backend pools
$backendpoolipv4 = New-AzureRmLoadBalancerBackendAddressPoolConfig `
                   -Name $backendAddressPoolV4Name
$backendpoolipv6 = New-AzureRmLoadBalancerBackendAddressPoolConfig `
                   -Name $backendAddressPoolV6Name

# 创建 Load Balancer 的 Inbound NAT rules
$inboundNATRule1v4 = New-AzureRmLoadBalancerInboundNatRuleConfig `
                     -Name $natRule1V4Name `
                     -FrontendIpConfiguration $FEIPConfigv4 `
                     -Protocol TCP `
                     -FrontendPort 10022 `
                     -BackendPort 22
$inboundNATRule2v4 = New-AzureRmLoadBalancerInboundNatRuleConfig `
                     -Name $natRule2V4Name `
                     -FrontendIpConfiguration $FEIPConfigv4 `
                     -Protocol TCP `
                     -FrontendPort 20022 `
                     -BackendPort 22

# 创建 Load Balancer 的 Health probes
$healthProbe = New-AzureRmLoadBalancerProbeConfig -Name $probeV4V6Name `
                                                  -Protocol Tcp `
                                                  -Port 22 `
                                                  -IntervalInSeconds 15 `
                                                  -ProbeCount 2

# 创建 Load Balancer 的 Load balancing rules
$lbrule1v4http = New-AzureRmLoadBalancerRuleConfig `
                 -Name $lbRule1V4HTTPName `
                 -FrontendIpConfiguration $FEIPConfigv4 `
                 -BackendAddressPool $backendpoolipv4 `
                 -Probe $healthProbe `
                 -Protocol Tcp `
                 -FrontendPort 80 `
                 -BackendPort 80
$lbrule1v6http = New-AzureRmLoadBalancerRuleConfig `
                 -Name $lbRule1V6HTTPName `
                 -FrontendIpConfiguration $FEIPConfigv6 `
                 -BackendAddressPool $backendpoolipv6 `
                 -Probe $healthProbe `
                 -Protocol Tcp `
                 -FrontendPort 80 `
                 -BackendPort 80
$lbrule1v4https = New-AzureRmLoadBalancerRuleConfig `
                  -Name $lbRule1V4HTTPSName `
                  -FrontendIpConfiguration $FEIPConfigv4 `
                  -BackendAddressPool $backendpoolipv4 `
                  -Probe $healthProbe `
                  -Protocol Tcp `
                  -FrontendPort 443 `
                  -BackendPort 443
$lbrule1v6https = New-AzureRmLoadBalancerRuleConfig `
                  -Name $lbRule1V6HTTPSName `
                  -FrontendIpConfiguration $FEIPConfigv6 `
                  -BackendAddressPool $backendpoolipv6 `
                  -Probe $healthProbe `
                  -Protocol Tcp `
                  -FrontendPort 443 `
                  -BackendPort 443

# 创建 Load Balancer
$loadbalancer = New-AzureRmLoadBalancer `
                -ResourceGroupName $rgName `
                -Name $lbName `
                -Location $location `
                -FrontendIpConfiguration $FEIPConfigv4,$FEIPConfigv6 `
                -InboundNatRule $inboundNATRule2v4,$inboundNATRule1v4 `
                -BackendAddressPool $backendpoolipv4,$backendpoolipv6 `
                -Probe $healthProbe `
                -LoadBalancingRule $lbrule1v4http,$lbrule1v6http,`
                $lbrule1v4https,$lbrule1v6https

创建两个虚拟网卡

# 重新获得虚拟网络及其虚拟子网的实例,
# 否则创建网卡时会提示没有指定虚拟子网
$vnet = Get-AzureRmVirtualNetwork -Name $vnetName `
                                  -ResourceGroupName $rgName
$backendSubnet = Get-AzureRmVirtualNetworkSubnetConfig `
                 -Name $subnetName `
                 -VirtualNetwork $vnet

$nic1IPv4 = New-AzureRmNetworkInterfaceIpConfig `
            -Name "IPv4IPConfig" `
            -PrivateIpAddressVersion "IPv4" `
            -Subnet $backendSubnet `
            -LoadBalancerBackendAddressPool $backendpoolipv4 `
            -LoadBalancerInboundNatRule $inboundNATRule1v4
$nic1IPv6 = New-AzureRmNetworkInterfaceIpConfig `
            -Name "IPv6IPConfig" `
            -PrivateIpAddressVersion "IPv6" `
            -LoadBalancerBackendAddressPool $backendpoolipv6
$nic1 = New-AzureRmNetworkInterface `
        -Name $nic1Name `
        -IpConfiguration $nic1IPv4,$nic1IPv6 `
        -ResourceGroupName $rgName `
        -Location $location

$nic2IPv4 = New-AzureRmNetworkInterfaceIpConfig `
            -Name "IPv4IPConfig" `
            -PrivateIpAddressVersion "IPv4" `
            -Subnet $backendSubnet `
            -LoadBalancerBackendAddressPool $backendpoolipv4 `
            -LoadBalancerInboundNatRule $inboundNATRule2v4
$nic2IPv6 = New-AzureRmNetworkInterfaceIpConfig `
            -Name "IPv6IPConfig" `
            -PrivateIpAddressVersion "IPv6" `
            -LoadBalancerBackendAddressPool $backendpoolipv6
$nic2 = New-AzureRmNetworkInterface `
        -Name $nic2Name `
        -IpConfiguration $nic2IPv4,$nic2IPv6 `
        -ResourceGroupName $rgName `
        -Location $location

创建虚拟机并分配新建的 NIC

# 创建 Availability Set
New-AzureRmAvailabilitySet -Name $availabilitySetName `
                           -Sku Aligned `
                           -PlatformFaultDomainCount 2 `
                           -PlatformUpdateDomainCount 5 `
                           -ResourceGroupName $rgName `
                           -location $location
$availabilitySet = Get-AzureRmAvailabilitySet `
                   -Name $availabilitySetName `
                   -ResourceGroupName $rgName

# 创建用户 Credential
$securePassword = ConvertTo-SecureString $userPassword `
                                         -AsPlainText -Force
$userCred = New-Object System.Management.Automation.PSCredential `
            ($userName, $securePassword)

# 创建第一台虚机,可以以同样的方式创建第二台虚机
$vm1 = New-AzureRmVMConfig -VMName $vm1Name `
                           -VMSize $vmSize `
                           -AvailabilitySetId $availabilitySet.Id
$vm1 = Set-AzureRmVMOperatingSystem `
       -VM $vm1 `
       -Linux `
       -ComputerName $vm1ComputerHostName `
       -Credential $userCred `
       -DisablePasswordAuthentication
$vm1 = Set-AzureRmVMSourceImage `
       -VM $vm1 `
       -PublisherName Canonical `
       -Offer UbuntuServer `
       -Skus $vmVersion `
       -Version "latest"
$vm1 = Set-AzureRmVMBootDiagnostics `
       -VM $vm1 `
       -Disable
$vm1 = Add-AzureRmVMNetworkInterface `
       -VM $vm1 `
       -Id $nic1.Id `
       -Primary
$vm1 = Set-AzureRmVMOSDisk `
       -VM $vm1 `
       -Name $vm1DiskName `
       -CreateOption FromImage `
       -StorageAccountType $storageAccountTypeName
Add-AzureRmVMSshPublicKey `
    -VM $vm1 `
    -KeyData $sshPublicKey `
    -Path "/home/$userName/.ssh/authorized_keys"
New-AzureRmVM -ResourceGroupName $rgName `
              -Location $location `
              -VM $vm1

到这里我们的 Load Balancer 已经创建完成了,完整的脚本代码请参考这里

在 Azure 门户上的 Cloud Shell 中执行脚本

假设你已经编辑好了自己的 Load Balancer 创建脚本,并命名为 azureloadbalancer.sp1。让我们先把脚本上传到 Azure 门户上的 Cloud Shell 中,然后在 Cloud Shell 中执行该脚本:

Azure Load Balancer : 支持 IPv6-LMLPHP

脚本执行完成后,一个支持 IPv6 的 Load Balancer 就部署成功了:

Azure Load Balancer : 支持 IPv6-LMLPHP

总结

虽然写脚本比 UI 操作的难度要高一些,但是一旦这些脚本写好了今后就可以通过重用这些脚本来提升自动化的程度,绝对是物有所值!在后续的文章中,笔者将介绍如何使用 PowerShell 脚本扩展支持 IPv6 的 Load Balancer 后端的虚机池。

参考:
用 PowerShell 创建支持 IPv6 的 Azure Load Balancer
Powershell load balancer
Azure Load Balancer 对 IPv6 的支持

01-29 09:42