尝试在 Service Fabric 中容器化和发布 StatelessService 时出现异常

Posted

技术标签:

【中文标题】尝试在 Service Fabric 中容器化和发布 StatelessService 时出现异常【英文标题】:Exception when trying to containerize and publish StatelessService in Service Fabric 【发布时间】:2020-07-08 17:59:37 【问题描述】:

我有一个 .NET Core Reliable Service,它几乎是一个模板服务,从 Add > New Service Fabric Service > .NET Core Stateless Service 获得。这意味着它包含ServiceEventSource、一个继承自StatelessService 类的Stateless1 类和一个Program.csProgram.cs 的内容是默认的:

private static void Main()

    try
    
        ServiceRuntime.RegisterServiceAsync("Stateless1Type",
            context => new Stateless1(context)).GetAwaiter().GetResult();                ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(Stateless1).Name);
        Thread.Sleep(Timeout.Infinite);
    
    catch (Exception e)
                    ServiceEventSource.Current.ServiceHostInitializationFailed(e.ToString());
        throw;
    


现在,一切正常,我可以正确启动 Service Fabric 应用程序并查看日志等。

我想要完成的是将此服务容器化,根据以下文章:https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-services-inside-containers。这意味着我添加了SFBinaryLoader.cs 并将以下文件添加到我的Program.cs

static Program()

    SFBinaryLoader.Initialize();


但是,通过尝试这样做会出现许多文档未解决的问题和问题。

我使用microsoft/service-fabric-reliableservices-windowsservercore:1803 作为基础镜像来构建我的容器。这是因为 Windows 服务器主机是 1803 版。运行 CreateDockerPackage.ps1 后,我注意到 Microsoft.ServiceFabric.Data.Interfaces.dllSystem.Fabric.*.dll 正在被删除。

我认为这就是为什么我们必须在运行时再次提供。这是由SFBinaryLoader.cs 通过在AppDomain.CurrentDomain.AssemblyResolve 上添加一个事件侦听器来执行的。此类应查看FabricCodePath 环境变量(在运行时看起来绑定到C:\SFFabricBin\ 目录)并手动添加这些二进制文件。

我想说,为了让程序运行,我还必须从容器中删除 *.deps.json 文件,因为在运行 dotnet Stateless1.dll 之前我遇到了一个异常,指出在*.deps.json 文件未找到。

现在,看起来我的容器通过结构可以正常启动,并且程序集正在正确加载。但是,每当尝试通过以下行将服务注册到结构时:

ServiceRuntime.RegisterServiceAsync("Stateless1Type",
                    context => new Stateless1(context)).GetAwaiter().GetResult();

这会引发以下异常:

注册服务时发生异常 System.Fabric.FabricException:服务类型已注册。 ---> System.Runtime.InteropServices.COMException:来自 HRESULT 的异常:0x80071BD1 在 System.Fabric.Interop.NativeRuntime.IFabricRuntime.EndRegisterStatelessServiceFactory(IFabricAsyncOperationContext 上下文) 在 System.Fabric.Interop.Utility.c__DisplayClass22_0.b__0(IFabricAsyncOperationContext 上下文) 在 System.Fabric.Interop.AsyncCallOutAdapter21.Finish(IFabricAsyncOperationContext context, Boolean expectedCompletedSynchronously) --- End of inner exception stack trace --- at Microsoft.ServiceFabric.Services.Runtime.ServiceRuntime.RegisterServiceAsync(String serviceTypeName, Func2 serviceFactory,TimeSpan 超时,CancellationToken cancelToken) 在 C:\MyLocalPath\StatelessService\Program.cs:line 33 中的 Eventellect.Fabric.TestDocker.Program.Main() 处

你知道为什么会这样吗?我还觉得很奇怪,我的 已发布 服务结构对我的本地路径一无所知。

我已经在 try...catch 块内包围了 RegisterServiceAsync 调用,但是,即使线程成功进入睡眠并且我的 docker 容器没有停止,我的 Stateless1.cs 类中的操作也永远不会执行。这意味着甚至没有调用构造函数。

有什么我可能遗漏的吗?

【问题讨论】:

【参考方案1】:

我遇到了同样的问题,但我实现了以不同于 microsoft 文档中指示的方式将无状态服务容器化。

    microsoft/service-fabric-reliableservices-windowsservercore:1803 docker 映像已安装 .Net Core 运行时 2.0。如果您的无状态服务在更高版本上运行,它将无法工作。出于这个原因,我以这种方式构建了我的 docker 镜像docker image servicefabric-runtime。 我意识到 SFBinaryLoader.cs 类对于在容器内运行 Service Fabric Reliable Services 或 Reliable Actors 不是必需的。我没有将它添加到我的代码中。 我没有执行 CreateDockerPackage.ps1 来构建容器,我只修改了 ServiceManifest.xml 来更改 EntryPoint 部分,如下所示:
    <EntryPoint>
      <ContainerHost>
        <ImageName>statelesscontainer:0.1</ImageName>
      </ContainerHost>
    </EntryPoint>
    我将构建项目的输出路径更改为 pub/,并根据步骤 1 在无状态服务的根目录中手动添加了 Dockerfile,如下所示:
    FROM edalx/servicefabric-runtime:dotnetcore-3.1.2
    WORKDIR /app
    ADD pub .
    CMD ["ApiService.exe"]
    除了在 ApplicationManifest.xml 中还需要添加 PortBinding 标签。
  <ContainerHostPolicies CodePackageRef="Code" Isolation="process" ContainersRetentionCount="2">
      <HealthConfig />
      <PortBinding ContainerPort="0" EndpointRef="ServiceEndpoint" />
      <ImageOverrides>
         <Image Name="edalx.azurecr.io/statelesscontainer:0.1" />
      </ImageOverrides>
  </ContainerHostPolicies>
    我正在使用 Visual Studio Community 2019 进行部署,它会自动检测到它是一个容器,并像非容器化服务一样显示向导,它会完成所有工作。

我尝试使用 hyperv 隔离,但对我来说它不起作用。

你可以在我的 repo https://github.com/edalx/servicefabric-examples/tree/master/servicefabric-container找到一个完整的例子

【讨论】:

【参考方案2】:

请检查容器化服务包的 ServiceManifest.xml,以获取 UseImplicitHost。 UseImplicitHost 需要设置为“False”,以便可靠的用户进程能够向运行时注册。对于 GuestContainers 和 GuestExecutables,UseImplicitHost 设置为 true。

【讨论】:

以上是关于尝试在 Service Fabric 中容器化和发布 StatelessService 时出现异常的主要内容,如果未能解决你的问题,请参考以下文章

带有 Docker 容器和 windowsservercore 和 iis 服务器的 Service Fabric 集群

如何使用 TeamCity 在 Azure Service Fabric 中自动部署 Docker 容器?

HTTPS 在带有 Docker 容器的 Service Fabric 中不起作用

Azure Service Fabric - 如何配置容器被强制终止之前的时间间隔

Azure Service Fabric 集群在 Windows 7 单机上运行 Windows 容器

使用默认 ASP.NET Core DI 容器在 Service Fabric 上设置依赖注入