docker容器即使在.net核心控制台应用程序中使用Console.ReadLine()也会立即退出

我正在尝试在Docker容器中运行.net核心1.0.0控制台应用程序。
当我从我的机器上的Demo文件夹内运行dotnet run命令时,它工作正常; 但是使用docker run -d --name demo Demo时,容器会立即退出。

我试着docker logs demo检查日志,它只是显示Console.WriteLine文本:

演示程序运行…

没有别的。

我已经在https://github.com/learningdockerandnetcore/Demo上传了这个项目

该项目包含Programs.cs ,用于创build演示图像的Dockerfileproject.json文件。

您应该以交互模式运行容器(使用-i选项)。 但请注意,后台进程将在运行容器时立即closures,因此请确保脚本在前台运行,否则将无法工作。

让Docker / Linux保持我的.NET Core应用程序活着的唯一方法就是欺骗ASP.NET来为我托pipe它…这真是一个丑陋的黑客!

这样做将在Docker中使用docker run -d选项docker run -d ,因此您不必拥有一个实时连接来保持STDINstream的活性。

我创build了一个.NET Core控制台应用程序(不是一个ASP.NET应用程序),我的程序类看起来像这样:

 public class Program { public static ManualResetEventSlim Done = new ManualResetEventSlim(false); public static void Main(string[] args) { //This is unbelievably complex because .NET Core Console.ReadLine() does not block in a docker container...! var host = new WebHostBuilder().UseStartup(typeof(Startup)).Build(); using (CancellationTokenSource cts = new CancellationTokenSource()) { Action shutdown = () => { if (!cts.IsCancellationRequested) { Console.WriteLine("Application is shutting down..."); cts.Cancel(); } Done.Wait(); }; Console.CancelKeyPress += (sender, eventArgs) => { shutdown(); // Don't terminate the process immediately, wait for the Main thread to exit gracefully. eventArgs.Cancel = true; }; host.Run(cts.Token); Done.Set(); } } } 

启动类:

 public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddSingleton<IServer, ConsoleAppRunner>(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { } } 

ConsoleAppRunner类

 public class ConsoleAppRunner : IServer { /// <summary>A collection of HTTP features of the server.</summary> public IFeatureCollection Features { get; } public ConsoleAppRunner(ILoggerFactory loggerFactory) { Features = new FeatureCollection(); } /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary> public void Dispose() { } /// <summary>Start the server with an application.</summary> /// <param name="application">An instance of <see cref="T:Microsoft.AspNetCore.Hosting.Server.IHttpApplication`1" />.</param> /// <typeparam name="TContext">The context associated with the application.</typeparam> public void Start<TContext>(IHttpApplication<TContext> application) { //Actual program code starts here... Console.WriteLine("Demo app running..."); Program.Done.Wait(); // <-- Keeps the program running - The Done property is a ManualResetEventSlim instance which gets set if someone terminates the program. } } 

唯一的好处就是你可以在应用程序中使用DI(如果你愿意的话) – 所以在我的用例中,我使用ILoggingFactory来处理日志。

另一个“肮脏的方式”是在屏幕上使用开始你的程序

 screen -dmS yourprogramm 

我不知道为什么Console.ReadLine(); 在分离的ConsoleCancelEventHandler容器中运行dotnet核心控制台应用程序时,不阻止主线程,但最好的解决scheme是使用Console.CancelKeyPress事件注册ConsoleCancelEventHandler

然后你可以用一个线程WaitHandle来阻塞主线程,并在Console.CancelKeyPress被触发时发出主线程的释放信号。

一个很好的示例代码可以在这里find: https : //gist.github.com/kuznero/73acdadd8328383ea7d5

您可以使用:

Thread.Sleep(Timeout.Infinite);

看到这个答案:

是Thread.Sleep(Timeout.Infinite); 比while(true){}更有效率?