我们在将Service集群部署到Azure并让它同时处理IPv4和IPv6流量时遇到了问题。
我们正在开发一个应用程序,它在iOS和安卓上都有移动客户端,它们可以与我们的Service集群通信。通信包括HTTP通信和TCP套接字通信。我们需要支持IPv6,以便让苹果在他们的应用商店中接受这个应用程序。
我们使用ARM模板部署到Azure,因为门户似乎不支持为虚拟机规模集配置带有IPv6配置的负载均衡器(ref:url)。链接的页面还说明了对IPv6支持的其他限制,例如不能将私有IPv6地址部署到VM比例集。然而,根据这页面,可以在预览中将私有IPv6分配给VM规模集(尽管这是最后一次更新07/14/2017)。
对于这个问题,我试图保持尽可能的一般性,并将ARM模板建立在本教程中的一个模板上。模板名为"template_original.json“,可以从这里下载。这是服务结构集群的基本模板,没有简单的安全性。
我将链接整个修改后的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,为套接字连接添加了端口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"
}
}还添加了每个负载平衡规则一个探针,但为了清楚起见,这里省略了。
根据上述预览解决方案的建议,VM刻度集的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我不知道为什么我不能让交通通过IPv6。可能是我在模板中漏掉了什么,或者是我自己犯了其他错误?如果需要更多的信息,请不要犹豫。
这是整个手臂模板。由于长度和后置长度的限制,我没有嵌入它,但是这里是一个与完整ARM模板的Pastebin链接(更新)。
更新
有关调试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" />我一直有点不确定,确切地说,哪一个地址应该听在“凯斯雷尔”里。使用FabricRuntime.GetNodeContext().IPAddressOrFQDN总是返回IPv4地址。我们现在就是这样开始的。为了调试这一点,我目前获得了所有的IPv6地址,以及我们使用该地址的端口8081的硬编码黑客。Fort 80使用IPAddress.IPv6Any,但是这始终默认为IPAddress.IPv6Any返回的IPv4地址
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中显示的端点:端点地址
对于套接字侦听器,我也做了修改,以便将IPv6转发到后端端口8517,而不是8507。类似于Kestrel服务器,套接字侦听器将在各自的地址上打开两个具有适当端口的侦听实例。
我希望这些信息对我们有帮助。
发布于 2018-05-31 09:15:04
原来我犯了一个非常愚蠢的错误,这完全是我的错,我忘了验证我的ISP完全支持IPv6。原来他们不知道!
来自具有完全IPv6支持的提供者的测试可以正常工作,并且我能够获得到Service集群中节点的完全连接。
这里是任何需要IPv4和IPv6支持的服务结构集群的完全工作示例的工作ARM模板:
Not allowed to post pastebin links without a accompanied code snippet...更新:
由于长度限制,模板不能完全粘贴在这个线程中,但是在Service的GitHub pasted页面上,我交叉了这一点。ARM模板在该线程中作为注释发布,希望它比pastebin链接更长。查看它,这里。
https://stackoverflow.com/questions/50574231
复制相似问题