简体   繁体   English

将Visual Studio中的C#Stateful Service Fabric应用程序部署到Linux

[英]Deploy a C# Stateful Service Fabric application from Visual Studio to Linux

EDIT 04/06/18 => Updated question with last status 编辑04/06/18 =>更新了上次状态的问题


So I have this working .Net 4.6 Stateful Service that currently run on my Windows Service Fabric cluster deployed on Azure. 所以我有这个工作.Net 4.6状态服务,目前在我部署在Azure上的Windows Service Fabric集群上运行。

Starting from 09/2017, I should be able to move to Linux: https://blogs.msdn.microsoft.com/azureservicefabric/2017/09/25/service-fabric-6-0-release/ 从2017年9月开始,我应该可以转到Linux: https ://blogs.msdn.microsoft.com/azureservicefabric/2017/09/25/service-fabric-6-0-release/

So I'm trying to deploy it on Linux so I can save costs. 所以我试图在Linux上部署它,这样我就可以节省成本。

  1. First things first, I've migrated all my code from .Net 4.6 to .Net Core 2.0. 首先,我将所有代码从.Net 4.6迁移到.Net Core 2.0。 Now I can compile my binaries without issues. 现在我可以毫无问题地编译我的二进制文件。 I've basically created new .Net Core projects and then moved all my source code from .Net 4.6 projects to the new .Net Core ones. 我基本上创建了新的.Net Core项目,然后将我的所有源代码从.Net 4.6项目移动到新的.Net Core项目。

  2. Then I've updated my Service Fabric application. 然后我更新了我的Service Fabric应用程序。 I removed my previous SF services from my sfproj, then I've added my new .Net Core ones. 我从我的sfproj中删除了以前的SF服务,然后我添加了新的.Net Core服务。

在此输入图像描述

Looks like there is a warning (nothing on the output window though), but it's here anyway if I try to create a new empty Statful service using .Net core 2.0 through the template provided by Service Fabric Tools 2.0 (beta): 看起来有一个警告(虽然输出窗口上没有任何内容),但无论如何,如果我尝试通过Service Fabric Tools 2.0(beta)提供的模板使用.Net core 2.0创建一个新的空Statful服务,它就在这里:

在此输入图像描述

So I'm going to live with it. 所以我会忍受它。

  1. On my dev machine, I've modified the 2 csproj projects that contain my Stateful services so they can run locally as Windows executables. 在我的开发机器上,我修改了包含我的有状态服务的2个csproj项目,以便它们可以作为Windows可执行文件在本地运行。 I've used the win7-x64 runtimeIdentifier . 我使用了win7-x64 runtimeIdentifier

Running my SF cluster locally on my Windows machine is fine. 在我的Windows机器上本地运行我的SF群集很好。

  1. Then I've slightly changed the previous csproj files for Linux. 然后我稍微改变了以前用于Linux的csproj文件。 I used the ubuntu.16.10-x64 runtimeIdentifier . 我使用了ubuntu.16.10-x64 runtimeIdentifier

Also I've changed the ServiceManifest.xml file to target the linux-compatible binary: 我还更改了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 is a basic script that eventually executes: entryPoint.sh是最终执行的基本脚本:

dotnet $DIR/MyService.dll
  1. Then I've successfully deployed to my secured SF Linux cluster from Visual Studio. 然后我从Visual Studio成功部署到我的安全SF Linux集群。 Unfortunately I have the following errors for both my stateful services: 不幸的是,我的状态服务有以下错误:

在此输入图像描述

Error event: SourceId='System.Hosting', Property='CodePackageActivation:Code:EntryPoint'. 错误事件:SourceId ='System.Hosting',Property ='CodePackageActivation:Code:EntryPoint'。 There was an error during CodePackage activation.The service host terminated with exit code:134 CodePackage激活期间出错。服务主机以退出代码终止:134

Looks like my binary crashes when starting. 看起来我的二进制文件在启动时崩溃了。 So here are my questions: 所以这是我的问题:

  • Is the approach right to deploy a C# .Net Core SF stateful service on Linux from Visual Studio? 从Visual Studio在Linux上部署C#.Net Core SF有状态服务的方法是否正确?

EDIT : looking inside the LinuxsyslogVer2v0 table, I get the following error: 编辑 :查看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'. starthost.sh [100041]:未处理的异常:System.IO.FileLoadException:无法加载文件或程序集'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) (HRESULT异常:0x80131040)

I found the following bug report: https://github.com/dotnet/sdk/issues/1502 Unfortunately, I still get the error without using MSBuild (using dotnet deploy ). 我发现了以下错误报告: https//github.com/dotnet/sdk/issues/1502不幸的是,我仍然在不使用MSBuild(使用dotnet deploy )的情况下得到错误。

EDIT : further clarification: 编辑 :进一步澄清:

  • My boss want me to run on Linux because starting from D1v2 machines, it's half the price compared to Windows machines (no license etc.) 我的老板要我在Linux上运行,因为从D1v2机器开始,它的价格是Windows机器的一半(没有许可证等)
  • My .NET Core 2.0 services successfully run on Windows. 我的.NET Core 2.0服务在Windows上成功运行。 So the .NET Core port should be fine. 所以.NET Core端口应该没问题。

So, this was a real pain in the ass to get it working properly. 所以,为了让它正常工作,这是一个真正的痛苦。 But it works. 但它的确有效。 Well, kind of. 好吧,有点儿。


First, Reliable Services are still in preview on Linux: https://github.com/Microsoft/service-fabric/issues/71 首先,Reliable Services仍然在Linux上进行预览: https //github.com/Microsoft/service-fabric/issues/71

Full Linux support should come very soon (actually it should be available already according to the previous link...). 完整的Linux支持应该很快就会到来(实际上它应该已经根据之前的链接提供了......)。

Now for the details about how to procede, here is some information to help others, because there is just nothing about that on Microsoft documentation and I literally lost 3 days trying to make it work. 现在有关如何处理的详细信息,这里有一些信息可以帮助其他人,因为在Microsoft文档上没有任何关于它的信息,而且我确实在3天内试图让它工作。

1. Do use .NET Core 2.0 for your projects. 1.为您的项目使用.NET Core 2.0。

It is supported on Linux. 它在Linux上受支持。 On preview for now, but it works. 现在预览,但它的工作原理。

2. Do use the right RID for your projects. 2.为项目使用正确的RID。

As of today (April 2018), the right RID to use is ubuntu.16.04-x64 . 截至今天(2018年4月),使用的正确RID是ubuntu.16.04-x64 Edit the csproj files of your Reliable Service projects and set the RID like this: 编辑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>

The fun part is, you should be able to provide multiple RIDs using the RuntimeIdentifiers parameter (with a S at the end) like that: 有趣的是,您应该能够使用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>

So you could build Windows binaries and Linux binaries at the same time. 因此,您可以同时构建Windows二进制文件和Linux二进制文件。 But it simply doesn't work . 它根本行不通 When building the project from Visual Studio, I end up with the following directory only: 从Visual Studio构建项目时,我最终只得到以下目录:

bin/Debug/netcoreapp2.0/

Only DLLs, no valid entry point. 只有DLL,没有有效的入口点。 No win7-x64 folder, no ubuntu.16.04-x64 , no nothing. 没有win7-x64文件夹,没有ubuntu.16.04-x64 ,没有什么。 This is a bug, supposed to be fixed, but it's not (I use Visual Studio 15.6.2 all up-to-date as of today). 这是一个错误,应该是修复的,但事实并非如此(我使用的Visual Studio 15.6.2至今都是最新版本)。 See https://github.com/dotnet/core/issues/1039 请参阅https://github.com/dotnet/core/issues/1039

3. You need a valid Entry Point for your service. 3.您的服务需要有效的入口点。

On Windows it's an executable file (*.exe). 在Windows上,它是一个可执行文件(* .exe)。 On Linux it's not. 在Linux上它不是。 I ended up getting the Linux C# example and copied/pasted the entry point. 我最终获得了Linux C#示例并复制/粘贴了入口点。 https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-create-your-first-linux-application-with-csharp https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-create-your-first-linux-application-with-csharp

So basically I now have on my ServiceManifest.xml file of each Reliable Service the following EntryPoint : 所以基本上我现在在每个Reliable Service的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 is as follows: 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 is as follows: 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

Both are inside the PackageRoot folder. 两者都在PackageRoot文件夹中。 I specified for both their properties so the Build Action is " Content " and the Copy to Output Directory is " Copy always ". 我指定了它们的属性,因此Build Action是“ Content ”, Copy to Output Directory是“ Copy always ”。

在此输入图像描述

4. Do NOT build using MSBuild !! 4.不要使用MSBuild构建!!

Yeah it is supposed to build Linux packages too, or at least it seems so, because MSBuild is able to produce the following files when you right click on your project and click "Build": 是的,它也应该构建Linux软件包,或者至少看起来如此,因为当您右键单击项目并单击“构建”时,MSBuild能够生成以下文件:

在此输入图像描述

Don't trust the apparent success of the operation, it will miserably FAIL to properly execute when deployed. 不要相信操作的明显成功,在部署时将很难正确执行。 Some *.so files missing and other issues. 一些*.so文件丢失和其他问题。 MSBuild is buggy as hell and misbehaves regarding dependencies. MSBuild是关于依赖关系的地狱和行为不端的错误。

See for instance this bug report: https://github.com/dotnet/sdk/issues/1502 Still not fixed after almost a year... 例如,请参阅此错误报告: https//github.com/dotnet/sdk/issues/1502近一年后仍未修复...

Or https://github.com/dotnet/core/issues/977 (got this one, too). 或者https://github.com/dotnet/core/issues/977 (也有这个)。

5. Do write some PowerShell script to build the stuff by yourself. 5.编写一些PowerShell脚本来自己构建这些东西。

I ended up reinventing the wheel using the following script to build my package: 我最后使用以下脚本重新发明轮子来构建我的包:

# 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 file is a Visual Studio / MSBuild related project, so you need to build everything by yourself. sfproj文件是一个与Visual Studio / MSBuild相关的项目,因此您需要自己构建所有内容。 The script above produces the same content as the pkg folder created by MSBuild when building your sfproj using Visual Studio. 上面的脚本生成的内容与MSBuild在使用Visual Studio构建sfproj时创建的pkg文件夹相同。 It copies everything on a PKG folder at the root of your solution. 它将所有内容复制到解决方案根目录下的PKG文件夹中。

The package structure is detailed here: https://github.com/MicrosoftDocs/azure-docs/blob/master/articles/service-fabric/service-fabric-package-apps.md 包结构详见: https//github.com/MicrosoftDocs/azure-docs/blob/master/articles/service-fabric/service-fabric-package-apps.md

6. Now it's time to deploy! 6.现在是时候部署了!

At this point I didn't trusted Visual Studio anymore, so I built my own PowerShell script: 此时我不再信任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

It reuses the Deploy-FabricApplication.ps1 script provided by the Service Fabric project template inside the sfproj project. 它重用sfproj项目中Service Fabric项目模板提供的Deploy-FabricApplication.ps1脚本。 This script parses the Cloud.xml PublishProfile and deploys to your service fabric cluster. 此脚本解析Cloud.xml PublishProfile并部署到服务结构集群。

So you specifies the rights values on both PublishProfiles/Cloud.xml and ApplicationParameters/Cloud.xml then execute the script. 因此,您在PublishProfiles/Cloud.xmlApplicationParameters/Cloud.xml上指定权限值,然后执行该脚本。

It only works if you have the certificate used to secure the cluster installed on your machine, of course. 只有当您拥有用于保护计算机上安装的群集的证书时,它才有效。 Do note the first dot '.' 请注意第一个点'。' is important, because if you don't use it, you'll have the following error: 很重要,因为如果你不使用它,你将有以下错误:

Get-ServiceFabricClusterManifest : Cluster connection instance is null Get-ServiceFabricClusterManifest:群集连接实例为空

See https://stackoverflow.com/a/38104087/870604 请参阅https://stackoverflow.com/a/38104087/870604

Oh, and as there are bugs on the Service Fabric SDK too, you might want to shutdown your local SF cluster too... https://github.com/Azure/service-fabric-issues/issues/821 哦,因为Service Fabric SDK上也有bug,你可能也想关闭你的本地SF集群... https://github.com/Azure/service-fabric-issues/issues/821

7. Now it's time for another deception. 7.现在是另一次欺骗的时候了。

It simply doesn't work, the service crashes on startup. 它根本不起作用,服务在启动时崩溃。 After searching hours inside the LinuxsyslogVer2v0 Azure Storage table (the log table for Linux, located in one of the two Azure Storage Accounts created automatically with the SF cluster), I found that Microsoft own Nuget Packages were buggy too. LinuxsyslogVer2v0 Azure存储表(Linux的日志表,位于使用SF集群自动创建的两个Azure存储帐户之一)中搜索数小时后,我发现微软自己的Nuget软件包也有错误。

Specifically, the Nuget package Microsoft.Azure.Devices doesn't work on version 1.6.0. 具体来说,Nuget包Microsoft.Azure.Devices在1.6.0版本上不起作用。 An issue with a reference of a dll not found or whatever. 引用未找到的DLL或其他问题。 I rollbacked to a previous version, namely 1.5.1, and it was fixed. 我回滚到以前的版本,即1.5.1,它已修复。

At this point I didn't had anymore energy to create another Github issue about that. 在这一点上,我没有更多的精力来创建另一个Github问题。 Sorry MS, I'm not your QA team, I'm getting tired. 对不起MS,我不是你的QA团队,我累了。

8. Build again using the first PowerShell script, deploy using the second PowerShell script, and you're done. 8.使用第一个PowerShell脚本再次构建,使用第二个PowerShell脚本进行部署,然后就完成了。

You've finally deployed C# Reliable Services using .NET Core 2.0 from Visual Studio (kind of, as it's buggy and I used PowerShell) on Windows to a Linux SF Cluster. 您最终使用Visual Studio中的.NET Core 2.0(因为它有问题而我使用PowerShell)在Windows上部署了C#Reliable Services到Linux SF Cluster。

Now I still have issues with my ASP.NET Core service, but it will be a story for another day. 现在我的ASP.NET核心服务仍然存在问题,但它将成为另一天的故事。


Conclusion: TL;DR 结论:TL; DR

The whole thing is a mess. 整件事情一团糟。 Bugs everywhere. 到处都是虫子。 In the SDK, in the tools, in some of Microsoft Nuget Packages. 在SDK中,在工具中,在一些Microsoft Nuget包中。 Awful experience. 糟糕的经历。 But it is supported (in preview for now) and you can make it work. 但它支持(现在预览),你可以使它工作。 Hope this post will help... 希望这篇文章能有所帮助......

I was having similar issues, but I believe this is the issue: 我有类似的问题,但我相信这是问题所在:

In this release, .NET Core 2.0 services are only supported on Service Fabric for Windows. 在此版本中,仅在Service Fabric for Windows上支持.NET Core 2.0服务。 Full cross-platform support for .NET Core 2.0 services on Windows and Linux is coming soon. Windows和Linux上对.NET Core 2.0服务的完全跨平台支持即将推出。

From the Service Fabric 6.1 Release Notes So no Linux as long as you are targeting .net core 2.0. Service Fabric 6.1发行说明 ,只要您的目标是.net core 2.0,就没有Linux。

I have success deploy to Linux service fabric with this help 通过此帮助,我已成功部署到Linux服务结构

Open all the service .csproj files and update the RuntimeIdentifier as shown below 打开所有服务.csproj文件并更新RuntimeIdentifier,如下所示

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
<IsServiceFabricServiceProject>True</IsServiceFabricServiceProject>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
</PropertyGroup>

Update the ServiceManifest.xml to remove .exe extension as shown below 更新ServiceManifest.xml以删除.exe扩展名,如下所示

<CodePackage Name="Code" Version="1.0.0">
<EntryPoint>
<ExeHost>
<Program>Web1</Program>
</ExeHost>
</EntryPoint>
</CodePackage>

See https://blogs.msdn.microsoft.com/premier_developer/2018/05/27/running-net-core-2-0-applications-in-a-linux-service-fabric-cluster-on-azure/ 请参阅https://blogs.msdn.microsoft.com/premier_developer/2018/05/27/running-net-core-2-0-applications-in-a-linux-service-fabric-cluster-on-azure/

*Visual Studio 15.7.3 * Visual Studio 15.7.3

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Visual Studio 2015 C#将应用程序部署到桌面 - Visual Studio 2015 C# Deploy Application to Desktop Azure Service Fabric:使用无状态服务将数据存储到有状态服务(C#编程) - Azure Service Fabric : Use stateless service to store data into stateful service (c# programming) 在 Visual Studio 中为 5 节点群集调试 Azure Service Fabric 应用程序 - Debugging Azure Service Fabric Application in Visual Studio for 5 node cluster 无法部署Visual C#应用程序 - Cannot deploy Visual C# application Visual Studio应用程序部署 - visual studio application deploy 在Linux中使用Visual Studio C#程序 - Using Visual Studio C# program in Linux 使用 Visual Studio Code 在 Linux 上编写 C# - Writing C# on Linux with Visual Studio Code 如何使用ClickOnce部署我的C#(4.0)Visual Studio 2010基于Windows窗体的应用程序? - How to use ClickOnce to deploy my C#(4.0)Visual studio 2010 windows form based Application? 如何在Visual Studio 2010中使用SQL Server 2012数据库打包和部署C#桌面应用程序? - How to package and deploy a C# desktop application with a SQL Server 2012 database in Visual Studio 2010? 部署在Visual Studio 2010 Express Edition中制作的C#应用​​程序 - Deploy my C# application made in Visual Studio 2010 Express Edition
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM