【问题标题】:Dynamic Servicefabric Settings and Overrides动态 Servicefabric 设置和覆盖
【发布时间】:2019-03-22 08:04:20
【问题描述】:

有没有办法完全不告诉服务有关设置而只在应用程序级别提供它们?

我仍然对 servicefabric 配置的工作方式不满意。

据我所知,我必须在服务的 settings.xml 中指定所有可能的配置值。然后我可以覆盖应用程序的 ApplicationParameters 中的那些。根据文档,这看起来也适用于环境变量。

造成的复杂情况是,我们的配置在许多情况下用于对数组进行水合选项。

例如考虑json:

{
  "AuthorizationOptions": {
    "Policies": [
      {
        "Name": "User",
        "Groups": [ "Domain Users" ]
      }
    ]
  }  
}

有2个数组;这是必要和有用的。为了在服务结构配置中表达这一点,它转换为:

<Section Name="AuthorizationOptions">
    <Parameter Name="Policies:0:Name" Value="User"/>
    <Parameter Name="Policies:0:Groups:0" Value="Domain Users"/>
</Section>

虽然与结构化对象相比,翻译并不令人愉快,但它是完全可用的。

但是,如果我没有在服务中指定部分和参数,我似乎无法在应用程序中覆盖它们。因此,在这种情况下,我必须定义服务中每个策略的确切策略和组数,并且应用程序可以修改策略名称或组值,但不能修改策略总数或组总数。

有没有办法完全不告诉服务有关设置而只在应用程序级别提供它们?

如果不存在使服务可跨应用程序重用的替代方案,我可能希望使用这些替代方案以不同方式提供这种类型的动态配置?

可能有助于回答这个问题的最后一部分是我正在使用一些 pre-release code 将服务结构设置转换为 Microsoft.Extensions.Configuration.IConfiguration。但是,这只是采用它找到的设置;这不是我遇到的覆盖问题的原因。

示例服务设置.xml:

<?xml version="1.0" encoding="utf-8" ?>
<Settings xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2011/01/fabric">
  <Section Name="AuthorizationOptions">
    <!-- I should not have to provide these at the application level!
         However, it fails to deploy if I don't. -->
    <Parameter Name="Policies:0:Name" Value="User"/>
    <Parameter Name="Policies:0:Groups:0" Value="Domain Users"/>
  </Section>
</Settings>

示例应用ApplicationManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<ApplicationManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ApplicationTypeName="ServiceFabric.ExampleType" ApplicationTypeVersion="1.0.0" xmlns="http://schemas.microsoft.com/2011/01/fabric">
  <Parameters>
    <Parameter Name="Service.Example_ASPNETCORE_ENVIRONMENT" DefaultValue="" />
    <Parameter Name="Service.Example_InstanceCount" DefaultValue="-1" />
    <Parameter Name="Service.Example_AuthorizationOptions_Policies_0_Name" DefaultValue="Users" />
    <Parameter Name="Service.Example_AuthorizationOptions_Policies_0_Groups_0" DefaultValue="Domain Users" />
  </Parameters>
  <ServiceManifestImport>
  <ServiceManifestImport>
    <ServiceManifestRef ServiceManifestName="Service.ExamplePkg" ServiceManifestVersion="1.0.0" />
    <ConfigOverrides>
      <ConfigOverride Name="Config">
        <Settings>
          <Section Name="AuthorizationOptions">
            <Parameter Name="Policies:0:Name" Value="[Service.Example_AuthorizationOptions_Policies_0_Name]" />
            <Parameter Name="Policies:0:Groups:0" Value="[Service.Example_AuthorizationOptions_Policies_0_Groups_0]" />
          </Section>
        </Settings>
      </ConfigOverride>
    </ConfigOverrides>
    <EnvironmentOverrides CodePackageRef="code">
      <EnvironmentVariable Name="ASPNETCORE_ENVIRONMENT" Value="[Service.Example_ASPNETCORE_ENVIRONMENT]" />
    </EnvironmentOverrides>
  </ServiceManifestImport>
  <DefaultServices>
    <Service Name="Service.Example" ServicePackageActivationMode="ExclusiveProcess">
      <StatelessService ServiceTypeName="Service.ExampleType" InstanceCount="[Service.Example_InstanceCount]">
        <SingletonPartition />
      </StatelessService>
    </Service>
  </DefaultServices>
</ApplicationManifest>

示例应用ApplicationParameters(Local.1Node.xml):

<?xml version="1.0" encoding="utf-8"?>
<Application xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Name="fabric:/ServiceFabric.Example" xmlns="http://schemas.microsoft.com/2011/01/fabric">
  <Parameters>
    <Parameter Name="Service.Example_ASPNETCORE_ENVIRONMENT" Value="Development" />
    <Parameter Name="Service.Example_InstanceCount" Value="-1" />
    <Parameter Name="Service.Example_AuthorizationOptions_Policies_0_Name" Value="Users" />
    <Parameter Name="Service.Example_AuthorizationOptions_Policies_0_Groups_0" Value="Domain Users" />
  </Parameters>
</Application>

示例应用程序发布配置文件(Local.1Node.xml):

<?xml version="1.0" encoding="utf-8"?>
<PublishProfile xmlns="http://schemas.microsoft.com/2015/05/fabrictools">
  <ClusterConnectionParameters />
  <ApplicationParameterFile Path="..\ApplicationParameters\Local.1Node.xml" />
</PublishProfile>

应该是无关的,但是设置的例子消费:

internal sealed class Example : StatelessService
{
    public Example(StatelessServiceContext context)
        : base(context)
    { }

    protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
    {
        return new ServiceInstanceListener[]
        {
            new ServiceInstanceListener(serviceContext =>
                new HttpSysCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
                {
                    ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting HttpSys on {url}");

                    return new WebHostBuilder()
                            .UseHttpSys(options =>
                            {
                                options.Authentication.Schemes = AuthenticationSchemes.Negotiate; // Microsoft.AspNetCore.Server.HttpSys
                                                                                        options.Authentication.AllowAnonymous = false;
                            }).ConfigureServices(services => services.AddSingleton<StatelessServiceContext>(serviceContext))
                                        .UseContentRoot(Directory.GetCurrentDirectory())
                                        .ConfigureAppConfiguration((hostingContext, config) =>
                                            {
                                                config.SetBasePath(Directory.GetCurrentDirectory());
                                                config.AddServiceFabricConfiguration(FabricRuntime.GetActivationContext(), options => {
                                                    options.IncludePackageName=false;
                                                });
                                            })
                                        .UseStartup<Startup>()
                                        .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
                                        .UseUrls(url)
                                        .Build();
                }))
        };
    }
}

从那时起,一切都按预期在 IConfiguration 对象中。

【问题讨论】:

    标签: azure-service-fabric service-fabric-on-premises


    【解决方案1】:

    有很多方法可以配置 Service Fabric 应用程序,每种方法都会给您带来不同的挑战。

    SF 团队推荐文档中的方法,因为您可以对配置进行更好的版本控制,并且更难犯错误,因为它在文件中明确声明,由于限制,我使用了几种不同的方法像您一样,以下方法可能会解决您的问题:

    像原始方法一样配置,但将复杂类型存储为 JSON 值:它是最接近推荐设计的解决方案,您仍然可以控制源代码管理中的配置版本。 p>

    应该是这样的:

    Settings.xml:

    <?xml version="1.0" encoding="utf-8" ?>
    <Settings xmlns... namespaces here...>
      <Section Name="AuthorizationOptions">
        <Parameter Name="Policies"/>
      </Section>
    </Settings>
    

    ApplicationManifest.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <ApplicationManifest ApplicationTypeName="ServiceFabric.ExampleType" ApplicationTypeVersion="1.0.0" xmlns:...namespaces....>
      <Parameters>
        <Parameter Name="Service.Example_ASPNETCORE_ENVIRONMENT" DefaultValue="" />
        <Parameter Name="Service.Example_InstanceCount" DefaultValue="-1" />
        <Parameter Name="Service.Example_AuthorizationOptions_Policies" DefaultValue="[]" />
      </Parameters>
      <ServiceManifestImport>
      <ServiceManifestImport>
        <ServiceManifestRef ServiceManifestName="Service.ExamplePkg" ServiceManifestVersion="1.0.0" />
        <ConfigOverrides>
          <ConfigOverride Name="Config">
            <Settings>
              <Section Name="AuthorizationOptions">
                <Parameter Name="Policies" Value="[Service.Example_AuthorizationOptions_Policies]" />
              </Section>
            </Settings>
          </ConfigOverride>
        </ConfigOverrides>
        <EnvironmentOverrides CodePackageRef="code">
          <EnvironmentVariable Name="ASPNETCORE_ENVIRONMENT" Value="[Service.Example_ASPNETCORE_ENVIRONMENT]" />
        </EnvironmentOverrides>
      </ServiceManifestImport>
      <DefaultServices>
        <Service Name="Service.Example" ServicePackageActivationMode="ExclusiveProcess">
          <StatelessService ServiceTypeName="Service.ExampleType" InstanceCount="[Service.Example_InstanceCount]">
            <SingletonPartition />
          </StatelessService>
        </Service>
      </DefaultServices>
    </ApplicationManifest>
    

    ApplicationParameters.xml

    <?xml version="1.0" encoding="utf-8"?>
    <Application Name="fabric:/ServiceFabric.Example" xmlns:...namespaces....>
      <Parameters>
        <Parameter Name="Service.Example_ASPNETCORE_ENVIRONMENT" Value="Development" />
        <Parameter Name="Service.Example_InstanceCount" Value="-1" />
        <Parameter Name="Service.Example_AuthorizationOptions_Policies" Value="[{'Name': 'User','Groups': ['Domain Users']}, {'Name': 'Admin','Groups': ['Administrators']}]" />
      </Parameters>
    </Application>
    

    在您的服务代码中:

    public class Policy
    {
        public string Name { get; set; }
        public string[] Groups { get; set; }
    }
    
    
    var settings = this.Context.CodePackageActivationContext.GetConfigurationPackageObject("Config").Settings;
    var authOptions = settings.Sections["AuthorizationOptions"].Parameters["Policies"].Value;
    var obj = JsonConvert.DeserializeObject<Policy[]>(authOptions);
    

    您可以更进一步并存储整个 AuthorizationOptions 作为 JSON,但就像之前所说的,更多 它变得通用,更容易犯错误,更难找到 配置问题。

    【讨论】:

    • 不错的一个。您是否尝试过以 JSON 形式部署配置作为数据包的一部分?在服务内部,您可以订阅数据包更改事件并刷新配置。
    • 这也是一个有效的选项,我在很少更改值的情况下使用它,因为它更难更新,我们需要在需要更新时部署新的包版本这些值,上述方法使其更加灵活,我们只需要使用新参数触发升级。
    猜你喜欢
    • 1970-01-01
    • 2012-01-22
    • 2012-11-15
    • 1970-01-01
    • 2011-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多