Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Suggerimento
Anche se si ha familiarità con Docker o Orleans, è consigliabile leggere questo articolo alla fine per evitare potenziali problemi con soluzioni alternative note.
Questo articolo e il relativo esempio sono ancora un work in progress. Commenti, pull request o suggerimenti sono benvenuti.
Distribuire soluzioni Orleans in Docker
La distribuzione Orleans in Docker può essere complessa a causa della progettazione di agenti di orchestrazione Docker e stack di clustering. La parte più complessa consiste nel comprendere il concetto di rete sovrapposta da Docker Swarm e il modello di rete Kubernetes.
I contenitori Docker e i modelli di rete sono stati progettati principalmente per l'esecuzione di contenitori senza stato e non modificabili. Avviare un cluster che esegue applicazioni Node.js o Nginx è piuttosto semplice. Tuttavia, l'uso di un'applicazione più elaborata, ad esempio un'applicazione realmente cluster o distribuita (ad esempio una basata su Orleans), potrebbe presentare difficoltà di configurazione. È possibile, ma non altrettanto semplice come la distribuzione di applicazioni basate sul Web.
Il clustering Docker prevede il raggruppamento di più host per funzionare come un singolo pool di risorse, gestito tramite un Agente di orchestrazione contenitori. Docker Inc. fornisce Swarm come opzione, mentre Google offre Kubernetes (noto anche come K8s). Esistono altri agenti di orchestrazione come DC/OS e Mesos , ma questo documento è incentrato su Swarm e K8s perché sono più ampiamente usati.
Le stesse interfacce e implementazioni a grana che vengono eseguite ovunque Orleans siano supportate funzionano anche nei container Docker. Non sono necessarie considerazioni speciali per eseguire un'applicazione Orleans nei contenitori Docker.
I concetti illustrati di seguito si applicano sia alle versioni di .NET Core che a .NET Framework 4.6.1 di Orleans. Tuttavia, per illustrare la natura multipiattaforma di Docker e .NET Core, ci si concentra sugli esempi che utilizzano .NET Core. I dettagli specifici della piattaforma (Windows/Linux/macOS) potrebbero essere forniti se necessario.
Prerequisiti
Questo articolo presuppone che siano installati i prerequisiti seguenti:
- Docker: Docker4X include un programma di installazione facile da usare per le principali piattaforme supportate. Contiene il motore Docker e Docker Swarm.
- Kubernetes (K8s): offerta di orchestrazione dei contenitori di Google. Include indicazioni per l'installazione di Minikube (una distribuzione K8s locale) e kubectl insieme alle dipendenze.
- .NET: versione multipiattaforma di .NET.
- Visual Studio Code (VSCode): è possibile usare qualsiasi IDE preferito. VsCode viene usato qui perché è multipiattaforma, assicurando che gli esempi funzionino su tutte le piattaforme. Dopo aver installato VSCode, installare l'estensione C#.
Importante
L'installazione di Kubernetes non è necessaria se non viene usata. Il programma di installazione Docker4X include già Swarm, quindi non è necessaria alcuna installazione aggiuntiva per Swarm.
Nota
In Windows il programma di installazione di Docker abilita Hyper-V durante l'installazione. Poiché questo articolo e i relativi esempi usano .NET Core, le immagini del contenitore usate sono basate su Windows Server NanoServer. Se si prevede di usare invece .NET Framework 4.6.1, usare le immagini basate su Windows Server Core e Orleans versione 1.4+ (che supporta solo .NET Framework).
Creare una Orleans soluzione
Le istruzioni seguenti illustrano come creare una soluzione standard Orleans usando gli dotnet strumenti.
Adattare i comandi in base alle esigenze della piattaforma. La struttura di directory è solo un suggerimento; adattarlo in base alle esigenze.
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
Finora è stato creato solo il codice boilerplate per la struttura della soluzione e i progetti e i riferimenti aggiunti tra di essi. Questo non è diverso dalla configurazione di un progetto normale Orleans .
Al momento della scrittura di questo articolo, Orleans la versione 2.0 (che supporta lo sviluppo di .NET Core e multipiattaforma) era disponibile in Technology Preview. I pacchetti NuGet sono stati ospitati in un feed MyGet, non nel feed NuGet.org ufficiale. Per installare i pacchetti NuGet di anteprima, usare la CLI dotnet, forzando il feed di origine e la versione da 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, tutte le dipendenze di base per eseguire una semplice Orleans applicazione sono ora disponibili. Si noti che nulla è cambiato da una configurazione regolare Orleans dell'applicazione fino a questo punto. A questo punto, aggiungiamo del codice per renderlo funzionale.
Implementare l'applicazione Orleans
Supponendo che venga usato VSCode , eseguire code . dalla directory della soluzione. Questo comando apre la directory in VSCode e carica la soluzione.
Si tratta della struttura della soluzione creata in precedenza.
Program.cs, OrleansHostWrapper.cs, IGreetingGrain.cs e GreetingGrain.cs file sono stati aggiunti rispettivamente alle interfacce e ai progetti granulari. Ecco il codice per questi file:
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);
}
}
}
}
I dettagli dell'implementazione granulare non sono trattati qui, perché non rientrano nell'ambito di questo articolo. Per altre informazioni, vedere altri documenti pertinenti. Questi file rappresentano un'applicazione minima Orleans , che funge da punto di partenza per il resto di questo articolo.
Questo articolo usa il OrleansAzureUtils provider di appartenenze, ma è possibile usare qualsiasi altro Orleansprovider supportato.
Dockerfile
Docker usa immagini per creare contenitori. Per altre informazioni sulla creazione di immagini personalizzate, vedere la documentazione di Docker. Questo articolo usa immagini Microsoft ufficiali. In base alle piattaforme di destinazione e sviluppo, selezionare l'immagine appropriata.
microsoft/dotnet:1.1.2-sdk, un'immagine basata su Linux, viene usata qui. Per Windows, ad esempio, microsoft/dotnet:1.1.2-sdk-nanoserver può essere usato. Scegliere quello più adatto alle esigenze.
Nota per gli utenti di Windows: come accennato in precedenza, per mantenere la compatibilità multipiattaforma, in questo articolo vengono usati .NET Core e Orleans Technical Preview 2.0. Per usare Docker in Windows con la versione completamente rilasciata Orleans 1.4+, usare le immagini basate su Windows Server Core, poiché le immagini basate su NanoServer e Linux supportano solo .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"]
Questo Dockerfile scarica e installa essenzialmente il debugger VSdbg e avvia un contenitore vuoto, mantenendolo attivo per un tempo indefinito, quindi non è necessario rimuovere e visualizzare ripetutamente durante il debug.
Ora, per la produzione, l'immagine è più piccola perché contiene solo il runtime .NET Core, non l'intero SDK. Il Dockerfile è anche più semplice:
Dockerfile:
FROM microsoft/dotnet:1.1.2-runtime
WORKDIR /app
ENTRYPOINT ["dotnet", "OrleansSilo.dll"]
COPY . /app
File docker-compose
Il docker-compose.yml file definisce un set di servizi e le relative dipendenze all'interno di un progetto a livello di servizio. Ogni servizio contiene una o più istanze di un determinato contenitore, in base alle immagini selezionate nel Dockerfile. Per ulteriori dettagli su docker-compose, consultare la documentazione di docker-compose.
Per una Orleans distribuzione, un caso d'uso comune prevede un docker-compose.yml file contenente due servizi: uno per il Orleans Silo e un altro per il Orleans client. Il servizio client dipende dal servizio Silo, ovvero viene avviato solo dopo l'esecuzione del servizio Silo. Un altro scenario potrebbe comportare l'aggiunta di un servizio di archiviazione o di un contenitore di database (ad esempio SQL Server), che deve essere avviato prima del client e del silo. In questo caso, i servizi client e silo dipendono dal servizio di database.
Nota
Prima di leggere ulteriormente, tenere presente che il rientroè importante nei docker-compose file. Prestare attenzione a esso se si verificano problemi.
Ecco come vengono descritti i servizi per questo articolo:
docker-compose.override.yml (debug):
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 (produzione):
version: '3.1'
services:
orleans-client:
image: orleans-client
depends_on:
- orleans-silo
orleans-silo:
image: orleans-silo
Nell'ambiente di produzione, la directory locale non viene mappata né è inclusa l'azione build: . Il motivo è che in un ambiente di produzione le immagini devono essere costruite e inviate a un Docker Registry privato.
Mettere insieme tutti gli elementi
Ora che tutti i componenti necessari sono pronti, è possibile metterli insieme per eseguire la Orleans soluzione all'interno di Docker.
Importante
I seguenti comandi devono essere eseguiti dalla directory della soluzione.
Assicurarsi prima di tutto che tutti i pacchetti NuGet per la soluzione vengano ripristinati. In genere è necessario eseguire una sola volta, a meno che le dipendenze del pacchetto non cambino.
dotnet restore
Ora, compila la soluzione usando l'interfaccia della riga di comando dotnet come di consueto e pubblicala in una directory di output.
dotnet publish -o ./bin/PublishOutput
Suggerimento
publish viene usato qui anziché build per evitare problemi con assembly caricati dinamicamente in Orleans. Si sta ancora cercando una soluzione migliore.
Con l'applicazione compilata e pubblicata, compilare le immagini Docker usando i Dockerfile. Questo passaggio richiede in genere l'esecuzione una sola volta per ogni progetto. Deve essere necessario di nuovo solo se il dockerfile o il file docker-compose cambia o se il registro delle immagini locali viene pulito per qualsiasi motivo.
docker-compose build
Tutte le immagini di base usate in Dockerfile e docker-compose.yml vengono estratte dal Registro di sistema e memorizzate nella cache nel computer di sviluppo. Le immagini dell'applicazione vengono compilate e tutto è pronto per l'esecuzione.
A questo punto, eseguire l'applicazione.
# 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
#
Ora, l'esecuzione docker-compose ps mostra due contenitori in esecuzione per il orleansdocker progetto:
# 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
Nota
Se in Windows e il contenitore usa un'immagine di base di Windows, la colonna Comando mostra il comando equivalente di PowerShell a tail nei sistemi *NIX, mantenendo il contenitore in esecuzione in modo analogo.
Ora che i contenitori sono in esecuzione, non è necessario interromperli ogni volta che l'applicazione Orleans deve essere avviata. È sufficiente integrare l'IDE per eseguire il debug dell'applicazione all'interno del contenitore, mappato in precedenza in docker-compose.yml.
Scalabilità
Una volta eseguito il progetto di composizione, ridimensionare facilmente l'applicazione verso l'alto o verso il basso usando il docker-compose scale comando :
# 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
Dopo alcuni secondi, i servizi vengono ridimensionati al numero specifico di istanze richieste.
# 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
Importante
La Command colonna in questi esempi mostra il tail comando perché viene usato il contenitore del debugger. Nell'ambiente di produzione, ad esempio, viene visualizzato dotnet OrleansSilo.dll.
Docker Swarm
Lo stack di clustering di Docker è denominato Swarm. Per altre informazioni, vedere Docker Swarm.
Per eseguire l'applicazione descritta in questo articolo in un Swarm cluster, non sono necessarie operazioni aggiuntive. L'esecuzione docker-compose up -d in un Swarm nodo pianifica i contenitori in base alle regole configurate. Lo stesso vale per altri servizi basati su Swarm come il servizio Azure Kubernetes (in modalità Swarm) e AWS Elastic Container Service (ECS). Distribuire il Swarm cluster prima di distribuire l'applicazione dockerizedOrleans .
Nota
Se si usa un motore Docker con la modalità Swarm che supporta stack, deploye compose v3, un approccio migliore per distribuire la soluzione è docker stack deploy -c docker-compose.yml <name>. Tenere presente che è necessario un file compose v3 compatibile con il motore Docker. Molti servizi ospitati come Azure e AWS usano ancora motori v2 e precedenti.
Google Kubernetes (K8s)
Se si prevede di usare Kubernetes per ospitare Orleans, un provider di clustering gestito dalla community è disponibile in OrleansContrib\Orleans. Clustering.Kubernetes. È possibile trovare documentazione ed esempi sull'hosting Orleans in Kubernetes senza problemi usando il provider.
Eseguire il debug Orleans all'interno di contenitori
Ora che l'esecuzione Orleans in un contenitore da zero è comprensibile, è utile sfruttare uno dei principi più importanti di Docker: immutabilità. I contenitori devono avere quasi la stessa immagine, le dipendenze e l'ambiente di esecuzione sia in sviluppo che in produzione. Questa procedura consente di evitare il problema classico "Funziona sul mio computer". Per rendere possibile questo problema, è necessario un modo per sviluppare all'interno del contenitore, incluso il collegamento di un debugger all'applicazione in esecuzione al suo interno.
Esistono diversi modi per ottenere questo risultato usando vari strumenti. Dopo aver valutato diverse opzioni al momento della scrittura, è stato scelto uno che sembra più semplice e meno intrusivo per l'applicazione.
Come accennato in precedenza, VSCode viene usato per sviluppare l'esempio. Ecco come collegare il debugger all'applicazione Orleans all'interno del contenitore:
Prima di tutto, modificare due file all'interno della .vscode directory nella soluzione:
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"
}
]
}
Questo file indica VSCode essenzialmente che ogni volta che il progetto viene compilato, esegue il publish comando, in modo analogo a come è stato eseguito manualmente in precedenza.
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"
]
}
}
]
}
A questo punto, compila la soluzione da VSCode, che pubblica anche, e avvia sia le configurazioni del Silo che del Client. VSCode invia un docker exec comando all'istanza o al contenitore del servizio in esecuzione docker-compose per avviare il debugger collegato all'applicazione. Questo è tutto! Il debugger è collegato al contenitore e può essere usato proprio come il debug di un'applicazione in esecuzione Orleans in locale. La differenza principale è che l'applicazione viene eseguita all'interno del contenitore. Al termine dello sviluppo, pubblicare l'immagine del contenitore nel registro ed eseguirne il pull negli host Docker nell'ambiente di produzione.