Azure Service Fabric 中的 DNS 服务

DNS 服务是可选的系统服务,可以在群集中启用,以发现使用 DNS 协议的其他服务。

许多服务(特别是容器化服务)可以通过现存的 URL 来寻址。 能够使用标准 DNS 协议(而不是 Service Fabric 命名服务协议)解析这些名称是很有必要的。 借助 DNS 服务,可将 DNS 名称映射到服务名称,进而解析终结点 IP 地址。 此类功能可在不同的平台之间保持容器化服务的可移植性,并更方便地利用“直接迁移”方案,因为它支持使用现有的服务 URL,而无需重新编写代码来利用命名服务。

DNS 服务可将 DNS 名称映射到服务名称,然后由命名服务进行解析以返回服务终结点。 在创建时提供服务的 DNS 名称。 下图显示了 DNS 服务如何适用于无状态服务。 为简洁起见,虽然每个服务可以具有多个终结点,但关系图只显示了服务的一个终结点。

显示 DNS 服务如何将 DNS 名称映射到服务名称以实现无状态服务的关系图。

从 Service Fabric 版本 6.3 开始,Service Fabric DNS 协议经过扩展,现在包含用于寻址已分区的有状态服务的方案。 使用这些扩展可以通过有状态服务 DNS 名称和分区名称的组合来解析特定的分区 IP 地址。 支持所有三种分区方案:

  • 命名分区
  • 按范围分区
  • 单一实例分区

下图显示了 DNS 服务如何适用于分区有状态服务。

显示 DNS 服务如何将 DNS 名称映射到服务名称以实现分区有状态服务。

有关分区查询的详细信息,请参阅以下部分

OS 支持

尽管对 Linux 的支持目前仅限于容器化服务,并且无法通过 Azure 门户启用,但 Windows 和 Linux 群集都支持 DNS 服务。 但是,Windows 支持所有服务类型和部署模型。

启用 DNS 服务

注意

启用 DNS 服务将替代节点上的一些 DNS 设置。 如果在连接到 Internet 时遇到问题,请检查 DNS 设置。

新群集

使用 ARM 模板的群集

要使用 ARM 模板部署新群集,可以使用示例模板或编写自己的模板。 如果尚未启用,可以使用支持的最低 API 版本和添加适当的设置在模板中启用 DNS 服务。 有关如何完成此操作的详细信息,请参阅以下编号列表中的第 1 点和第 2 点。

使用 Azure 门户的群集

如果要在门户中创建标准群集,则默认情况下已在“加载项功能”部分下的“包括 DNS 服务”选项中启用了 DNS 服务。

通过门户为标准群集启用 DNS 服务的屏幕截图。

如果要在门户中创建托管群集,则默认情况下已在“加载项功能”部分下的“DNS 服务”选项中启用了 DNS 服务。

通过门户为托管群集启用 DNS 服务的屏幕截图。

现有群集

如果要更新现有托管群集以启用 DNS 服务,可以通过从群集资源页访问“加载项服务”页来从门户执行此操作。 或者可以使用下面引用的替代方法来启用 DNS 服务:

  • 通过用于部署群集的 ARM 模板(如果适用)。
  • 导航到 Azure 资源资源管理器上的群集并更新群集资源,如以下步骤中所示(步骤 2 及后续步骤)。
  • 导航到门户上的群集,然后单击“导出模板”。 若要了解详细信息,请参阅从资源组导出模板

现在你已获取模板,可以通过以下步骤启用 DNS 服务:

  1. 对于标准群集,检查是否已为 Microsoft.ServiceFabric/clusters 资源将 apiVersion 设置为 2017-07-01-preview 或更高版本,如果不是,请按以下示例所示进行更新:

    {
        "apiVersion": "2017-07-01-preview",
        "type": "Microsoft.ServiceFabric/clusters",
        "name": "[parameters('clusterName')]",
        "location": "[parameters('clusterLocation')]",
        ...
    }
    

    对于托管群集,检查是否已为 Microsoft.ServiceFabric/managedClusters 资源将 apiVersion 设置为 2020-01-01-preview 或更高版本,如果不是,请按以下示例所示进行更新:

    {
        "apiVersion": "2020-01-01-preview",
        "type": "Microsoft.ServiceFabric/managedClusters",
        "name": "[parameters('clusterName')]",
        "location": "[parameters('clusterLocation')]",
        ...
    }
    
  2. 现在,使用以下方式之一启用 DNS 服务:

    • 要启用带有默认设置的 DNS 服务,请将其添加到 properties 部分中的 addonFeatures 部分,如以下示例所示:

      "properties": {
        ...
        "addonFeatures": [
          "DnsService"
          ],
        ...
      }
      
    • 若要启用采用非默认设置的服务,请将 DnsService 节添加到 properties 节中的 fabricSettings 节。 在这种情况下,不需要将 DnsService 添加到 addonFeatures。 要详细了解可为 DNS 服务设置的属性,请参阅 DNS 服务设置

      "properties": {
       ...
       "fabricSettings": [
         ...
         {
           "name": "DnsService",
           "parameters": [
             {
               "name": "IsEnabled",
               "value": "true"
             },
             {
               "name": "<key>",
               "value": "<value>"
             }
           ]
         },
         ...
       ]
      }
      
  3. 通过这些更改更新群集模板后,请应用更改并等待升级完成。 完成升级后,DNS 系统服务将开始在群集中运行。 服务名称是 fabric:/System/DnsService,可以在 Service Fabric Explorer 的“系统”服务部分下找到它 。

注意

将 DNS 从禁用升级到启用时,Service Fabric Explorer 可能未反映新状态。 如果要解决问题,请通过修改模板中的升级策略重启节点。

设置服务的 DNS 名称

可以使用 ARM 模板、ApplicationManifest.xml 文件中的默认服务,或使用 PowerShell 命令设置服务的 DNS 名称。

服务的 DNS 名称在整个群集中是可解析的,因此,请务必确保 DNS 名称在整个群集中的唯一性。

强烈建议使用 <ServiceName>.<AppName> 命名方案;例如 service1.application1。 如果使用 Docker Compose 部署应用程序,服务会自动分配使用此命名方案的 DNS 名称。

使用 ARM 模板设置 DNS 名称

如果使用 ARM 模板来部署服务,则可以将 serviceDnsName 属性添加到相应的部分,并为其分配值。 示例如下所示:

标准群集

对于标准群集,检查是否已为 Microsoft.ServiceFabric/clusters/applications/services 资源将 apiVersion 设置为 2019-11-01-preview 或更高版本,如果不是,请按以下示例所示进行更新:

{
  "apiVersion": "2019-11-01-preview",
  "type": "Microsoft.ServiceFabric/clusters/applications/services",
  "name": "[concat(parameters('clusterName'), '/', parameters('applicationName'), '/', parameters('serviceName'))]",
  "location": "[variables('clusterLocation')]",
  "dependsOn": [
    "[concat('Microsoft.ServiceFabric/clusters/', parameters('clusterName'), '/applications/', parameters('applicationName'))]"
  ],
  "properties": {
    "provisioningState": "Default",
    "serviceKind": "Stateless",
    "serviceTypeName": "[parameters('serviceTypeName')]",
    "instanceCount": "-1",
    "partitionDescription": {
      "partitionScheme": "Singleton"
    },
    "correlationScheme": [],
    "serviceLoadMetrics": [],
    "servicePlacementPolicies": [],
    "serviceDnsName": "[parameters('serviceDnsName')]"
  }
}

托管群集

对于托管群集,检查是否已为 Microsoft.ServiceFabric/managedclusters/applications/services 资源将 apiVersion 设置为 2022-10-01-preview 或更高版本,如果不是,请按以下示例所示进行更新:

{
  "apiVersion": "2022-10-01-preview",
  "type": "Microsoft.ServiceFabric/managedclusters/applications/services",
  "name": "[concat(parameters('clusterName'), '/', parameters('applicationName'), '/', parameters('serviceName'))]",
  "location": "[variables('clusterLocation')]",
  "dependsOn": [
    "[concat('Microsoft.ServiceFabric/managedclusters/', parameters('clusterName'), '/applications/', parameters('applicationName'))]"
  ],
  "properties": {
    "serviceKind": "Stateless",
    "serviceTypeName": "[parameters('serviceTypeName')]",
    "instanceCount": "-1",
    "partitionDescription": {
      "partitionScheme": "Singleton"
    },
    "correlationScheme": [],
    "serviceLoadMetrics": [],
    "servicePlacementPolicies": [],
    "serviceDnsName": "[parameters('serviceDnsName')]"
  }
}

在 ApplicationManifest.xml 中为默认服务设置 DNS 名称

在 Visual Studio 中或所选的编辑器中打开项目,并打开 ApplicationManifest.xml 文件。 转到默认服务部分,为每个服务添加 ServiceDnsName 属性。 以下示例说明如何将服务的 DNS 名称设置为 stateless1.application1

<Service Name="Stateless1" ServiceDnsName="stateless1.application1">
  <StatelessService ServiceTypeName="Stateless1Type" InstanceCount="[Stateless1_InstanceCount]">
    <SingletonPartition />
  </StatelessService>
</Service>

以下示例将有状态服务的 DNS 名称设置为 stateful1.application1。 该服务使用命名分区方案。 请注意分区名称均为小写。 这是在 DNS 查询中用作目标的分区的一项要求;有关详细信息,请参阅针对有状态服务分区发出 DNS 查询

<Service Name="Stateful1" ServiceDnsName="stateful1.application1" />
  <StatefulService ServiceTypeName="Stateful1Type" TargetReplicaSetSize="2" MinReplicaSetSize="2">
    <NamedPartition>
      <Partition Name="partition1" />
      <Partition Name="partition2" />
    </NamedPartition>
  </StatefulService>
</Service>

使用 PowerShell 设置服务的 DNS 名称

可在创建时使用 New-ServiceFabricService PowerShell 命令设置服务的 DNS 名称。 以下示例将会创建一个 DNS 名称为 stateless1.application1 的新的无状态服务:

New-ServiceFabricService `
    -Stateless `
    -PartitionSchemeSingleton `
    -ApplicationName fabric:/application1 `
    -ServiceName fabric:/application1/stateless1 `
    -ServiceTypeName Stateless1Type `
    -InstanceCount 1 `
    -ServiceDnsName stateless1.application1

还可以使用 Update-ServiceFabricService PowerShell 命令来更新现有服务。 以下示例更新了现有无状态服务以添加 DNS 名称 stateless1.application1

Update-ServiceFabricService `
    -Stateless `
    -ServiceName fabric:/application1/stateless1 `
    -ServiceDnsName stateless1.application1

验证是否已在 Service Fabric Explorer 中设置 DNS 名称

使用 DNS 名称部署服务后,Service Fabric Explorer 将显示服务的 DNS 名称,如下图所示:

Service Fabric Explorer 中 DNS 名称的屏幕截图。

注意

此视图可能因使用的 Service Fabric Explorer 版本而异,但 DNS 名称字段应在服务页上以某种形式显示。

针对有状态服务分区发出 DNS 查询

从 Service Fabric 版本 6.3 开始,DNS 服务支持面向服务分区的查询。 要启用对分区服务查询的支持,必须更新 DNS 服务设置,以将选项 EnablePartitionedQuery 设置为 true

对于 DNS 查询中使用的分区,适用以下命名限制:

  • 分区名称应符合 DNS 规范。
  • 不应使用包含圆点或“.”的多标签分区名称。
  • 分区名称应为小写。

针对分区的 DNS 查询的格式如下:

    <First-Label-Of-Partitioned-Service-DNSName><PartitionPrefix><Target-Partition-Name><PartitionSuffix>.<Remaining-Partitioned-Service-DNSName>

其中:

  • First-Label-Of-Partitioned-Service-DNSName 是服务 DNS 名称的第一个部分。
  • PartitionPrefix 是可以在群集清单的 DnsService 部分中设置的值,或者是可通过群集的 ARM 模板设置的值。 默认值为“--”。 有关详细信息,请参阅 DNS 服务设置
  • Target-Partition-Name 是分区的名称。
  • PartitionSuffix 是可以在群集清单的 DnsService 节中设置的,或者是可通过群集的 ARM 模板设置的值。 默认值为空字符串。 有关详细信息,请参阅 DNS 服务设置
  • Remaining-Partitioned-Service-DNSName 是服务 DNS 名称的剩余部分。

以下示例显示了针对某个群集(该群集对 PartitionPrefixPartitionSuffix 采用默认设置)上运行的分区服务发出的 DNS 查询:

  • 若要解析具有 DNS 名称 backendrangedschemesvc.application(使用按范围分区方案)的服务的分区“0”,请使用 backendrangedschemesvc--0.application
  • 若要解析具有 DNS 名称 backendnamedschemesvc.application(使用命名分区方案)的服务的分区“first”,请使用 backendnamedschemesvc--first.application

DNS 服务将返回与该分区主要副本关联的终结点的 IP 地址。 如果未指定分区,则 DNS 服务将随机选择分区。

在服务中使用 DNS 名称

如果使用 DNS 名称部署服务,则可以通过引用 DNS 名称来查找公开终结点的 IP 地址。 DNS 服务适用于无状态服务,并且在 Service Fabric 版本 6.3 和更高版本中也适用于有状态服务。 对于运行低于 6.3 版本的 Service Fabric 的有状态服务,可以使用适用于 HTTP 调用的内置反向代理服务来调用特定的服务分区。

DNS 服务不支持动态端口。 可以通过反向代理服务解析使用动态端口的服务。

以下代码演示如何通过 DNS 调用无状态服务。 它只是一个常规 http 调用,你将在其中提供 DNS 名称、端口和任何可选路径作为 URL 的一部分。

public class ValuesController : Controller
{
    // GET api
    [HttpGet]
    public async Task<string> Get()
    {
        string result = "";
        try
        {
            Uri uri = new Uri("http://stateless1.application1:8080/api/values");
            HttpClient client = new HttpClient();
            var response = await client.GetAsync(uri);
            result = await response.Content.ReadAsStringAsync();

        }
        catch (Exception e)
        {
            Console.Write(e.Message);
        }

        return result;
    }
}

以下代码演示如何调用有状态服务的特定分区。 在本例中,DNS 名称包含分区名称 (partition1)。 该调用假设群集对PartitionPrefixPartitionSuffix 使用默认值。

public class ValuesController : Controller
{
    // GET api
    [HttpGet]
    public async Task<string> Get()
    {
        string result = "";
        try
        {
            Uri uri = new Uri("http://stateful1--partition1.application1:8080/api/values");
            HttpClient client = new HttpClient();
            var response = await client.GetAsync(uri);
            result = await response.Content.ReadAsStringAsync();

        }
        catch (Exception e)
        {
            Console.Write(e.Message);
        }

        return result;
    }
}

递归查询

对于 DNS 服务无法自行解析的 DNS 名称(例如公共 DNS 名称),它会将查询转发到节点上预先存在的递归 DNS 服务器。

显示如何解析对公共名称的 DNS 查询的关系图。

在 Service Fabric 9.0 之前,会按 5 秒的超时期限对这些服务器进行连续查询,直到收到响应为止。 如果服务器在超时期间未响应,则将查询下一台服务器(如果提供)。 如果这些 DNS 服务器遇到任何问题,则完成 DNS 查询将需要 5 秒以上的时间,这并不理想。

从 Service Fabric 9.0 开始,添加了对并行递归查询的支持。 通过并行查询,可以同时联系所有递归 DNS 服务器,以第一台响应的服务器为准。 在上面提及的方案中,这会导致更快的响应。 默认情况下不启用此选项。

Service Fabric 9.0 中还引入了细粒度选项来控制递归查询的行为,包括超时时间和查询尝试。 可以在 DNS 服务设置中设置这些选项:

  • RecursiveQuerySerialMaxAttempts - 最多尝试的串号查询数。 如果此数字高于转发 DNS 服务器的数字,查询将在恰好尝试所有服务器一次后停止。
  • RecursiveQuerySerialTimeout - 每个尝试的串号查询的超时值(以秒为单位)。
  • RecursiveQueryParallelMaxAttempts - 将尝试并行查询的次数。 在已耗尽串号查询的最大尝试后,将执行并行查询。
  • RecursiveQueryParallelTimeout - 每次尝试的并行查询的超时值(以秒为单位)。

限制和已知问题

  • DNS 服务不支持动态端口。 若要解析动态端口上公开的服务,请使用反向代理服务
  • 对 Linux 的支持目前仅限于容器化服务。 Linux 上基于进程的服务当前无法使用 DNS 服务。
  • 无法通过 Azure 门户来启用面向 Linux 群集的 DNS 服务。
  • 如果更改了服务的 DNS 名称,则在某些情况下可能不会立即显示名称更新。 要解决此问题,应跨群集重启 DNS 服务实例。

后续步骤

通过连接服务并与服务进行通信,了解有关群集内服务通信的详细信息