Azure Service Fabric IPv6网络问题

时间:2018-05-28 22:48:20

标签: azure-service-fabric azure-load-balancer

我们遇到了将Service Fabric群集部署到Azure并让它同时处理IPv4的问题 和IPv6流量。

我们正在开发一个在iOS和Android上与移动客户端进行通信的应用程序 我们的Service Fabric集群。通信包括HTTP流量以及TCP套接字通信。 我们需要支持IPv6才能让Apple在他们的App Store中接受该应用程序。

我们正在使用ARM模板部署到Azure,因为门户似乎不支持配置 具有IPv6配置的负载均衡器,用于虚拟机规模集(参考:url)。链接页面还说明了其他限制 对IPv6支持,例如私有IPv6地址无法部署到VM Scale Sets。但是根据 在this页面中,预览可以将私有IPv6分配给VM Scale Sets (虽然这是最后更新于2017年7月14日)。

对于这个问题,我试图尽可能保持这一点,并在找到的模板上基于ARM模板 在this tutorial。该模板被称为" template_original.json"并可以从。下载 here。这是服务结构集群的基本模板,为简单起见,没有安全性。

我将在本文的底部链接整个修改过的ARM模板,但会突出显示 主要修改部分首先。

与负载均衡器关联的公共IPv4和IPv6地址。这些与其各自的后端池相关联:

"frontendIPConfigurations": [
    {
        "name": "LoadBalancerIPv4Config",
        "properties": {
            "publicIPAddress": {
                "id": "[resourceId('Microsoft.Network/publicIPAddresses',concat(parameters('lbIPv4Name'),'-','0'))]"
            }
        }
    },
    {
        "name": "LoadBalancerIPv6Config",
        "properties": {
            "publicIPAddress": {
                "id": "[resourceId('Microsoft.Network/publicIPAddresses',concat(parameters('lbIPv6Name'),'-','0'))]"
            }
        }
    }
],
"backendAddressPools": [
    {
        "name": "LoadBalancerIPv4BEAddressPool",
        "properties": {}
    },
    {
        "name": "LoadBalancerIPv6BEAddressPool",
        "properties": {}
    }
],

各个公共IP地址(IPv4和IPv6)上的前端端口的负载平衡规则。 这相当于四个规则,每个前端端口两个。我在这里为HTTP添加了端口80,为Socket连接添加了端口5607。 注意我已将IPv6端口80的后端端口更新为8081,将IPv6端口8507更新为8517.

{
    "name": "AppPortLBRule1Ipv4",
    "properties": {
        "backendAddressPool": {
            "id": "[variables('lbIPv4PoolID0')]"
        },
        "backendPort": "[parameters('loadBalancedAppPort1')]",
        "enableFloatingIP": "false",
        "frontendIPConfiguration": {
            "id": "[variables('lbIPv4Config0')]"
        },
        "frontendPort": "[parameters('loadBalancedAppPort1')]",
        "idleTimeoutInMinutes": "5",
        "probe": {
            "id": "[concat(variables('lbID0'),'/probes/AppPortProbe1')]"
        },
        "protocol": "tcp"
    }
},
{
    "name": "AppPortLBRule1Ipv6",
    "properties": {
        "backendAddressPool": {
            "id": "[variables('lbIPv6PoolID0')]"
        },
        /*"backendPort": "[parameters('loadBalancedAppPort1')]",*/
        "backendPort": 8081,
        "enableFloatingIP": "false",
        "frontendIPConfiguration": {
            "id": "[variables('lbIPv6Config0')]"
        },
        "frontendPort": "[parameters('loadBalancedAppPort1')]",
        /*"idleTimeoutInMinutes": "5",*/
        "probe": {
            "id": "[concat(variables('lbID0'),'/probes/AppPortProbe1')]"
        },
        "protocol": "tcp"
    }
},
{
    "name": "AppPortLBRule2Ipv4",
    "properties": {
        "backendAddressPool": {
            "id": "[variables('lbIPv4PoolID0')]"
        },
        "backendPort": "[parameters('loadBalancedAppPort2')]",
        "enableFloatingIP": "false",
        "frontendIPConfiguration": {
            "id": "[variables('lbIPv4Config0')]"
        },
        "frontendPort": "[parameters('loadBalancedAppPort2')]",
        "idleTimeoutInMinutes": "5",
        "probe": {
            "id": "[concat(variables('lbID0'),'/probes/AppPortProbe2')]"
        },
        "protocol": "tcp"
    }
},
{
    "name": "AppPortLBRule2Ipv6",
    "properties": {
        "backendAddressPool": {
            "id": "[variables('lbIPv6PoolID0')]"
        },
        "backendPort": 8517,
        "enableFloatingIP": "false",
        "frontendIPConfiguration": {
            "id": "[variables('lbIPv6Config0')]"
        },
        "frontendPort": "[parameters('loadBalancedAppPort2')]",
        /*"idleTimeoutInMinutes": "5",*/
        "probe": {
            "id": "[concat(variables('lbID0'),'/probes/AppPortProbe2')]"
        },
        "protocol": "tcp"
    }
}

每个负载平衡规则也添加了一个探测器,但为清楚起见,这里省略了。

虚拟机规模集的apiVerison设置为" 2017-03-30"根据上述预览解决方案的建议。 网络接口配置也根据建议进行配置。

"networkInterfaceConfigurations": [
    {
        "name": "[concat(parameters('nicName'), '-0')]",
        "properties": {
            "ipConfigurations": [
                {
                    "name": "[concat(parameters('nicName'),'-IPv4Config-',0)]",
                    "properties": {
                        "privateIPAddressVersion": "IPv4",
                        "loadBalancerBackendAddressPools": [
                            {
                                "id": "[variables('lbIPv4PoolID0')]"
                            }
                        ],
                        "loadBalancerInboundNatPools": [
                            {
                                "id": "[variables('lbNatPoolID0')]"
                            }
                        ],
                        "subnet": {
                            "id": "[variables('subnet0Ref')]"
                        }
                    }
                },
                {
                    "name": "[concat(parameters('nicName'),'-IPv6Config-',0)]",
                    "properties": {
                        "privateIPAddressVersion": "IPv6",
                        "loadBalancerBackendAddressPools": [
                            {
                                "id": "[variables('lbIPv6PoolID0')]"
                            }
                        ]
                    }
                }
            ],
        "primary": true
        }
    }
]

使用此模板,我可以将其成功部署到Azure。使用IPv4的通信 群集按预期工作,但我无法获得任何IPv6流量。这是 端口80(HTTP)和5607(套接字)都相同。

在Azure门户中查看负载均衡器的后端池列表时,会显示 以下信息消息,我一直无法找到任何信息。我不确定 如果这会以任何方式影响任何事情?

Backend pool 'loadbalanceripv6beaddresspool' was removed from Virtual machine scale set 'Node1'. Upgrade all the instances of 'Node1' for this change to apply Node1

load balancer error message

我不知道为什么我无法通过IPv6获得流量。可能是我有一些东西 我错过了模板,或者我的其他一些错误?如果需要任何其他信息 不要犹豫。

这是整个ARM模板。由于长度和帖子长度限制,我没有嵌入它,但这里是Pastebin link to the full ARM Template (Updated)

更新

有关调试IPv6连接的一些信息。我尝试稍微改变ARM模板,将端口80上的IPv6流量转发到后端端口8081。因此,IPv4是80 => 80并且IPv6 80 => 8081。 ARM模板已更新(请参阅上一节中的链接)。

在端口80上我运行Kestrel作为无状态Web服务器。我在ServiceManifest.xml中有以下条目:

<Endpoint Protocol="http" Name="ServiceEndpoint1" Type="Input" Port="80" />      
<Endpoint Protocol="http" Name="ServiceEndpoint3" Type="Input" Port="8081" />

我特别不确定哪些地址可以在Kestrel中收听。使用FabricRuntime.GetNodeContext()。IPAddressOrFQDN始终返回IPv4地址。这是我们目前的开始。为了调试这个,我目前得到了所有的IPv6地址,以及我们使用该地址的端口8081的硬编码黑客。 Fort端口80使用IPAddress.IPv6Any,但是它总是默认为FabricRuntime.GetNodeContext()返回的IPv4地址.IPAddressOrFQDN。

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
    var endpoints = Context.CodePackageActivationContext.GetEndpoints()
        .Where(endpoint => endpoint.Protocol == EndpointProtocol.Http ||
                           endpoint.Protocol == EndpointProtocol.Https);

    var strHostName = Dns.GetHostName();
    var ipHostEntry = Dns.GetHostEntry(strHostName);
    var ipv6Addresses = new List<IPAddress>();

    ipv6Addresses.AddRange(ipHostEntry.AddressList.Where(
        ipAddress => ipAddress.AddressFamily == AddressFamily.InterNetworkV6));

    var listeners = new List<ServiceInstanceListener>();

    foreach (var endpoint in endpoints)
    {
        var instanceListener = new ServiceInstanceListener(serviceContext =>
            new KestrelCommunicationListener(
                serviceContext,
                (url, listener) => new WebHostBuilder().
                    UseKestrel(options =>
                    {
                        if (endpoint.Port == 8081 && ipv6Addresses.Count > 0)
                        {
                            // change idx to test different IPv6 addresses found
                            options.Listen(ipv6Addresses[0], endpoint.Port);
                        }
                        else
                        {
                            // always defaults to ipv4 address
                            options.Listen(IPAddress.IPv6Any, endpoint.Port);
                        }
                    }).
                    ConfigureServices(
                        services => services
                            .AddSingleton<StatelessServiceContext>(serviceContext))
                    .UseContentRoot(Directory.GetCurrentDirectory())
                    .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
                    .UseStartup<Startup>()
                    .UseUrls(url)
                    .Build()), endpoint.Name);
        listeners.Add(instanceListener);
    }

    return listeners;
}

以下是Service Fabric Explorer中为其中一个节点显示的端点:Endpoint addresses

关于套接字监听器,我也进行了更改,以便将IPv6转发到后端端口8517而不是8507.与Kestrel Web服务器类似,套接字监听器将使用适当的端口在相应的地址上打开两个监听实例。

我希望这些信息有任何帮助。

1 个答案:

答案 0 :(得分:0)

事实证明我犯了一个非常愚蠢的错误,完全是我的错,我忘了确实验证我的ISP完全支持IPv6。事实证明他们没有!

从具有完全IPv6支持的提供程序进行测试可以正常工作,并且我能够与Service Fabric群集中的节点完全连接。

Here是适用于需要具有IPv4和IPv6支持的Service Fabric群集的完整工作示例的任何人的工作ARM模板:

Not allowed to post pastebin links without a accompanied code snippet...

更新:

由于长度限制,模板无法完整地粘贴到此线程中,但是在Service Fabric I的GitHub问题页面上交叉了这个。 ARM模板作为注释发布在该线程中,它有望比pastebin链接更长。查看here