2016-07-24 131 views
7

我試圖在Docker容器中運行.NET內核1.0.0控制檯應用程序。
當我在我的機器上的Demo文件夾內運行dotnet run命令時,它工作正常;但是當使用docker run -d --name demo Demo運行時,容器立即退出。Docker容器即使在.NET內核控制檯應用程序中使用Console.ReadLine()也會立即退出

我試圖docker logs demo檢查日誌,它只是顯示了從Console.WriteLine命令文本:

演示應用程序運行......

,別無其他。

我在https://github.com/learningdockerandnetcore/Demo

該項目包含Programs.csDockerfile用於創建演示圖像,並project.json文件上傳的項目。

+0

我想了解自己:我認爲你要在交互模式下運行它,並可能要加上一個期限。 'docker run -it -name demo demo' – hdz

+0

如果你在背景模式下運行它(-d),你也可以附加到它'docker attach {container}'來取回它。你不會看到輸出,因爲它已經輸出了,但你可以按回車鍵退出 – hdz

回答

6

您應該以交互模式運行容器(使用-i選項)。但請注意,後臺進程將在您運行容器時立即關閉,因此請確保您的腳本在前臺運行,否則它將無法工作。

+0

不是'-i'交互模式 - 不是守護進程(或分離)模式? – Jay

+0

是的,'-d'是deamon/detached模式。 – Peter

8

我可以讓Docker/Linux保持我的.NET Core應用程序活着的唯一方法是欺騙ASP.NET來爲我託管它......這是一個很醜陋的黑客!

這樣做會在Docker中使用docker run -d選項運行,因此您不必擁有實時連接來保持STDIN流的活性。

我創建了一個.NET的核心控制檯應用程序(不是一個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來處理我的日誌記錄。

0

多了一個「骯髒的方式」是使用

screen -dmS yourprogramm 
0

我不知道爲什麼在分離泊塢窗容器中運行的dotnet核心控制檯應用程序時Console.ReadLine();不會阻塞主線程在屏幕開始你的程序,但最好的解決方案是在Console.CancelKeyPress事件中註冊ConsoleCancelEventHandler

然後,您可以使用線程WaitHandle阻止主線程,並在啓動Console.CancelKeyPress時發出主線程的釋放信號。

一個很好的例子代碼可以在這裏找到:https://gist.github.com/kuznero/73acdadd8328383ea7d5

0

使用Console.ReadLine而不是似乎工作。

C#:

do 
{ 
    Console.WriteLine($"Type: quit<Enter> to end {Process.GetCurrentProcess().ProcessName}"); 
} 
while (!Console.ReadLine().Trim().Equals("quit",StringComparison.OrdinalIgnoreCase)); 

F#:

while not (Console.ReadLine().Trim().Equals("quit",StringComparison.OrdinalIgnoreCase)) do 
    printfn "Type: quit<Enter> to end" 
相關問題