以非root用户身份在linux中运行mono-service

问题描述:

我需要在嵌入式系统上以最低Ubuntu安装方式运行.net C#应用程序(在Windows系统上开发)作为服务/守护程序(不包括X,除服务器外SSH,只有相关的软件)。我创建了一个/etc/init.d脚本,其中包含该行以非root用户身份在linux中运行mono-service

mono-service my-.net-app.exe service 

并且工作良好。还有交互式启动应用程序(用于调试)选项与

mono my-.net-app.exe interactive 

最后一个参数是告诉它,如果它是作为服务运行的.NET应用程序的参数。这是大致这种方式实现:

private static void Main(string[] args){ 
    if(args.Any() && args[0] != null && args[0] == "service"){ 
    ServiceBase.Run(new[] {(ServiceBase) new MyService()}); 
    }else{ 
    try{ 
     Console.Write("starting app"); 
     if(StartWork()){ 
     Console.Write("press any key to exit"); 
     Console.ReadKey(); 
     }else{ 
     Console.WriteLine("starting app failed"); 
     } 
    } // end try 
    finally{ 
     StopWork(); 
     Console.WriteLine("finished app"); 
    } 
    } // end else 
... 
} // end Main 

public class MyService : ServiceBase{ 
    static private Thread _worker; 

    protected override void OnStart(string[] args){ 
    _worker = new Thread(() => Program.StartWork(asService: true)); // this asService tells StartWork to not produce console output 
    _worker.Start(); 
    } 

    protected override void OnStop(){ 
    Program.StopWork(); 
    _worker.Join(1000); 
    } 
} 

这种实现的目的是允许应用程序(即,执行StopWork())于Linux机器上发送SIGTERM正常死亡。

出于安全原因,我需要能够以非root用户身份运行该服务。我创建了一个新用户,并使其成为应用程序写入其日志文件的目录的所有者,并将其添加到各个组以允许其访问所需的设备文件。然后,根将启动应用程序作为

sudo -u newuser mono-service my-.net-app.exe service 

sudo -u newuser mono my-.net-app.exe interactive 

mono与第二个选择的效果很好,但第一个与mono-service不(见下文错误消息)。由于它与mono一起使用,我相信用户newuser具有访问所有相关文件和设备的适当权限。我想知道mono-service是否被设想为仅限于根的应用程序。

我也可以住在一起使用mono选项,并抑制控制台输出,就像这样:

private static void Main(string[] args){ 
    try{ 
    Console.Write("starting app"); 
    if(StartWork(consoleoutput)){ // true or false depending on whether the service argument was given 
     Console.Write("press any key to exit"); 
     Console.ReadKey(); 
    }else{ 
     Console.WriteLine("starting app failed"); 
    } 
    } // end try 
    finally{ 
    StopWork(); 
    Console.WriteLine("finished app"); 
    } 
... 
} // end Main 

但后来,当我杀死服务(即发送SIGTERM到mono过程),它停止.net应用程序,而不允许它执行finally块。

最后,我的问题是否有人知道为什么mono-service在没有以root身份启动时失败。错误消息如下,正如我前面提到的,当我使用mono而不是mono-service时,它不存在。

ERROR Program [4] [15:03:06.795 01/12/14] Error in Main! 
FluentNHibernate.Cfg.FluentConfigurationException: An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail. 

---> NHibernate.HibernateException: Could not create the driver from SAFEmine.DataStore.Database.MonoSqliteDriver, SAFEmine.DataStore, Version=1.3.0.6, Culture=neutral, PublicKeyToken=null. ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> NHibernate.HibernateException: The IDbCommand and IDbConnection implementation in the assembly Mono.Data.Sqlite could not be found. Ensure that the assembly Mono.Data.Sqlite is located in the application directory or in the Global Assembly Cache. If the assembly is in the GAC, use <qualifyAssembly/> element in the application configuration file to specify the full name of the assembly. 
at NHibernate.Driver.ReflectionBasedDriver..ctor (System.String providerInvariantName, System.String driverAssemblyName, System.String connectionTypeName, System.String commandTypeName) [0x00000] in <filename unknown>:0 
at NHibernate.Driver.ReflectionBasedDriver..ctor (System.String driverAssemblyName, System.String connectionTypeName, System.String commandTypeName) [0x00000] in <filename unknown>:0 
at SAFEmine.DataStore.Database.MonoSqliteDriver..ctor() [0x00000] in <filename unknown>:0 
at (wrapper managed-to-native) System.Reflection.MonoCMethod:InternalInvoke (System.Reflection.MonoCMethod,object,object[],System.Exception&) 
at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) [0x00000] in <filename unknown>:0 

或者,如果我满足于mono代替mono-service,有没有办法从.NET应用程序中,并优雅地死抓SIGTERM?我试过这个:https://github.com/ServiceStack/ServiceStack/wiki/Run-ServiceStack-as-a-daemon-on-Linux,但是代码不会在Visual Studio上编译,说这个using Mono.Unix;using Mono.Unix.Native行是无效的。我还在Windows上安装了Mono,并试图使用Mono编译器,但它抱怨同样的事情。

+1

'Mono.Unix'在[Mono.Posix.dll](http://*.com/a/8408723/85785)中。 – mythz 2014-12-01 17:15:02

mono-service.exe创建一个新的AppDomainApplicationBase是当前目录。这可能会影响装配加载。由于您看到这样的错误,我会尝试启用MONO_LOG_LEVEL=debug MONO_LOG_MASK=asm和/或strace -e file以查看它们是否提供任何提示。

另外请注意,您可以通过-d切换到mono-service来让它更改您的目录。