Freigeben über


Docker-Bereitstellung

Tipp

Auch wenn Sie mit Docker oder Orleansvertraut sind, wird empfohlen, diesen Artikel am Ende zu lesen, um potenzielle Probleme mit bekannten Problemumgehungen zu vermeiden.

Dieser Artikel und sein Beispiel sind keine endgültige Fassung. Feedback, PRs oder Vorschläge sind willkommen.

Bereitstellen von Orleans-Lösungen in Docker

Die Bereitstellung Orleans in Docker kann aufgrund des Designs von Docker-Orchestratoren und Clustering-Stapeln schwierig sein. Der komplizierteste Teil ist das Verständnis des Konzepts des Overlay-Netzwerks von Docker-Schwarm und dem Kubernetes-Netzwerkmodell.

Docker-Container und Netzwerkmodelle wurden in erster Linie für die Ausführung zustandsloser und unveränderlicher Container entwickelt. Das Einrichten eines Clusters mit Node.js- oder Nginx-Anwendungen ist ziemlich einfach. Die Verwendung von etwas Aufwändigem, wie eine wirklich gruppierte oder verteilte Anwendung (wie eine, die auf Orleans basiert), kann jedoch Schwierigkeiten bei der Einrichtung darstellen. Es ist möglich, aber nicht so einfach wie die Bereitstellung webbasierter Anwendungen.

Docker-Clustering umfasst das Gruppieren mehrerer Hosts, um als einzelner Ressourcenpool zu arbeiten, der mit einem Container Orchestrator verwaltet wird. Docker Inc. bietet Schwarm als Option, während GoogleKubernetes (auch bekannt als K8s) anbietet. Andere Orchestratoren wie DC/OS und Mesos existieren, aber dieses Dokument konzentriert sich auf Schwarm und K8s, da sie häufiger verwendet werden.

Dieselben Schnittstellen und Implementierungen, die überall dort laufen, wo Orleans unterstützt wird, laufen auch auf Docker-Containern. Es sind keine besonderen Überlegungen erforderlich, um eine Orleans Anwendung in Docker-Containern auszuführen.

Die hier beschriebenen Konzepte gelten sowohl für .NET Core- als auch .NET Framework 4.6.1-Versionen von Orleans. Um die Plattformunabhängigkeit von Docker und .NET Core zu veranschaulichen, werden Beispiele mit .NET Core besonders hervorgehoben. Plattformspezifische Details (Windows/Linux/macOS) können ggf. bereitgestellt werden.

Voraussetzungen

In diesem Artikel wird davon ausgegangen, dass die folgenden Voraussetzungen installiert sind:

  • Docker: Docker4X verfügt über ein benutzerfreundliches Installationsprogramm für wichtige unterstützte Plattformen. Es enthält die Docker-Engine und Docker Swarm.
  • Kubernetes (K8s): Das Container-Orchestrierungsangebot von Google. Es enthält Anleitungen für die Installation von Minikube (eine lokale K8s-Bereitstellung) und Kubectl zusammen mit Abhängigkeiten.
  • .NET: Plattformübergreifende Variante von .NET.
  • Visual Studio Code (VSCode):Jede bevorzugte IDE kann verwendet werden. VSCode wird hier verwendet, da es plattformübergreifend ist und sicherstellt, dass Beispiele auf allen Plattformen funktionieren. Installieren Sie nach der Installation von VSCode die C#-Erweiterung.

Wichtig

Die Kubernetes-Installation ist nicht erforderlich, wenn sie nicht verwendet wird. Das Docker4X-Installationsprogramm enthält bereits Schwarm, sodass für Schwarm keine zusätzliche Installation erforderlich ist.

Hinweis

Unter Windows aktiviert das Docker-Installationsprogramm Hyper-V während der Installation. Da in diesem Artikel und in seinen Beispielen .NET Core verwendet werden, basieren die verwendeten Containerimages auf Windows Server NanoServer. Wenn Sie stattdessen .NET Framework 4.6.1 verwenden möchten, verwenden Sie Bilder, die auf Windows Server Core und Orleans Version 1.4+ basieren (die nur .NET Framework unterstützt).

Erstellen einer Orleans Lösung

Die folgenden Anweisungen zeigen, wie Sie mit dem Orleans Werkzeug eine Standardlösung dotnet erstellen.

Passen Sie die Befehle entsprechend der Plattform an. Die Verzeichnisstruktur ist nur ein Vorschlag; passen Sie sie nach Bedarf an.

mkdir Orleans-Docker
cd Orleans-Docker
dotnet new sln
mkdir -p src/OrleansSilo
mkdir -p src/OrleansClient
mkdir -p src/OrleansGrains
mkdir -p src/OrleansGrainInterfaces
dotnet new console -o src/OrleansSilo --framework netcoreapp1.1
dotnet new console -o src/OrleansClient --framework netcoreapp1.1
dotnet new classlib -o src/OrleansGrains --framework netstandard1.5
dotnet new classlib -o src/OrleansGrainInterfaces --framework netstandard1.5
dotnet sln add src/OrleansSilo/OrleansSilo.csproj
dotnet sln add src/OrleansClient/OrleansClient.csproj
dotnet sln add src/OrleansGrains/OrleansGrains.csproj
dotnet sln add src/OrleansGrainInterfaces/OrleansGrainInterfaces.csproj
dotnet add src/OrleansClient/OrleansClient.csproj reference src/OrleansGrainInterfaces/OrleansGrainInterfaces.csproj
dotnet add src/OrleansSilo/OrleansSilo.csproj reference src/OrleansGrainInterfaces/OrleansGrainInterfaces.csproj
dotnet add src/OrleansGrains/OrleansGrains.csproj reference src/OrleansGrainInterfaces/OrleansGrainInterfaces.csproj
dotnet add src/OrleansSilo/OrleansSilo.csproj reference src/OrleansGrains/OrleansGrains.csproj

Bisher wurden nur Codebausteine für die Lösungsstruktur und Projekte erstellt und Verweise dazwischen hinzugefügt. Dies unterscheidet sich nicht von der Einrichtung eines regulären Orleans Projekts.

Zu dem Zeitpunkt, zu dem dieser Artikel geschrieben wurde, Orleans war 2.0 (unterstützung für .NET Core und plattformübergreifende Entwicklung) in Technology Preview. Die NuGet-Pakete wurden in einem MyGet-Feed gehostet, nicht in dem offiziellen NuGet.org-Feed. Um die Vorschau-NuGet-Pakete zu installieren, verwenden Sie die dotnet CLI, wodurch der Quellfeed und die Version von MyGet erzwungen werden:

dotnet add src/OrleansClient/OrleansClient.csproj package Microsoft.Orleans.Core -s https://dotnet.myget.org/F/orleans-prerelease/api/v3/index.json -v 2.0.0-preview2-201705020000
dotnet add src/OrleansGrainInterfaces/OrleansGrainInterfaces.csproj package Microsoft.Orleans.Core -s https://dotnet.myget.org/F/orleans-prerelease/api/v3/index.json -v 2.0.0-preview2-201705020000
dotnet add src/OrleansGrains/OrleansGrains.csproj package Microsoft.Orleans.Core -s https://dotnet.myget.org/F/orleans-prerelease/api/v3/index.json -v 2.0.0-preview2-201705020000
dotnet add src/OrleansSilo/OrleansSilo.csproj package Microsoft.Orleans.Core -s https://dotnet.myget.org/F/orleans-prerelease/api/v3/index.json -v 2.0.0-preview2-201705020000
dotnet add src/OrleansSilo/OrleansSilo.csproj package Microsoft.Orleans.OrleansRuntime -s https://dotnet.myget.org/F/orleans-prerelease/api/v3/index.json -v 2.0.0-preview2-201705020000
dotnet restore

Okay, alle grundlegenden Abhängigkeiten zum Ausführen einer einfachen Orleans Anwendung sind jetzt vorhanden. Beachten Sie, dass sich bis zu diesem Zeitpunkt bei der Einrichtung einer regulären Orleans Anwendung nichts geändert hat. Nun fügen wir code hinzu, um ihn funktionsfähig zu machen.

Implementieren der Orleans Anwendung

Angenommen, VSCode wird verwendet, führen Sie code . aus dem Lösungsverzeichnis aus. Mit diesem Befehl wird das Verzeichnis in VSCode geöffnet und die Lösung geladen.

Dies ist die zuvor erstellte Lösungsstruktur.

Visual Studio Code: Explorer mit ausgewählter Datei „Program.cs“.

Program.cs, OrleansHostWrapper.cs, IGreetingGrain.cs und GreetingGrain.cs Dateien wurden ebenfalls zu den Schnittstellen- und Kornprojekten hinzugefügt. Hier ist der Code für diese Dateien:

IGreetingGrain.cs:

using System;
using System.Threading.Tasks;
using Orleans;

namespace OrleansGrainInterfaces
{
    public interface IGreetingGrain : IGrainWithGuidKey
    {
        Task<string> SayHello(string name);
    }
}

GreetingGrain.cs:

using System;
using System.Threading.Tasks;
using OrleansGrainInterfaces;

namespace OrleansGrains
{
    public class GreetingGrain : Grain, IGreetingGrain
    {
        public Task<string> SayHello(string name)
        {
            return Task.FromResult($"Hello from Orleans, {name}");
        }
    }
}

OrleansHostWrapper.cs:

using System;
using System.NET;
using Orleans.Runtime;
using Orleans.Runtime.Configuration;
using Orleans.Runtime.Host;

namespace OrleansSilo;

public class OrleansHostWrapper
{
    private readonly SiloHost _siloHost;

    public OrleansHostWrapper(ClusterConfiguration config)
    {
        _siloHost = new SiloHost(Dns.GetHostName(), config);
        _siloHost.LoadOrleansConfig();
    }

    public int Run()
    {
        if (_siloHost is null)
        {
            return 1;
        }

        try
        {
            _siloHost.InitializeOrleansSilo();

            if (_siloHost.StartOrleansSilo())
            {
                Console.WriteLine(
                    $"Successfully started Orleans silo '{_siloHost.Name}' as a {_siloHost.Type} node.");
                return 0;
            }
            else
            {
                throw new OrleansException(
                    $"Failed to start Orleans silo '{_siloHost.Name}' as a {_siloHost.Type} node.");
            }
        }
        catch (Exception exc)
        {
            _siloHost.ReportStartupError(exc);
            Console.Error.WriteLine(exc);

            return 1;
        }
    }

    public int Stop()
    {
        if (_siloHost is not null)
        {
            try
            {
                _siloHost.StopOrleansSilo();
                _siloHost.Dispose();
                Console.WriteLine($"Orleans silo '{_siloHost.Name}' shutdown.");
            }
            catch (Exception exc)
            {
                siloHost.ReportStartupError(exc);
                Console.Error.WriteLine(exc);

                return 1;
            }
        }
        return 0;
    }
}

Program.cs (Silo):

using System;
using System.Collections.Generic;
using System.Linq;
using System.NET;
using System.Threading.Tasks;
using Orleans.Runtime.Configuration;

namespace OrleansSilo
{
    public class Program
    {
        private static OrleansHostWrapper s_hostWrapper;

        static async Task<int> Main(string[] args)
        {
            int exitCode = await InitializeOrleansAsync();

            Console.WriteLine("Press Enter to terminate...");
            Console.ReadLine();

            exitCode += ShutdownSilo();

            return exitCode;
        }

        private static int InitializeOrleansAsync()
        {
            var config = new ClusterConfiguration();
            config.Globals.DataConnectionString =
                "[AZURE STORAGE CONNECTION STRING HERE]";
            config.Globals.DeploymentId = "Orleans-Docker";
            config.Globals.LivenessType =
                GlobalConfiguration.LivenessProviderType.AzureTable;
            config.Globals.ReminderServiceType =
                GlobalConfiguration.ReminderServiceProviderType.AzureTable;
            config.Defaults.PropagateActivityId = true;
            config.Defaults.ProxyGatewayEndpoint =
                new IPEndPoint(IPAddress.Any, 10400);
            config.Defaults.Port = 10300;
            var ips = await Dns.GetHostAddressesAsync(Dns.GetHostName());
            config.Defaults.HostNameOrIPAddress =
                ips.FirstOrDefault()?.ToString();

            s_hostWrapper = new OrleansHostWrapper(config);
            return hostWrapper.Run();
        }

        static int ShutdownSilo() =>
            s_hostWrapper?.Stop() ?? 0;
    }
}

Program.cs (Client):

using System;
using System.NET;
using System.Threading;
using System.Threading.Tasks;
using Orleans;
using Orleans.Runtime.Configuration;
using OrleansGrainInterfaces;

namespace OrleansClient
{
    class Program
    {
        private static IClusterClient s_client;
        private static bool s_running;

        static async Task Main(string[] args)
        {
            await InitializeOrleansAsync();

            Console.ReadLine();

            s_running = false;
        }

        static async Task InitializeOrleansAsync()
        {
            var config = new ClientConfiguration
            {
                DeploymentId = "Orleans-Docker";
                PropagateActivityId = true;
            };
            var hostEntry =
                await Dns.GetHostEntryAsync("orleans-silo");
            var ip = hostEntry.AddressList[0];
            config.Gateways.Add(new IPEndPoint(ip, 10400));

            Console.WriteLine("Initializing...");

            using client = new ClientBuilder().UseConfiguration(config).Build();
            await client.Connect();
            s_running = true;
            Console.WriteLine("Initialized!");

            var grain = client.GetGrain<IGreetingGrain>(Guid.Empty);

            while (s_running)
            {
                var response = await grain.SayHello("Gutemberg");
                Console.WriteLine($"[{DateTime.UtcNow}] - {response}");

                await Task.Delay(1000);
            }
        }
    }
}

Die Details zur Kornimplementierung werden hier nicht behandelt, da sie außerhalb des Umfangs dieses Artikels liegen. Weitere Informationen finden Sie in anderen relevanten Dokumenten. Diese Dateien stellen eine minimale Orleans Anwendung dar, die als Ausgangspunkt für den Rest dieses Artikels dient.

In diesem Artikel wird der OrleansAzureUtils Mitgliedschaftsanbieter verwendet, aber jeder andere Orleansunterstützte Anbieter kann verwendet werden.

Die Dockerfile-Datei

Docker verwendet Images zum Erstellen von Containern. Weitere Informationen zum Erstellen von benutzerdefinierten Images finden Sie in der Docker-Dokumentation. In diesem Artikel werden offizielle Microsoft-Bilder verwendet. Wählen Sie basierend auf den Ziel- und Entwicklungsplattformen das entsprechende Image aus. microsoft/dotnet:1.1.2-sdk, ein Linux-basiertes Image, wird hier verwendet. Für Windows microsoft/dotnet:1.1.2-sdk-nanoserver könnte z. B. verwendet werden. Wählen Sie das, das den Anforderungen entspricht.

Hinweis für Windows-Benutzer: Wie bereits erwähnt, werden .NET Core und Orleans Technical Preview 2.0 in diesem Artikel verwendet, um plattformübergreifende Kompatibilität aufrechtzuerhalten. Um Docker unter Windows mit der vollständig veröffentlichten Orleans Version 1.4+ zu verwenden, verwenden Sie Images, die auf Windows Server Core basieren, da NanoServer- und Linux-basierte Images nur .NET Core unterstützen.

Dockerfile.debug:

FROM microsoft/dotnet:1.1.2-sdk
ENV NUGET_XMLDOC_MODE skip
WORKDIR /vsdbg
RUN apt-get update \
    && apt-get install -y --no-install-recommends \
        unzip \
    && rm -rf /var/lib/apt/lists/* \
    && curl -sSL https://aka.ms/getvsdbgsh | bash /dev/stdin -v latest -l /vsdbg
WORKDIR /app
ENTRYPOINT ["tail", "-f", "/dev/null"]

Diese Dockerfile lädt im Wesentlichen den VSdbg-Debugger herunter und installiert ihn, und startet einen leeren Container, der unbegrenzt aktiv bleibt, sodass er während des Debuggings nicht ständig heruntergefahren und neu gestartet werden muss.

Für die Produktion ist das Image kleiner, da es nur die .NET Core-Laufzeit und nicht das gesamte SDK enthält. Die Dockerfile-Datei ist ebenfalls einfacher:

Docker-Datei:

FROM microsoft/dotnet:1.1.2-runtime
WORKDIR /app
ENTRYPOINT ["dotnet", "OrleansSilo.dll"]
COPY . /app

Die „docker-compose“-Datei

Die docker-compose.yml Datei definiert eine Reihe von Diensten und deren Abhängigkeiten innerhalb eines Projekts auf Dienstebene. Jeder Dienst enthält eine oder mehrere Instanzen eines bestimmten Containers, basierend auf den in der Dockerfile-Datei ausgewählten Images. Weitere Informationen docker-compose finden Sie in der Docker-Compose-Dokumentation.

Bei einer Orleans Bereitstellung umfasst ein gängiger Anwendungsfall eine docker-compose.yml Datei mit zwei Diensten: einer für den Orleans Silo und einer für den Orleans Client. Der Clientdienst hängt vom Silo-Dienst ab, was bedeutet, dass er erst gestartet wird, nachdem der Silo-Dienst ausgeführt wurde. Ein weiteres Szenario kann das Hinzufügen eines Speicher- oder Datenbankdiensts/-Containers (z. B. SQL Server) umfassen, der sowohl vor dem Client als auch dem Silo gestartet werden soll. In diesem Fall würden sowohl Client- als auch Silodienste vom Datenbankdienst abhängen.

Hinweis

Bevor Sie weiterlesen, beachten Sie, dass ein Einzugwichtig ist in docker-compose Dateien. Achten Sie darauf, wenn Probleme auftreten.

Hier erfahren Sie, wie die Dienste für diesen Artikel beschrieben werden:

docker-compose.override.yml (Debuggen):

version: '3.1'

services:
  orleans-client:
    image: orleans-client:debug
    build:
      context: ./src/OrleansClient/bin/PublishOutput/
      dockerfile: Dockerfile.Debug
    volumes:
      - ./src/OrleansClient/bin/PublishOutput/:/app
      - ~/.nuget/packages:/root/.nuget/packages:ro
    depends_on:
      - orleans-silo
  orleans-silo:
    image: orleans-silo:debug
    build:
      context: ./src/OrleansSilo/bin/PublishOutput/
      dockerfile: Dockerfile.Debug
    volumes:
      - ./src/OrleansSilo/bin/PublishOutput/:/app
      - ~/.nuget/packages:/root/.nuget/packages:ro

docker-compose.yml (Produktion):

version: '3.1'

services:
  orleans-client:
    image: orleans-client
    depends_on:
      - orleans-silo
  orleans-silo:
    image: orleans-silo

In der Produktion wird das lokale Verzeichnis nicht zugeordnet, auch ist die build: Aktion nicht enthalten. Der Grund dafür ist, dass in einer Produktionsumgebung Images erstellt und an eine private Docker-Registrierung übertragen werden sollten.

Zusammenfügen der Bestandteile

Nachdem nun alle erforderlichen Komponenten bereit sind, stellen wir sie zusammen, um die Orleans Lösung in Docker auszuführen.

Wichtig

Die folgenden Befehle sollten aus dem Projektmappenverzeichnis ausgeführt werden.

Stellen Sie zunächst sicher, dass alle NuGet-Pakete für die Lösung wiederhergestellt werden. Dies muss in der Regel nur einmal ausgeführt werden, es sei denn, Paketabhängigkeiten ändern sich.

dotnet restore

Erstellen Sie nun die Lösung wie gewohnt mit der dotnet CLI, und veröffentlichen Sie sie in einem Ausgabeverzeichnis:

dotnet publish -o ./bin/PublishOutput

Tipp

publish wird hier anstelle von build verwendet, um Probleme mit dynamisch geladenen Assemblys in Orleans zu vermeiden. Es wird noch eine bessere Lösung gesucht.

Erstellen Sie mit der erstellten und veröffentlichten Anwendung die Docker-Images mithilfe der Dockerfiles. Dieser Schritt muss in der Regel nur einmal pro Projekt ausgeführt werden. Es sollte nur erneut benötigt werden, wenn sich die Dockerfile- oder Docker-Compose-Datei ändert oder die lokale Imageregistrierung aus irgendeinem Grund bereinigt wird.

docker-compose build

Alle Basisimages, die in sowohl Dockerfile als auch docker-compose.yml verwendet werden, werden aus dem Registry abgerufen und auf dem Entwicklungscomputer zwischengespeichert. Die Anwendungsimages sind erstellt, und alles kann ausgeführt werden.

Jetzt führen wir die Anwendung aus!

# docker-compose up -d
Creating network "orleansdocker_default" with the default driver
Creating orleansdocker_orleans-silo_1 ...
Creating orleansdocker_orleans-silo_1 ... done
Creating orleansdocker_orleans-client_1 ...
Creating orleansdocker_orleans-client_1 ... done
#

Die Ausführung von docker-compose ps zeigt nun zwei Container an, die im orleansdocker Projekt ausgeführt werden.

# docker-compose ps
             Name                     Command        State   Ports
------------------------------------------------------------------
orleansdocker_orleans-client_1   tail -f /dev/null   Up
orleansdocker_orleans-silo_1     tail -f /dev/null   Up

Hinweis

Wenn unter Windows und der Container ein Windows-Basisimage verwendet, zeigt die Befehlsspalte den PowerShell-äquivalenten Befehl zu tail auf *NIX-Systemen an, wodurch der Container ähnlich weiterläuft.

Nachdem die Container ausgeführt werden, ist das Beenden nicht jedes Mal erforderlich, wenn die Orleans Anwendung gestartet werden muss. Integrieren Sie einfach die IDE, um die Anwendung innerhalb des Containers zu debuggen, die zuvor zugeordnet docker-compose.ymlwurde.

Skalierung

Sobald das Verfassenprojekt ausgeführt wird, skalieren Sie die Anwendung mithilfe des docker-compose scale Befehls auf einfache Weise nach oben oder unten:

# docker-compose scale orleans-silo=15
Starting orleansdocker_orleans-silo_1 ... done
Creating orleansdocker_orleans-silo_2 ...
Creating orleansdocker_orleans-silo_3 ...
Creating orleansdocker_orleans-silo_4 ...
Creating orleansdocker_orleans-silo_5 ...
Creating orleansdocker_orleans-silo_6 ...
Creating orleansdocker_orleans-silo_7 ...
Creating orleansdocker_orleans-silo_8 ...
Creating orleansdocker_orleans-silo_9 ...
Creating orleansdocker_orleans-silo_10 ...
Creating orleansdocker_orleans-silo_11 ...
Creating orleansdocker_orleans-silo_12 ...
Creating orleansdocker_orleans-silo_13 ...
Creating orleansdocker_orleans-silo_14 ...
Creating orleansdocker_orleans-silo_15 ...
Creating orleansdocker_orleans-silo_6
Creating orleansdocker_orleans-silo_5
Creating orleansdocker_orleans-silo_3
Creating orleansdocker_orleans-silo_2
Creating orleansdocker_orleans-silo_4
Creating orleansdocker_orleans-silo_9
Creating orleansdocker_orleans-silo_7
Creating orleansdocker_orleans-silo_8
Creating orleansdocker_orleans-silo_10
Creating orleansdocker_orleans-silo_11
Creating orleansdocker_orleans-silo_15
Creating orleansdocker_orleans-silo_12
Creating orleansdocker_orleans-silo_14
Creating orleansdocker_orleans-silo_13

Nach ein paar Sekunden skalieren die Dienste auf die angegebene Anzahl der Instanzen, die angefordert wurden.

# docker-compose ps
             Name                     Command        State   Ports
------------------------------------------------------------------
orleansdocker_orleans-client_1   tail -f /dev/null   Up
orleansdocker_orleans-silo_1     tail -f /dev/null   Up
orleansdocker_orleans-silo_10    tail -f /dev/null   Up
orleansdocker_orleans-silo_11    tail -f /dev/null   Up
orleansdocker_orleans-silo_12    tail -f /dev/null   Up
orleansdocker_orleans-silo_13    tail -f /dev/null   Up
orleansdocker_orleans-silo_14    tail -f /dev/null   Up
orleansdocker_orleans-silo_15    tail -f /dev/null   Up
orleansdocker_orleans-silo_2     tail -f /dev/null   Up
orleansdocker_orleans-silo_3     tail -f /dev/null   Up
orleansdocker_orleans-silo_4     tail -f /dev/null   Up
orleansdocker_orleans-silo_5     tail -f /dev/null   Up
orleansdocker_orleans-silo_6     tail -f /dev/null   Up
orleansdocker_orleans-silo_7     tail -f /dev/null   Up
orleansdocker_orleans-silo_8     tail -f /dev/null   Up
orleansdocker_orleans-silo_9     tail -f /dev/null   Up

Wichtig

Die Command Spalte in diesen Beispielen zeigt den tail Befehl, da der Debuggercontainer verwendet wird. In der Produktion würde es angezeigt werden, z. B. dotnet OrleansSilo.dll.

Docker-Schwarm

Dockers Clustering-Stapel wird als Schwarm bezeichnet. Weitere Informationen finden Sie unter Docker-Schwarm.

Um die in diesem Artikel beschriebene Anwendung in einem Swarm Cluster auszuführen, ist keine zusätzliche Arbeit erforderlich. Die Ausführung docker-compose up -d auf einem Swarm Knoten plant Container basierend auf konfigurierten Regeln. Das gleiche gilt für andere schwarmbasierte Dienste wie Azure Kubernetes Service (AKS) (im Schwarmmodus) und AWS Elastic Container Service (ECS). Stellen Sie einfach den Swarm Cluster bereit, bevor Sie die dockerisierteOrleans Anwendung bereitstellen.

Hinweis

Wenn Sie eine Docker-Engine mit Unterstützung für den Schwarmmodus verwenden und stack, deploy sowie compose v3 unterstützen, ist docker stack deploy -c docker-compose.yml <name> ein besserer Ansatz für die Bereitstellung der Lösung. Beachten Sie, dass dies eine v3-Erstelldatei erfordert, die mit dem Docker-Modul kompatibel ist. Viele gehostete Dienste wie Azure und AWS verwenden weiterhin v2 und ältere Engines.

Google Kubernetes (K8s)

Wenn Sie planen, Kubernetes zum Hosten Orleanszu verwenden, ist ein von der Community verwalteter Clusteringanbieter unter OrleansContrib\Orleans verfügbar. Clustering.Kubernetes. Hier finden Sie Dokumentationen und Beispiele zum nahtlosen Hosting von Orleans in Kubernetes mit dem Anbieter.

Debuggen von Orleans innerhalb von Containern

Da die Ausführung Orleans in einem Container vom Grund auf verstanden wurde, ist es vorteilhaft, eines der wichtigsten Prinzipien von Docker zu nutzen: Unveränderlichkeit. Container sollten (fast) dasselbe Image, die Abhängigkeiten und die Laufzeit in der Entwicklung wie in der Produktion aufweisen. Diese Praxis hilft, das klassische Problem "Es funktioniert auf meinem Computer!" zu verhindern. Um dies zu ermöglichen, ist eine Möglichkeit zum Entwickeln innerhalb des Containers erforderlich, einschließlich des Anfügens eines Debuggers an die anwendung, die darin ausgeführt wird.

Es gibt mehrere Möglichkeiten, dies mithilfe verschiedener Tools zu erreichen. Nach der Auswertung mehrerer Optionen zum Zeitpunkt des Schreibens, wurde eine, die einfacher und weniger aufdringlich für die Anwendung erscheint, ausgewählt.

Wie bereits erwähnt, wird VSCode zum Entwickeln des Beispiels verwendet. Hier erfahren Sie, wie Sie den Debugger an die Orleans Anwendung innerhalb des Containers anfügen:

Ändern Sie zunächst zwei Dateien innerhalb des .vscode Verzeichnisses in der Lösung:

tasks.json:

{
    "version": "0.1.0",
    "command": "dotnet",
    "isShellCommand": true,
    "args": [],
    "tasks": [
        {
            "taskName": "publish",
            "args": [
                "${workspaceRoot}/Orleans-Docker.sln", "-c", "Debug", "-o", "./bin/PublishOutput"
            ],
            "isBuildCommand": true,
            "problemMatcher": "$msCompile"
        }
    ]
}

Diese Datei weist VSCode im Wesentlichen darauf hin, dass jedes Mal, wenn das Projekt erstellt wird, der Befehl publish ausgeführt wird, ähnlich wie zuvor manuell.

launch.json:

{
   "version": "0.2.0",
   "configurations": [
        {
            "name": "Silo",
            "type": "coreclr",
            "request": "launch",
            "cwd": "/app",
            "program": "/app/OrleansSilo.dll",
            "sourceFileMap": {
                "/app": "${workspaceRoot}/src/OrleansSilo"
            },
            "pipeTransport": {
                "debuggerPath": "/vsdbg/vsdbg",
                "pipeProgram": "/bin/bash",
                "pipeCwd": "${workspaceRoot}",
                "pipeArgs": [
                    "-c",
                    "docker exec -i orleansdocker_orleans-silo_1 /vsdbg/vsdbg --interpreter=vscode"
                ]
            }
        },
        {
            "name": "Client",
            "type": "coreclr",
            "request": "launch",
            "cwd": "/app",
            "program": "/app/OrleansClient.dll",
            "sourceFileMap": {
                "/app": "${workspaceRoot}/src/OrleansClient"
            },
            "pipeTransport": {
                "debuggerPath": "/vsdbg/vsdbg",
                "pipeProgram": "/bin/bash",
                "pipeCwd": "${workspaceRoot}",
                "pipeArgs": [
                    "-c",
                    "docker exec -i orleansdocker_orleans-client_1 /vsdbg/vsdbg --interpreter=vscode"
                ]
            }
        }
    ]
}

Erstellen Sie nun die Lösung aus VSCode (die auch veröffentlicht wird) und starten Sie sowohl die Silo- als auch die Clientkonfigurationen. VSCode sendet einen docker exec Befehl an die ausgeführte Dienstinstanz/den ausgeführten docker-compose Container, um den an die Anwendung angefügten Debugger zu starten. Das ist alles! Der Debugger ist an den Container angefügt und kann wie das Debuggen einer lokal ausgeführten Orleans Anwendung verwendet werden. Der hauptunterschied besteht darin, dass die Anwendung innerhalb des Containers ausgeführt wird. Nachdem die Entwicklung abgeschlossen ist, veröffentlichen Sie das Containerimage in der Registrierung, und rufen Sie es in der Produktion auf Docker-Hosts ab.