webentwicklung-frage-antwort-db.com.de

der Docker-Container wird auch mit Console.ReadLine () in einer .net-Core-Konsolenanwendung sofort beendet

Ich versuche, eine .net Core 1.0.0-Konsolenanwendung in einem Docker-Container auszuführen.
Wenn ich den dotnet run-Befehl aus dem Demo-Ordner auf meinem Computer ausführe, funktioniert es einwandfrei. Bei Ausführung mit docker run -d --name demo Demo wird der Container jedoch sofort beendet. 

Ich habe versucht, docker logs demo die Protokolle zu überprüfen, und es wird nur der Text aus der Console.WriteLine angezeigt: 

Demo-App läuft ...

und sonst nichts.

Ich habe das Projekt unter https://github.com/learningdockerandnetcore/Demo hochgeladen.

Das Projekt enthält Programs.cs, Dockerfile zum Erstellen eines Demo-Images und project.json-Datei.

14
Learning Docker

Sie sollten Ihren Container entweder im interaktiven Modus ausführen (mit der Option -i). Beachten Sie jedoch, dass die Hintergrundprozesse sofort geschlossen werden, wenn Sie den Container ausführen. Stellen Sie daher sicher, dass Ihr Skript im Vordergrund ausgeführt wird, da es sonst nicht funktioniert.

7
Miad Abrin

Wenn Sie Ihre App auf .net Core 2.0 umstellen, können Sie Microsoft.Extensions.Hosting pacakge verwenden, um eine .net Core-Konsolenanwendung zu hosten, indem Sie die HostBuilder-API zum Starten/Stoppen der Anwendung verwenden. Die Klasse ConsoleLifetime verarbeitet die allgemeine Start/Stopp-Methode der Anwendung.

Um Ihre App auszuführen, müssen Sie eine eigene IHostedService-Schnittstelle implementieren oder von der Klasse BackgroundService erben und sie dem Host-Kontext in ConfigureServices hinzufügen.

namespace Microsoft.Extensions.Hosting
{
    //
    // Summary:
    //     Defines methods for objects that are managed by the Host.
    public interface IHostedService
    {
        // Summary:
        // Triggered when the application Host is ready to start the service.
        Task StartAsync(CancellationToken cancellationToken);

        // Summary:
        // Triggered when the application Host is performing a graceful shutdown.
        Task StopAsync(CancellationToken cancellationToken);
    }
}

Hier ist ein Beispiel für einen gehosteten Dienst:

public class TimedHostedService : IHostedService, IDisposable
{
    private readonly ILogger _logger;
    private Timer _timer;

    public TimedHostedService(ILogger<TimedHostedService> logger)
    {
        _logger = logger;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Timed Background Service is starting.");

        _timer = new Timer(DoWork, null, TimeSpan.Zero, 
            TimeSpan.FromSeconds(5));

        return Task.CompletedTask;
    }

    private void DoWork(object state)
    {
        _logger.LogInformation("Timed Background Service is working.");
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Timed Background Service is stopping.");

        _timer?.Change(Timeout.Infinite, 0);

        return Task.CompletedTask;
    }

    public void Dispose()
    {
        _timer?.Dispose();
    }
}

Erstellen Sie dann den HostBuilder und fügen Sie den Dienst und andere Komponenten hinzu (Protokollierung, Konfiguration).

public class Program
{
    public static async Task Main(string[] args)
    {
        var hostBuilder = new HostBuilder()
             // Add configuration, logging, ...
            .ConfigureServices((hostContext, services) =>
            {
                // Add your services with depedency injection.
            });

        await hostBuilder.RunConsoleAsync();
    }
}
10
Feiyu Zhou

Der einzige Weg, wie ich Docker/Linux dazu bringen konnte, meine .NET Core-Anwendung am Leben zu erhalten, war, ASP.NET für das Hosting für mich zu fälschen ... Dies ist ein so hässlicher Hack !! 

Wenn Sie dies auf diese Weise tun, wird dies in Docker mit der Option docker run -d ausgeführt, sodass Sie keine Live-Verbindung haben müssen, um den STDIN-Stream am Leben zu erhalten.

Ich habe eine .NET Core-Konsolenanwendung (keine ASP.NET-App) erstellt, und meine Programmklasse sieht folgendermaßen aus:

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();
        }
    }      
}

Die Startup-Klasse:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IServer, ConsoleAppRunner>();
    }


    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
    }
}

Die ConsoleAppRunner-Klasse

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.

    }
}

Das einzig schöne daran ist, dass Sie DI in Ihrer Anwendung verwenden können (wenn Sie möchten) - also verwende ich in meinem Anwendungsfall die ILoggingFactory, um meine Protokollierung durchzuführen.

Edit 30. Oktober 2018 Dieser Post scheint immer noch beliebt zu sein - ich möchte jeden, der meinen alten Post liest, darauf aufmerksam machen, dass er jetzt ziemlich alt ist. Ich habe es auf .NET Core 1.1 (das damals noch neu war) gegründet. Wenn Sie eine neuere Version von .NET-Kern (2.0/2.1 oder höher) verwenden, ist es wahrscheinlich, dass dieses Problem jetzt viel besser gelöst werden kann. Bitte nehmen Sie sich die Zeit, einige der anderen Beiträge in diesem Thread anzusehen, die möglicherweise nicht so hoch eingestuft sind wie dieser, aber möglicherweise neuer und aktueller sind.

10
Jay

Sie können verwenden:

Thread.Sleep(Timeout.Infinite);

Diese Antwort sehen:

Ist Thread.Sleep (Timeout.Infinite); effizienter als während (wahr) {}?

1
Tjaart

Ich bin nicht sicher, warum Console.ReadLine(); den Haupt-Thread nicht blockiert, wenn eine Dotnet-Core-Konsolen-App in einem separaten Docker-Container ausgeführt wird, aber die beste Lösung ist, eine ConsoleCancelEventHandler mit dem Console.CancelKeyPress-Ereignis zu registrieren.

Dann können Sie stattdessen den Haupt-Thread mit einem Typ von Threading WaitHandle blockieren und die Freigabe des Haupt-Threads signalisieren, wenn Console.CancelKeyPress ausgelöst wird.

Ein guter Beispielcode kann hier gefunden werden: https://Gist.github.com/kuznero/73acdadd8328383ea7d5

1
Patrick Burls

Ich benutze diesen Ansatz:

static async Task Main(string[] args)
{
   // run code ..

   await Task.Run(() => Thread.Sleep(Timeout.Infinite));
}
0
t2t

Für diejenigen, die Ihre .net 4.x-Konsolen-App in Linux Docker ausführen möchten, ohne -i und möchten es im Hintergrund ausführen, ist die beste Lösung mono.posix package, das genau das tut, wonach wir suchen, hört linux-signale ab.

das gilt auch für WebApi2 mit Owin Projekten oder grundsätzlich jedem console app

für die meisten von uns laufen Container im Hintergrund mit console.read oder ManualResetEventSlim oder AutoResetEvent funktioniert nicht, da der Docker den Modus getrennt hat.

Die beste Lösung ist die Installation von Install-Package Mono.Posix

hier ist ein Beispiel:

using System;
using Microsoft.Owin.Hosting;
using Mono.Unix;
using Mono.Unix.Native;

public class Program
{
    public static void Main(string[] args)
    {
        string baseAddress = "http://localhost:9000/"; 

        // Start OWIN Host 
        using (WebApp.Start<Startup>(url: baseAddress)) 
        { 
            Console.ReadLine(); 
        }

        if (IsRunningOnMono())
        {
            var terminationSignals = GetUnixTerminationSignals();
            UnixSignal.WaitAny(terminationSignals);
        }
        else
        {
            Console.ReadLine();
        }

        Host.Stop();
    }

    public static bool IsRunningOnMono()
    {
        return Type.GetType("Mono.Runtime") != null;
    }

    public static UnixSignal[] GetUnixTerminationSignals()
    {
        return new[]
        {
            new UnixSignal(Signum.SIGINT),
            new UnixSignal(Signum.SIGTERM),
            new UnixSignal(Signum.SIGQUIT),
            new UnixSignal(Signum.SIGHUP)
        };
    }
}

vollständiger Quellblogbeitrag: https://dusted.codes/running-nancyfx-in-a-docker-container-a-beginners-guide-to-build-and-run-dotnet-applications-in-docker

0

ein weiterer "schmutziger Weg" besteht darin, Ihr Programm im Bildschirm mit zu starten 

screen -dmS yourprogramm
0