國產中標麒麟Linux部署dotnet core 環境並運行項目 (二) 部署運行控制檯項目

背景
在上一篇文章安裝dotnet core,已經安裝好dotnet core了。之前只是安裝成功了dotnet, 輸入dotnet --info,可以確認安裝成功了,但是在運行代碼時,還是報錯了,本章記錄在部署好dotnet core後,到能運行控制檯程序當中的錯誤。

首先將項目用vs發佈一下,然後把文件放到中標麒麟的系統上,在文件夾打開終端,執行 dotnet **.dll,結果如下:

[root@gumis02 PublishOutput]# dotnet Beyondbit.ConsoleFrameworkNetStandard.IntegrationTests.dll
Failed to load \ufffd=l, error: libunwind.so.8: cannot open shared object file: No such file or directory
Failed to bind to CoreCLR at '/home/dotnet/shared/Microsoft.NETCore.App/2.0.7/libcoreclr.so'

[root@gumis02 PublishOutput]#

錯誤 error : libunwind.so.8: cannot open shared object file: No such file or directory

修復此問題的解決方案是安裝 libunwind

手動源碼安裝 libunwind

libunwind的源代碼現在已經託管到github上了,libunwind github 地址
我安裝的是最新版1.2.1, 輸入下面命令安裝:

wget https://github.com/libunwind/libunwind/releases/download/v1.2.1/libunwind-1.2.1.tar.gz
tar -xf libunwind-1.2.1.tar.gz
cd libunwind-1.2.1
CFLAGS=-fPIC ./configure  #添加編譯參數 
make CFLAGS=-fPIC 
make CFLAGS=-fPIC install 

安裝成功後,再執行dotnet **.dll,會發現依然報錯ibunwind.so.8: cannot open shared object file: No such file or directory
在輸入以下命令修復:

[root@gumis02 dotnet]# find / -name libunwind.so.8
/home/.Trash-0/files/libunwind-1.2.1/src/.libs/libunwind.so.8
/home/NetCoreSdk/libunwind-1.2.1/src/.libs/libunwind.so.8
/usr/local/lib/libunwind.so.8
[root@gumis02 dotnet]# ln -s /usr/local/lib/libunwind.so.8 /lib64/
[root@gumis02 dotnet]# ln -s /usr/local/lib/libunwind.so.8 /lib

[root@gumis02 dotnet]# find / -name libunwind-x86_64.so.8
/home/.Trash-0/files/libunwind-1.2.1/src/.libs/libunwind-x86_64.so.8
/home/NetCoreSdk/libunwind-1.2.1/src/.libs/libunwind-x86_64.so.8
/usr/local/lib/libunwind-x86_64.so.8

[root@gumis02 dotnet]# ln -s /usr/local/lib/libunwind-x86_64.so.8 /lib64/
[root@gumis02 dotnet]# ln -s /usr/local/lib/libunwind-x86_64.so.8 /lib

輸入後,再執行dotnet **.dll,發現上面的問題已經消失。但是出現新的錯誤提示:

FailFast: Couldn't find a valid ICU package installed on the system. Set the configuration flag System.Globalization.Invariant to true if you want to run with no globalization support.

   at System.Environment.FailFast(System.String)
   at System.Globalization.GlobalizationMode.GetGlobalizationInvariantMode()
   at System.Globalization.GlobalizationMode..cctor()
   at System.Globalization.CultureData.CreateCultureWithInvariantData()
   at System.Globalization.CultureData.get_Invariant()
   at System.Globalization.CultureData.GetCultureData(System.String, Boolean)
   at System.Globalization.CultureInfo.InitializeFromName(System.String, Boolean)
   at System.Globalization.CultureInfo.Init()
   at System.Globalization.CultureInfo..cctor()
   at System.StringComparer..cctor()
   at System.AppDomainSetup.SetCompatibilitySwitches(System.Collections.Generic.IEnumerable`1<System.String>)
   at System.AppDomain.PrepareDataForSetup(System.String, System.AppDomainSetup, System.Security.Policy.Evidence, System.Security.Policy.Evidence, IntPtr, System.String, System.String[], System.String[])
\u5df2\u653e\u5f03 (core dumped)
[root@gumis02 PublishOutput]# 

下一步,準備修復這個錯誤.

錯誤 Couldn't find a valid ICU package installed on the system. Set the configuration flag System.Globalization.Invariant to true if you want to run with no globalization support.

查找資料顯示,這是NET Core 全球化的模式,可見微軟的文章 NET Core Globalization Invariant Mode

摘取一段原文說明背景

Globalization rules and the data that represents those rules frequently change, often due to country-specific policy changes (for example, changes in currency symbol, sorting behavior or time zones). Developers expect globalization behavior to always be current and for their applications to adapt to new data over time. In order to keep up with those changes, .NET Core (and the .NET Framework, too) depends on the underlying OS to keep up with these changes.

Relying on the underlying OS for globalization data has the following benefits:

  • .NET apps have the same globalization behavior on a given OS as native apps (assuming they also rely on the OS).
  • .NET apps do not have to carry this data.
  • The .NET team doesn't have to maintain this data themselves (it's very expensive to do this!).

Globalization support has the following potential challenges for applications:

  • Different behavior across OSes (and potentially OS versions).
  • Installing/carrying the ICU package on Linux (~28 MB).

Note: On Linux, .NET Core relies on globalization data from ICU. For example, .NET Core Linux Docker images install this component. Globalization data is available on Windows and macOS as part of their base installs.

上文提到依賴 ICU Package,可點擊鏈接去查看。

有兩種解決方案:

  1. 在runtimeconfig.json中添加以下配置即可,不想糾結原理的就使用這種方式即可:
    "configProperties": {
      "System.Globalization.Invariant": true
    }

完整的在runtimeconfig.json 如下:

{
  "runtimeOptions": {
    "tfm": "netcoreapp2.0",
    "framework": {
      "name": "Microsoft.NETCore.App",
      "version": "2.0.0"
    },
   "configProperties": {
      "System.Globalization.Invariant": true
    }
  }
}

注意
這種方式,證明了是可以解決問題的,但是他開啓了Globalization.Invariant Mode 模式,在簡單的應用下,程序可以正常運行,但是在遇到複雜的應用很有可能會遇到一個異常,System.ArgumentNullException: SafeHandle cannot be null,見我正式項目的運行結果,這個異常在github上有很多人提到,如:

我的測試項目就是用了log4net導致的,目前net corefx團隊收到了反饋已經在着手解決了。要想終極解決此問題,需要用以下第二種方式來解決,安裝 ICU Package模塊。

  1. 安裝ICU Package

ICU Package

我們使用源碼的方式安裝icu. 我選擇的是59.1版本,輸入以下命令:

wget http://download.icu-project.org/files/icu4c/59.1/icu4c-59_1-src.tgz 
tar -xzvf icu4c-59_1-src.tgz
cd icu/source
./configure --prefix=/usr/local/icu

make 
make install 

參看是否安裝成功:

[root@gumis02 ~]# icu-config --version
59.1
[root@gumis02 ~]# icuinfo
icuinfo: error while loading shared libraries: libicutu.so.59: cannot open shared object file: No such file or directory

看到安裝成功了,但是查看具體信息會提示缺少 libicutu.so.59,其他缺少的dll,同樣處理。
輸入以下命令查找,並映射so文件:

[root@gumis02 ~]# find / -name libicutu.so.59
/home/NetCoreSdk/icu/source/lib/libicutu.so.59
/home/NetCoreSdk/icu2/source/lib/libicutu.so.59
/usr/lib/libicutu.so.59
/usr/local/icu/lib/libicutu.so.59

[root@gumis02 ~]# ln -s /usr/local/icu/lib/libicutu.so.59 /lib64/
[root@gumis02 ~]# ln -s /usr/local/icu/lib/libicui18n.so.59 /lib64/
[root@gumis02 ~]# ln -s /usr/local/icu/lib/libicuuc.so.59 /lib64/
[root@gumis02 ~]# ln -s /usr/local/icu/lib/libicudata.so.59 /lib64/
[root@gumis02 ~]# ln -s /usr/local/icu/lib/libicudata.so.59 /lib64/ 
[root@gumis02 ~]# icuinfo
 <icuSystemParams type="icu4c">
    <param name="copyright"> Copyright (C) 2016 and later: Unicode, Inc. and others. License & terms of use: http://www.unicode.org/copyright.html </param>
    <param name="product">icu4c</param>
    <param name="product.full">International Components for Unicode for C/C++</param>
    <param name="version">59.1</param>
    <param name="version.unicode">9.0</param>
    <param name="platform.number">4000</param>
    <param name="platform.type">Linux</param>
    <param name="locale.default">zh_CN</param>
    <param name="locale.default.bcp47">zh-CN</param>
    <param name="converter.default">UTF-8</param>
    <param name="icudata.name">icudt59l</param>
    <param name="icudata.path"></param>
    <param name="cldr.version">31.0.1</param>
    <param name="tz.version">2017b</param>
    <param name="tz.default">PRC</param>
    <param name="cpu.bits">64</param>
    <param name="cpu.big_endian">0</param>
    <param name="os.wchar_width">4</param>
    <param name="os.charset_family">0</param>
    <param name="os.host">x86_64-unknown-linux-gnu</param>
    <param name="build.build">x86_64-unknown-linux-gnu</param>
    <param name="build.cc">gcc</param>
    <param name="build.cxx">g++</param>
    <param name="uconfig.internal_digitlist">1</param>
    <param name="uconfig.have_parseallinput">1</param>
    <param name="uconfig.format_fastpaths_49">1</param>
 </icuSystemParams>


ICU Initialization returned: U_ZERO_ERROR
Plugins are disabled.

參考:

install ICU-61.1
安裝完成後,再測試正式的項目,執行成功了,數據插入到數據庫了。

運行測試

HelloWorld 項目

採用配置了 runtimeconfig.json中添加以下配置

    "configProperties": {
      "System.Globalization.Invariant": true
    }

HelloWorld程序運行測試:

Microsoft .NET Core Shared Framework Host

  Version  : 2.0.7
  Build    : 2d61d0b043915bc948ebf98836fefe9ba942be11

[root@gumis02 ConsoleTest2]# dotnet ConsoleApp2.dll
FailFast: Couldn't find a valid ICU package installed on the system. Set the configuration flag System.Globalization.Invariant to true if you want to run with no globalization support.

   at System.Environment.FailFast(System.String)
   at System.Globalization.GlobalizationMode.GetGlobalizationInvariantMode()
   at System.Globalization.GlobalizationMode..cctor()
   at System.Globalization.CultureData.CreateCultureWithInvariantData()
   at System.Globalization.CultureData.get_Invariant()
   at System.Globalization.CultureData.GetCultureData(System.String, Boolean)
   at System.Globalization.CultureInfo.InitializeFromName(System.String, Boolean)
   at System.Globalization.CultureInfo.Init()
   at System.Globalization.CultureInfo..cctor()
   at System.StringComparer..cctor()
   at System.AppDomainSetup.SetCompatibilitySwitches(System.Collections.Generic.IEnumerable`1<System.String>)
   at System.AppDomain.PrepareDataForSetup(System.String, System.AppDomainSetup, System.Security.Policy.Evidence, System.Security.Policy.Evidence, IntPtr, System.String, System.String[], System.String[])
\u5df2\u653e\u5f03 (core dumped)
[root@gumis02 ConsoleTest2]# dotnet ConsoleApp2.dll
Hello World!
[root@gumis02 ConsoleTest2]# 

正式控制檯項目

在runtimeconfig.json中添加以下配置即可,不想糾結原理的就使用這種方式即可:

    "configProperties": {
      "System.Globalization.Invariant": true
    }

上面的這種方式,我使用helloworld程序是能正常運行的,但是在正式的項目中,用到了log4net,運行的話,會報其他的錯誤:

[root@gumis02 PublishOutput]# dotnet Beyondbit.ConsoleFrameworkNetStandard.IntegrationTests.dll

Unhandled Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentNullException: SafeHandle cannot be null.
Parameter name: pHandle
   at System.ThrowHelper.ThrowArgumentNullException(ExceptionArgument argument, ExceptionResource resource)
   at System.StubHelpers.StubHelpers.SafeHandleAddRef(SafeHandle pHandle, Boolean& success)
   at Interop.GlobalizationInterop.GetSortKey(SafeSortHandle sortHandle, String str, Int32 strLength, Byte* sortKey, Int32 sortKeyLength, CompareOptions options)
   at System.Globalization.CompareInfo.GetHashCodeOfStringCore(String source, CompareOptions options, Boolean forceRandomizedHashing, Int64 additionalEntropy)
   at System.Collections.Hashtable.GetHash(Object key)
   at System.Collections.Hashtable.InitHash(Object key, Int32 hashsize, UInt32& seed, UInt32& incr)
   at System.Collections.Hashtable.Insert(Object key, Object nvalue, Boolean add)
   at System.Collections.Hashtable.set_Item(Object key, Object value)
   at log4net.Core.LevelMap.Add(Level level)
   at log4net.Repository.LoggerRepositorySkeleton.AddBuiltinLevels()
   at log4net.Repository.LoggerRepositorySkeleton..ctor(PropertiesDictionary properties)
   at log4net.Repository.Hierarchy.Hierarchy..ctor(PropertiesDictionary properties, ILoggerFactory loggerFactory)
   --- End of inner exception stack trace ---
   at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor)
   at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
   at System.Activator.CreateInstance(Type type, Boolean nonPublic)
   at System.Activator.CreateInstance(Type type)
   at log4net.Core.DefaultRepositorySelector.CreateRepository(String repositoryName, Type repositoryType)
   at log4net.Core.DefaultRepositorySelector.CreateRepository(Assembly repositoryAssembly, Type repositoryType, String repositoryName, Boolean readAssemblyAttributes)
   at log4net.Core.LoggerManager.GetLogger(Assembly repositoryAssembly, String name)
   at log4net.LogManager.GetLogger(Type type)
   at Beyondbit.Framework.Core.Proxy.Proxy.SetSessionToContext(ISession session) in E:\\u5de5\u4f5c\u533a\03 \u4e92\u8054\u7f51\00 Beyondbit Infrastructure\\u5f00\u53d1\u6846\u67b6\3.0\Beyondbit.Framework\Core\Proxy\Proxy.cs:line 117
   at Beyondbit.Framework.Core.Proxy.Proxy.CreateClassProxy[T]() in E:\\u5de5\u4f5c\u533a\03 \u4e92\u8054\u7f51\00 Beyondbit Infrastructure\\u5f00\u53d1\u6846\u67b6\3.0\Beyondbit.Framework\Core\Proxy\Proxy.cs:line 82
   at Beyondbit.Framework.Core.Proxy.Proxy.CreateObject[T]() in E:\\u5de5\u4f5c\u533a\03 \u4e92\u8054\u7f51\00 Beyondbit Infrastructure\\u5f00\u53d1\u6846\u67b6\3.0\Beyondbit.Framework\Core\Proxy\Proxy.cs:line 55
   at Beyondbit.ConsoleFrameworkNetStandard.IntegrationTests.Program.Insert() in E:\\u5de5\u4f5c\u533a\03 \u4e92\u8054\u7f51\00 Beyondbit Infrastructure\\u5f00\u53d1\u6846\u67b6\3.0\Test\Integration\ConsoleFrameworkNetStandard\Program.cs:line 22
   at Beyondbit.ConsoleFrameworkNetStandard.IntegrationTests.Program.Main(String[] args) in E:\\u5de5\u4f5c\u533a\03 \u4e92\u8054\u7f51\00 Beyondbit Infrastructure\\u5f00\u53d1\u6846\u67b6\3.0\Test\Integration\ConsoleFrameworkNetStandard\Program.cs:line 14
\u5df2\u653e\u5f03 (core dumped)
[root@gumis02 PublishOutput]# 

可以看到錯誤的調用堆棧,是由log4net運行出來的,這個很有可能是裏面需要增加全局資源文件,因爲看到了System.Globalization命名空間,不過呢,已經能看到了正常的net 錯誤堆棧,可以證明dotnet 已經在中標麒麟的操作系統上能運行了。

這個異常產生的原因我在上面已經說明了,要解決這個問題,不能開啓Globalization.Invariant,必須講他設置成false,同時安裝ICU Packet解決
在runtimeconfig.json中添加以下配置即可,不想糾結原理的就使用這種方式即可:

    "configProperties": {
      "System.Globalization.Invariant": false
    }

執行結果:

[root@gumis02 PublishOutput]# dotnet Beyondbit.ConsoleFrameworkNetStandard.IntegrationTests.dll
用戶插入成功
[root@gumis02 PublishOutput]# 

dotnet core 2.0 在真實項目上,還有很多的未知,還等待我去解決和探索。 Keep going.

總結
經過一個星期的摸爬滾打終於在中標麒麟Linux系統上成功的運行了dotnet core 正式的項目,而不是helloworld程序。心力交瘁中也收穫了很多東西,在這一個星期中,我一個linux盲,也掌握了很多linux命令,如:mkdir,ln, find,ll,ldd 等等。

當然用了一個星期的時間,主要還是自己兩方面的問題:

  1. 對linux不熟悉,基本是linux盲
  2. 對net core 底層的編譯知識還不熟悉,在摸索當中

後續還要加強兩方面的學習,學無止境

後續

成功的是控制檯程序,下一步開始把做好的dotnet core web api + 前端 vuejs項目部署到麒麟系統上,我預計到又是一段打怪路程,通關後,我會繼續將通關記錄分享出來。

最後曬下截圖:
image

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章