Wdrażanie platformy Docker

Napiwek

Nawet jeśli znasz platformę Docker i/lub Orleans, jako dowolną inną Orleans dokumentację, zalecamy przeczytanie jej na końcu, aby uniknąć problemów, z którymi już pracowaliśmy.

Ten artykuł i jego przykład są w toku. Wszelkie opinie, żądania ściągnięcia lub sugestie są bardzo mile widziane.

Wdrażanie Orleans rozwiązań na platformie Docker

Orleans Wdrażanie na platformie Docker może być trudne, biorąc pod uwagę sposób projektowania orkiestratorów platformy Docker i stosów klastrowania. Najbardziej skomplikowaną rzeczą jest zrozumienie koncepcji overlay Network z modelu sieci Docker Swarm i Kubernetes.

Kontenery platformy Docker i modele sieciowe zostały zaprojektowane do uruchamiania głównie bezstanowych i niezmiennych kontenerów. Dlatego uruchamianie klastra z systemem node.js lub aplikacji Nginx jest dość proste. Jeśli jednak spróbujesz użyć czegoś bardziej skomplikowanego, takiego jak prawdziwa aplikacja klastrowana lub rozproszona (na przykład Orleansoparta na nich), w końcu będziesz mieć problemy z jego skonfigurowaniem. Jest to możliwe, ale nie tak proste, jak aplikacje internetowe.

Klastrowanie platformy Docker składa się z łączenia wielu hostów w celu pracy jako pojedynczej puli zasobów zarządzanych przy użyciu koordynatora kontenerów. Docker Inc. podaj Swarm jako opcję orkiestracji kontenerów, podczas gdy google ma kubernetes (czyli K8s). Istnieją inne orkiestratory, takie jak DC/OS, Mesos, ale w tym dokumencie omówimy Swarm i K8s, ponieważ są one szerzej używane.

Te same interfejsy ziarna i implementacja, które działają w dowolnym miejscu Orleans , są już obsługiwane, będą również działać w kontenerach platformy Docker. Aby można było uruchamiać aplikację w kontenerach platformy Docker, nie trzeba stosować żadnych specjalnych zagadnień.

Omówione tutaj koncepcje Orleans mogą być używane zarówno w wersjach .NET Core, jak i .NET 4.6.1, ale aby zilustrować międzyplatformowy charakter platformy Docker i platformy .NET Core, skupimy się na przykładzie, biorąc pod uwagę, że używasz platformy .NET Core. Szczegółowe informacje dotyczące platformy (Windows/Linux/OSX) można znaleźć w tym artykule.

Wymagania wstępne

W tym artykule założono, że masz zainstalowane następujące wymagania wstępne:

  • Docker — Docker4X ma łatwy w użyciu instalator dla głównych obsługiwanych platform. Zawiera on aparat platformy Docker, a także docker Swarm.
  • Kubernetes (K8s) — oferta Google dla orkiestracji kontenerów. Zawiera wskazówki dotyczące instalowania narzędzia Minikube (lokalnego wdrożenia K8s) i narzędzia kubectl wraz ze wszystkimi jego zależnościami.
  • .NET — międzyplatformowa wersja platformy .NET
  • Visual Studio Code (VSCode) — możesz użyć dowolnego środowiska IDE. Program VSCode jest międzyplatformowy, dlatego używamy go do zapewnienia, że działa na wszystkich platformach. Po zainstalowaniu programu VSCode zainstaluj rozszerzenie języka C#.

Ważne

Jeśli nie zamierzasz go używać, nie musisz mieć zainstalowanego rozwiązania Kubernetes. Instalator Platformy Docker4X zawiera już narzędzie Swarm, więc do korzystania z niego nie jest wymagana żadna dodatkowa instalacja.

Uwaga

W systemie Windows instalator platformy Docker włączy funkcję Hyper-V podczas procesu instalacji. Ponieważ ten artykuł i jego przykłady korzystają z platformy .NET Core, używane obrazy kontenerów są oparte na systemie Windows Server NanoServer. Jeśli nie planujesz korzystać z platformy .NET Core i będzie przeznaczony dla platformy .NET 4.6.1 pełnej platformy, używany obraz powinien zawierać system Windows Server Core i wersję 1.4 lub nowszą (która obsługuje tylko pełną strukturę Orleans platformy .NET).

Tworzenie rozwiązania Orleans

Poniższe instrukcje pokazują, jak utworzyć regularne Orleans rozwiązanie przy użyciu nowego dotnet narzędzia.

Dostosuj polecenia do dowolnego odpowiedniego elementu na platformie. Ponadto struktura katalogów jest tylko sugestią. Dostosuj go do swoich potrzeb.

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

To, co zrobiliśmy do tej pory, to tylko standardowy kod umożliwiający utworzenie struktury rozwiązania i projektów oraz dodanie odwołań między projektami. Nic innego niż zwykły Orleans projekt.

Do czasu pisania tego artykułu 2.0 (która jest jedyną wersją, która obsługuje platformę .NET Core i międzyplatformową) jest w wersji zapoznawczej technologii, Orleans więc jego pakiety NuGet są hostowane w kanale informacyjnym MyGet i nie są publikowane w celu Nuget.org oficjalnego kanału informacyjnego. Aby zainstalować pakiety NuGet w wersji zapoznawczej, użyjemy dotnet interfejsu wiersza polecenia wymuszające źródło danych i wersję z narzędzia MyGet:

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

Ok, teraz masz wszystkie podstawowe zależności, aby uruchomić prostą Orleans aplikację. Należy pamiętać, że do tej pory nic się nie zmieniło z zwykłej Orleans aplikacji. Teraz dodajmy kod, abyśmy mogli z nim coś zrobić.

Implementowanie Orleans aplikacji

Przy założeniu, że używasz programu VSCode z katalogu rozwiązania, uruchom polecenie code .. Spowoduje to otwarcie katalogu w programie VSCode i załadowanie rozwiązania.

Jest to właśnie utworzona wcześniej struktura rozwiązania.

Visual Studio Code: Explorer with Program.cs selected.

Dodaliśmy również pliki Program.cs, OrleansHostWrapper.cs, IGreetingGrain.cs i GreetingGrain.cs do interfejsów i projektów ziarna, a oto kod dla tych plików:

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 (Silos):

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 (klient):

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

W tym miejscu nie będziemy szczegółowo mówić o implementacji ziarna, ponieważ wykracza poza zakres tego artykułu. Sprawdź inne dokumenty związane z nim. Te pliki są zasadniczo minimalną Orleans aplikacją i zaczniemy od niej, aby przejść do przodu z resztą tego artykułu.

W tym artykule używamy OrleansAzureUtils dostawcy członkostwa, ale możesz użyć innych już obsługiwanych przez Orleansprogram .

Plik Dockerfile

Aby utworzyć kontener, platforma Docker używa obrazów. Aby uzyskać więcej informacji na temat tworzenia własnych, możesz zapoznać się z dokumentacją platformy Docker. W tym artykule użyjemy oficjalnych obrazów firmy Microsoft. Na podstawie platform docelowych i programistycznych należy wybrać odpowiedni obraz. W tym artykule używamy microsoft/dotnet:1.1.2-sdk obrazu opartego na systemie Linux. Można na przykład użyć microsoft/dotnet:1.1.2-sdk-nanoserver dla systemu Windows. Wybierz ten, który odpowiada Twoim potrzebom.

Uwaga dla użytkowników systemu Windows: Jak wspomniano wcześniej, w wielu platformach używamy platformy .NET Core i Orleans Technical Preview 2.0 w tym artykule. Jeśli chcesz używać platformy Docker w systemie Windows z w pełni wydaną Orleans wersją 1.4 lub nowszą, musisz użyć obrazów opartych na systemie Windows Server Core, ponieważ obrazy oparte na systemie NanoServer i Linux obsługują tylko platformę .NET Core.

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"]

Ten plik Dockerfile zasadniczo pobiera i instaluje debuger VSdbg i uruchamia pusty kontener, zachowując go na zawsze, aby nie trzeba było usuwać/wyłączać podczas debugowania.

Teraz w przypadku środowiska produkcyjnego obraz jest mniejszy, ponieważ zawiera tylko środowisko uruchomieniowe platformy .NET Core, a nie cały zestaw SDK, a plik dockerfile jest nieco prostszy:

Plik Dockerfile:

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

Plik docker-compose

Plik docker-compose.yml zasadniczo definiuje (w projekcie) zestaw usług i jego zależności na poziomie usługi. Każda usługa zawiera co najmniej jedno wystąpienie danego kontenera, które jest oparte na obrazach wybranych w pliku Dockerfile. Więcej szczegółów na ten docker-compose temat można znaleźć w dokumentacji narzędzia docker-compose.

W przypadku wdrożenia typowym przypadkiem Orleans użycia jest posiadanie elementu zawierającego docker-compose.yml dwie usługi. Jeden dla Orleans silosu, a drugi dla Orleans klienta. Klient będzie mieć zależność od silosu i oznacza to, że zostanie uruchomiony dopiero po uruchomieniu usługi Silo. Innym przypadkiem jest dodanie usługi magazynu/bazy danych/kontenera, na przykład programu SQL Server, który powinien zostać uruchomiony przed klientem i silosem, więc obie usługi powinny mieć na nim zależność.

Uwaga

Przed kontynuowaniem należy pamiętać, że wcięciema znaczenie w docker-compose plikach. Dlatego zwróć uwagę na to, jeśli masz jakiekolwiek problemy.

Poniżej przedstawiono sposób opisywania naszych usług dla tego artykułu:

docker-compose.override.yml (debugowanie):

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 (produkcja):

version: '3.1'

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

W środowisku produkcyjnym nie mapujemy katalogu lokalnego ani nie mamy build: akcji. Przyczyną jest to, że w środowisku produkcyjnym obrazy powinny być kompilowane i wypychane do własnego rejestru platformy Docker.

Ułóż wszystko razem

Teraz mamy wszystkie przenoszone części wymagane do uruchomienia aplikacji Orleans , więc możemy uruchomić nasze Orleans rozwiązanie wewnątrz platformy Docker (Wreszcie!).

Ważne

Następujące polecenia należy wykonać z katalogu rozwiązania.

Najpierw upewnijmy się, że przywracamy wszystkie pakiety NuGet z naszego rozwiązania. Wystarczy to zrobić tylko raz. Należy to zrobić tylko wtedy, gdy zmienisz dowolną zależność pakietu od projektu.

dotnet restore

Teraz skompilujmy nasze rozwiązanie przy użyciu dotnet interfejsu wiersza polecenia w zwykły sposób i opublikujemy je w katalogu wyjściowym:

dotnet publish -o ./bin/PublishOutput

Napiwek

Używamy publish tutaj zamiast kompilacji, aby uniknąć problemów z naszymi zestawami ładowanymi dynamicznie w systemie Orleans. Nadal szukamy lepszego rozwiązania.

Po utworzeniu i opublikowaniu aplikacji należy skompilować obrazy dockerfile. Ten krok jest wymagany tylko raz na projekt i powinien być wykonywany ponownie tylko wtedy, gdy zmienisz plik Dockerfile, docker-compose lub z jakiegokolwiek powodu wyczyścisz lokalny rejestr obrazów.

docker-compose build

Wszystkie obrazy używane zarówno w Dockerfile systemie , jak i docker-compose.yml są pobierane z rejestru i buforowane na maszynie dewelopera. Obrazy są kompilowane i wszystko jest gotowe do uruchomienia.

Teraz uruchommy go!

# 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
#

Teraz po uruchomieniu elementu docker-compose pszobaczysz 2 kontenery uruchomione dla orleansdocker projektu:

# 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

Uwaga

Jeśli korzystasz z systemu Windows, a kontener używa obrazu systemu Windows jako podstawy, w kolumnie Command (Polecenie) zostanie wyświetlone polecenie względne programu PowerShell do tail elementu w systemach *NIX, aby kontener zachował ten sam sposób.

Teraz, gdy masz już kontenery, nie musisz go zatrzymywać za każdym razem, gdy chcesz uruchomić aplikację Orleans . Wystarczy zintegrować środowisko IDE w celu debugowania aplikacji wewnątrz kontenera, który został wcześniej zamapowany w pliku docker-compose.yml.

Skalowanie

Po uruchomieniu projektu redagowania można łatwo skalować aplikację w górę lub w dół przy użyciu docker-compose scale polecenia :

# 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

Po kilku sekundach zobaczysz usługi skalowane do określonej liczby żądanych wystąpień.

# 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

Ważne

Kolumna Command na tych przykładach pokazuje tail polecenie tylko dlatego, że używamy kontenera debugera. Gdybyśmy byli w środowisku produkcyjnym, byłoby to pokazane dotnet OrleansSilo.dll na przykład.

Docker swarm

Stos klastrowania platformy Docker nosi nazwę Swarm, aby uzyskać więcej informacji, zobacz Docker Swarm.

Aby uruchomić ten artykuł w klastrze, nie masz żadnej dodatkowej Swarm pracy. Po uruchomieniu docker-compose up -d w węźle Swarm będzie on planować kontenery na podstawie skonfigurowanych reguł. Dotyczy to również innych usług opartych na rozwiązaniu Swarm, takich jak Docker Datacenter, Azure ACS (w trybie Swarm) i AWS ECS Container Service. Wystarczy wdrożyć Swarm klaster przed wdrożeniem aplikacji dockerizedOrleans .

Uwaga

Jeśli używasz aparatu platformy Docker z trybem Swarm, który ma już obsługę stacksystemu , deployi compose w wersji 3, lepszym podejściem do wdrożenia rozwiązania będzie docker stack deploy -c docker-compose.yml <name>. Pamiętaj tylko, że wymaga pliku redagowania w wersji 3, aby obsługiwać aparat platformy Docker, a większość hostowanych usług, takich jak Azure i AWS, nadal używa wersji 2 i starszych aparatów.

Google Kubernetes (K8s)

Jeśli planujesz hostowanie przy użyciu platformy Kubernetes, dostępny jest dostawca klastrowania obsługiwany przez społeczność pod adresem OrleansContrib\Orleans.Orleans Clustering.Kubernetes i tam można znaleźć dokumentację i przykłady dotyczące bezproblemowego hostowania Orleans na platformie Kubernetes przy użyciu dostawcy.

Debugowanie Orleans wewnątrz kontenerów

Cóż, teraz, gdy wiesz, jak uruchomić Orleans w kontenerze od podstaw, warto wykorzystać jedną z najważniejszych zasad platformy Docker. Kontenery są niezmienne. Powinny one mieć (prawie) ten sam obraz, zależności i środowisko uruchomieniowe w środowisku deweloperskim, co w środowisku produkcyjnym. Dzięki temu dobre stare stwierdzenie "Działa na mojej maszynie!" nigdy nie dzieje się ponownie. Aby to możliwe, musisz mieć możliwość opracowywania wewnątrz kontenera i zawiera debuger dołączony do aplikacji wewnątrz kontenera.

Istnieje wiele sposobów, aby to osiągnąć przy użyciu wielu narzędzi. Po ocenie kilku, do czasu napisałem ten artykuł, skończyło się na wybraniu jednego, który wygląda bardziej prosty i jest mniej uciążliwy w aplikacji.

Jak wspomniano wcześniej w tym artykule, używamy VSCode go do tworzenia przykładu, więc oto jak uzyskać debuger dołączony do aplikacji Orleans wewnątrz kontenera.

Najpierw zmień dwa pliki wewnątrz .vscode katalogu w rozwiązaniu:

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"
        }
    ]
}

Ten plik zasadniczo informuje VSCode o tym, że za każdym razem, gdy kompilujesz projekt, polecenie zostanie wykonane publish tak, jak zrobiliśmy to ręcznie wcześniej.

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"
                ]
            }
        }
    ]
}

Teraz możesz po prostu skompilować rozwiązanie ( VSCode które zostanie opublikowane) i uruchomić zarówno silos, jak i klienta. Spowoduje to wysłanie docker exec polecenia do uruchomionego docker-compose wystąpienia usługi/kontenera, aby uruchomić debuger do aplikacji i to jest. Masz debuger dołączony do kontenera i użyj go tak, jakby był to lokalnie uruchomiona Orleans aplikacja. Różnica polega teraz na tym, że znajduje się wewnątrz kontenera, a po zakończeniu możesz po prostu opublikować kontener w rejestrze i ściągnąć go na hostach platformy Docker w środowisku produkcyjnym.