c# - 从Visual Studio到Linux部署C#状态服务结构应用程序

标签 c# linux azure azure-service-fabric service-fabric-stateful

编辑04/06/18 =>更新问题,最后状态为

因此,我拥有目前正在运行在Azure上的Windows Service Fabric群集上运行的.Net 4.6状态服务。

从09/2017开始,我应该可以迁移到Linux:https://blogs.msdn.microsoft.com/azureservicefabric/2017/09/25/service-fabric-6-0-release/

因此,我正在尝试将其部署在Linux上,以便节省成本。

  • 首先,我已经将所有代码从.Net 4.6迁移到.Net Core 2.0。现在,我可以毫无问题地编译我的二进制文件了。我基本上已经创建了新的.Net Core项目,然后将我的所有源代码从.Net 4.6项目移到了新的.Net Core项目中。
  • 然后,我更新了Service Fabric应用程序。我从sfproj中删除了以前的SF服务,然后添加了新的.Net Core服务。

  • enter image description here

    看起来好像有一个警告(尽管在输出窗口上什么也没有),但是无论如何,如果我尝试通过Service Fabric Tools 2.0(测试版)提供的模板使用.Net core 2.0创建一个新的空Statful服务,那么它就在这里:

    enter image description here

    所以我要忍受它。
  • 在我的开发机上,我已经修改了两个包含状态服务的csproj项目,因此它们可以作为Windows可执行文件在本地运行。我使用了 win7-x64 runtimeIdentifier

  • 在我的Windows计算机上本地运行我的SF群集很好。
  • 然后,我对Linux的先前的csproj文件进行了一些更改。我使用了 ubuntu.16.10-x64 runtimeIdentifier

  • 另外,我还更改了ServiceManifest.xml文件,以针对与Linux兼容的二进制文件作为目标:
      <!-- Code package is your service executable. -->
      <CodePackage Name="Code" Version="1.9.6">
        <EntryPoint>
          <ExeHost>
            <Program>entryPoint.sh</Program>
          </ExeHost>
        </EntryPoint>
      </CodePackage>
    
    entryPoint.sh是最终执行的基本脚本:
    dotnet $DIR/MyService.dll
    
  • 然后,我已经从Visual Studio成功部署到了我的安全SF Linux群集。不幸的是,我的两个有状态服务都出现以下错误:

  • enter image description here

    Error event: SourceId='System.Hosting', Property='CodePackageActivation:Code:EntryPoint'. There was an error during CodePackage activation.The service host terminated with exit code:134



    看起来我的二进制文件在启动时崩溃了。所以这是我的问题:
  • 从Visual Studio在Linux上部署C#.Net Core SF状态服务的方法正确吗?

  • 编辑:在LinuxsyslogVer2v0表中查看,我得到以下错误:

    starthost.sh[100041]: Unhandled Exception: System.IO.FileLoadException: Could not load file or assembly 'System.Threading.Thread, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)



    我发现以下错误报告:https://github.com/dotnet/sdk/issues/1502
    不幸的是,如果不使用MSBuild(使用dotnet deploy),我仍然会收到错误消息。

    编辑:进一步说明:
  • 我的老板希望我在Linux上运行,因为从D1v2机器开始,它的价格是Windows机器的一半(无许可证等)。
  • 我的.NET Core 2.0服务已在Windows上成功运行。因此,.NET Core端口应该可以。
  • 最佳答案

    因此,要使其正常工作,实在是一件痛苦的事情。但这行得通。好吧,有点。

    首先,可靠服务仍在Linux上进行预览: https://github.com/Microsoft/service-fabric/issues/71

    全面的Linux支持应该很快就会出现(实际上,根据前面的链接它应该已经可用...)。

    现在,有关如何进行操作的详细信息,这里是一些可以帮助他人的信息,因为Microsoft文档上对此一无所知,而我实际上却花了3天的时间才能使它正常工作。

    1.请为您的项目使用.NET Core 2.0。

    在Linux上受支持。目前处于预览状态,但可以使用。

    2.请为您的项目使用正确的RID。

    截至今天(2018年4月),使用的正确RID是ubuntu.16.04-x64
    编辑您的Reliable Service项目的csproj文件,并按如下所示设置RID:

    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>netcoreapp2.0</TargetFramework>
        <IsServiceFabricServiceProject>True</IsServiceFabricServiceProject>
        <RuntimeIdentifier>ubuntu.16.04-x64</RuntimeIdentifier>
        <Platforms>AnyCPU;x64</Platforms>
      </PropertyGroup>
    

    有趣的部分是,您应该能够使用RuntimeIdentifiers参数(最后是 S )来提供多个RID,如下所示:
      <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>netcoreapp2.0</TargetFramework>
        <IsServiceFabricServiceProject>True</IsServiceFabricServiceProject>
        <RuntimeIdentifiers>win7x64;ubuntu.16.04-x64</RuntimeIdentifiers>
        <Platforms>AnyCPU;x64</Platforms>
      </PropertyGroup>
    

    因此,您可以同时构建Windows二进制文件和Linux二进制文件。
    但是根本不起作用。从Visual Studio构建项目时,仅以以下目录结尾:
    bin/Debug/netcoreapp2.0/
    

    仅DLL,没有有效的入口点。没有win7-x64文件夹,没有ubuntu.16.04-x64,什么也没有。
    这是一个应该修复的错误,但不是(我今天使用的都是最新的Visual Studio 15.6.2)。参见https://github.com/dotnet/core/issues/1039

    3.您需要一个有效的服务入口点。

    在Windows上,它是一个可执行文件(* .exe)。在Linux上不是。我最终得到了Linux C#示例,并复制/粘贴了入口点。 https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-create-your-first-linux-application-with-csharp

    因此,基本上我现在在每个可靠服务的ServiceManifest.xml文件中都有以下EntryPoint:
    <?xml version="1.0" encoding="utf-8"?>
    <ServiceManifest Name="XXXX"
                     Version="1.0.0"
                     xmlns="http://schemas.microsoft.com/2011/01/fabric"
                     xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <ServiceTypes>
        <!-- This is the name of your ServiceType.
             This name must match the string used in RegisterServiceType call in Program.cs. -->
        <StatefulServiceType ServiceTypeName="YYY" HasPersistedState="true" />
      </ServiceTypes>
    
      <!-- Code package is your service executable. -->
      <CodePackage Name="Code" Version="1.0.0">
        <EntryPoint>
          <ExeHost>
            <Program>entryPoint.sh</Program>
          </ExeHost>
        </EntryPoint>
      </CodePackage>
    
    entryPoint.sh如下:
    #!/usr/bin/env bash
    check_errs()
    {
      # Function. Parameter 1 is the return code
      if [ "${1}" -ne "0" ]; then
        # make our script exit with the right error code.
        exit ${1}
      fi
    }
    
    DIR=`dirname $0`
    echo 0x3f > /proc/self/coredump_filter
    source $DIR/dotnet-include.sh
    dotnet $DIR/NAME_OF_YOUR_SERVICE_DLL.dll $@
    check_errs $?
    
    dotnet-include.sh如下:
    #!/bin/bash
    . /etc/os-release
    linuxDistrib=$ID
    if [ $linuxDistrib = "rhel" ]; then
      source scl_source enable rh-dotnet20
      exitCode=$?
      if [ $exitCode != 0 ]; then
        echo "Failed: source scl_source enable rh-dotnet20 : ExitCode: $exitCode"
        exit $exitCode
      fi
    fi
    

    两者都在PackageRoot文件夹中。我为它们的属性都指定了属性,因此Build Action是“Content”,而Copy to Output Directory是“Copy always”。

    enter image description here

    4.不要使用MSBuild进行构建!

    是的,它也应该构建Linux软件包,或者至少看起来如此,因为当您右键单击项目并单击“构建”时,MSBuild能够生成以下文件:

    enter image description here

    不要相信该操作会取得明显的成功,否则部署后将无法正确执行。一些*.so文件丢失和其他问题。 MSBuild就像是 hell 般的 buggy ,并且对依赖项行为不端。

    例如,查看此错误报告:https://github.com/dotnet/sdk/issues/1502
    差不多一年后仍未解决...

    https://github.com/dotnet/core/issues/977(也可以获取此代码)。

    5.一定要编写一些PowerShell脚本来自己构建内容。

    我最终使用以下脚本重新构建了轮子,以构建我的程序包:
    # Creating binaries for service 1
    cd DIRECTORY_OF_MY_SERVICE_1
    dotnet publish -c Release -r ubuntu.16.04-x64
    
    # Creating binaries for service 2
    cd ..\DIRECTORY_OF_MY_SERVICE_2
    dotnet publish -c Release -r ubuntu.16.04-x64
    
    # Creating binaries for service 3
    cd ..\DIRECTORY_OF_MY_SERVICE_3
    dotnet publish -c Release -r ubuntu.16.04-x64
    
    # Copying ApplicationManifest.xml
    cd ..
    mkdir PKG\ServiceFabricApplication
    echo F|xcopy "ServiceFabricApplication\ApplicationPackageRoot\ApplicationManifest.xml" "PKG\ServiceFabricApplication\ApplicationManifest.xml" /sy
    
    # Copying Service1 files
    mkdir "PKG\ServiceFabricApplication\Service1Pkg"
    mkdir "PKG\ServiceFabricApplication\Service1Pkg\Code"
    xcopy "Service1\PackageRoot\*" "PKG\ServiceFabricApplication\Service1Pkg" /sy /D
    xcopy "Service1\bin\Release\netcoreapp2.0\ubuntu.16.04-x64\publish\*" "PKG\ServiceFabricApplication\Service1Pkg\Code" /sy
    
    # Copying Service2 files
    mkdir "PKG\ServiceFabricApplication\Service2Pkg"
    mkdir "PKG\ServiceFabricApplication\Service2Pkg\Code"
    xcopy "Service2\PackageRoot\*" "PKG\ServiceFabricApplication\Service2Pkg" /sy /D
    xcopy "Service2\bin\Release\netcoreapp2.0\ubuntu.16.04-x64\publish\*" "PKG\ServiceFabricApplication\Service2Pkg\Code" /sy
    
    # Copying Service3 files
    mkdir "PKG\ServiceFabricApplication\Service3Pkg"
    mkdir "PKG\ServiceFabricApplication\Service3Pkg\Code"
    xcopy "Service3\PackageRoot\*" "PKG\ServiceFabricApplication\Service3Pkg" /sy /D
    xcopy "Service3\bin\Release\netcoreapp2.0\ubuntu.16.04-x64\publish\*" "PKG\ServiceFabricApplication\Service3Pkg\Code" /sy
    
    # Compresses the package
    Write-host "Compressing package..."
    Copy-ServiceFabricApplicationPackage -ApplicationPackagePath .\PKG\ServiceFabricApplication -CompressPackage -SkipCopy
    
    sfproj文件是一个与Visual Studio/MSBuild相关的项目,因此您需要自己构建所有内容。
    当使用Visual Studio构建pkg时,上面的脚本产生的内容与MSBuild创建的sfproj文件夹相同。它将所有内容复制到解决方案根目录的PKG文件夹中。

    软件包结构在这里详细说明:https://github.com/MicrosoftDocs/azure-docs/blob/master/articles/service-fabric/service-fabric-package-apps.md

    6.现在该进行部署了!

    在这一点上,我不再信任Visual Studio,所以我建立了自己的PowerShell脚本:
    . .\ServiceFabricApplication\Scripts\Deploy-FabricApplication.ps1 -ApplicationPackagePath '.\PKG\ServiceFabricApplication' -PublishProfileFile '.\ServiceFabricApplication\PublishProfiles\Cloud.xml' -DeployOnly:$false -ApplicationParameter:@{} -UnregisterUnusedApplicationVersionsAfterUpgrade $false -OverrideUpgradeBehavior 'None' -OverwriteBehavior 'SameAppTypeAndVersion' -SkipPackageValidation:$false -ErrorAction Stop
    

    它重用了Deploy-FabricApplication.ps1项目内Service Fabric项目模板提供的sfproj脚本。该脚本解析Cloud.xml PublishProfile并部署到您的服务结构集群。

    因此,您可以同时在PublishProfiles/Cloud.xmlApplicationParameters/Cloud.xml上指定权限值,然后执行脚本。

    当然,仅当您具有用于保护计算机上安装的群集的证书时,此方法才有效。
    请注意第一个点“。”之所以重要,是因为如果您不使用它,则会出现以下错误:

    Get-ServiceFabricClusterManifest : Cluster connection instance is null



    参见https://stackoverflow.com/a/38104087/870604

    哦,而且由于Service Fabric SDK上也有错误,因此您可能也想关闭本地SF群集...
    https://github.com/Azure/service-fabric-issues/issues/821

    7.现在是另一个欺骗的时候了。

    它根本不起作用,服务在启动时崩溃。在LinuxsyslogVer2v0 Azure存储表(Linux的日志表,位于由SF群集自动创建的两个Azure存储帐户之一)中搜索了几个小时后,我发现Microsoft自己的Nuget软件包也有问题。

    具体来说,Nuget软件包Microsoft.Azure.Devices在1.6.0版上不起作用。找不到与dll的引用有关的问题或其他问题。我回滚到以前的版本,即1.5.1,并已修复。

    在这一点上,我再也没有能力为此提出另一个Github问题了。抱歉,MS,我不是您的质量检查小组,我已经累了。

    8.使用第一个PowerShell脚本再次构建,使用第二个PowerShell脚本进行部署,完成。

    您终于在Windows上使用Visual Studio中的.NET Core 2.0(有点像是 bug ,我使用PowerShell)将C#Reliable Services部署到了Linux SF群集上。

    现在我的ASP.NET Core服务仍然有问题,但这将是另一回事。

    结论:TL; DR

    整个事情都是一团糟。到处都是 bug 。在SDK中,在工具中,在某些Microsoft Nuget程序包中。糟糕的经验。但是它受支持(目前处于预览状态),您可以使其正常运行。希望这篇文章对您有帮助...

    关于c# - 从Visual Studio到Linux部署C#状态服务结构应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48170445/

    相关文章:

    使用azure移动服务脚本时出现javascript错误

    c# - 在 C# 中从线程更新 UI 的其他方法

    c# - 如何将已解析的实例从控制反转传递给应用程序中的类?

    c# - bool 转换问题的枚举

    linux - 进程 Linux 的可能名称?

    mysql - 为什么我的 Slave 没有在 MYSQL 上启动?

    C# 嵌入式 FTP 服务器

    php - 杀死用popen()打开的进程?

    Azure 私有(private) DNS 区域链接到 VNet

    azure - 诊断 Service Fabric 应用程序失败的原因