1

Service Fabric クラスターを Azure にデプロイする際に問題が発生し、IPv4 と IPv6 の両方のトラフィックを処理します。

Service Fabric クラスターと通信する iOS および Android 上のモバイル クライアントを持つアプリケーションを開発しています。通信は、HTTP トラフィックと TCP ソケット通信の両方で構成されます。Apple に App Store でアプリを受け入れてもらうには、IPv6 をサポートする必要があります。

Azure へのデプロイに ARM テンプレートを使用しています。これは、ポータルが仮想マシン スケール セットの IPv6 構成を使用したロード バランサーの構成をサポートしていないように見えるためです (参照: url )。リンク先のページには、プライベート IPv6 アドレスを VM スケール セットにデプロイできないなど、IPv6 サポートに対するその他の制限も記載されています。ただし、このページによると、プライベート IPv6 を VM スケール セットに割り当てる可能性はプレビューで利用できます (ただし、これは 2017 年 7 月 14 日に最終更新されました)。

この質問では、これを可能な限り一般的に保ち、このチュートリアルにあるテンプレートに基づいて 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 の両方) でのフロントエンド ポートの負荷分散規則。これは合計で 4 つのルールになり、フロント エンド ポートごとに 2 つになります。ここでは、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"
    }
}

また、負荷分散ルールごとに 1 つのプローブを追加しましたが、わかりやすくするためにここでは省略しました。

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 portal でロード バランサーのバックエンド プールのリストを表示すると、次の情報メッセージが表示されますが、これに関する情報を見つけることができませんでした。これが何らかの形で何かに影響するかどうかはわかりませんか?

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 テンプレート全体を次に示します。長さと投稿の長さの制限により、私はそれを埋め込んでいませんが、完全な ARM テンプレート (更新済み) への Pastebin リンクを次に示します。

アップデート

IPv6 接続のデバッグに関する情報。ポート 80 の IPv6 トラフィックをバックエンド ポート 8081 に転送するように ARM テンプレートを少し変更してみました。したがって、IPv4 は 80=>80、IPv6 は 80=>8081 です。ARM テンプレートが更新されました (前のセクションのリンクを参照)。

ポート 80 で、ステートレス Web サーバーとして Kestrel を実行しています。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().IPAddressOrFQDN によって返される 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;
}

ノードの 1 つの Service Fabric Explorer に表示されるエンドポイントを次に示します。

ソケット リスナーに関しても、IPv6 がバックエンド ポート 8507 ではなく 8517 に転送されるように変更しました。同様に、Kestrel Web サーバーと同様に、ソケット リスナーは、適切なポートを持つそれぞれのアドレスで 2 つのリッスン インスタンスを開きます。

この情報が少しでもお役に立てば幸いです。

4

1 に答える 1