Implantação do Docker
Gorjeta
Mesmo que você esteja familiarizado com o Docker ou Orleanso , é recomendável ler este artigo até o final para evitar problemas que possam ser enfrentados com soluções alternativas.
Este artigo e seu exemplo são um trabalho em andamento. Qualquer feedback, RP ou sugestão é bem-vindo.
Implantar Orleans soluções no Docker
A implantação Orleans no Docker pode ser complicada, dada a maneira como os orquestradores do Docker e as pilhas de clustering foram projetados. O mais complicado é entender o conceito de Overlay Network do modelo de rede Docker Swarm e Kubernetes.
Os contêineres e modelos de rede do Docker foram projetados para executar principalmente contêineres sem estado e imutáveis. Assim, girar um cluster executando aplicativos node.js ou Nginx é muito fácil. No entanto, se você tentar usar algo mais elaborado, como um aplicativo real clusterizado ou distribuído (como Orleansos baseados em -based), você acabará tendo problemas para configurá-lo. É possível, mas não tão simples como as aplicações baseadas na Web.
O cluster do Docker consiste em reunir vários hosts para trabalhar como um único pool de recursos, gerenciado usando um Orquestrador de Contêineres. Docker Inc. fornecem o Swarm como opção para orquestração de contêineres, enquanto o Google tem o Kubernetes (também conhecido como K8s). Existem outros Orchestrators como DC/OS, Mesos, mas neste documento, vamos falar sobre Swarm e K8s como eles são mais amplamente utilizados.
As mesmas interfaces de grão e implementação que são executadas em qualquer lugar Orleans já são suportadas também serão executadas em contêineres do Docker. Nenhuma consideração especial é necessária para poder executar seu aplicativo em contêineres do Docker.
Os conceitos discutidos aqui podem ser usados nos sabores .NET Core e .NET 4.6.1, mas Orleans para ilustrar a natureza multiplataforma do Docker e do .NET Core, vamos nos concentrar no exemplo, considerando que você está usando o .NET Core. Detalhes específicos da plataforma (Windows/Linux/OSX) podem ser fornecidos neste artigo.
Pré-requisitos
Este artigo pressupõe que você tenha os seguintes pré-requisitos instalados:
- Docker - O Docker4X tem um instalador fácil de usar para as principais plataformas suportadas. Ele contém o mecanismo Docker e também o Docker Swarm.
- Kubernetes (K8s) - Oferta do Google para orquestração de contêineres. Ele contém orientação para instalar Minikube (uma implantação local de K8s) e kubectl juntamente com todas as suas dependências.
- .NET - Sabor multiplataforma do .NET
- Visual Studio Code (VSCode) - Você pode usar o IDE que quiser. O VSCode é multiplataforma, por isso estamos a usá-lo para garantir que funciona em todas as plataformas. Depois de instalar o VSCode, instale a extensão C#.
Importante
Você não é obrigado a ter o Kubernetes instalado se você não vai usá-lo. O instalador do Docker4X já inclui o Swarm, portanto, nenhuma instalação extra é necessária para usá-lo.
Nota
No Windows, o instalador do Docker habilitará o Hyper-V no processo de instalação. Como este artigo e seus exemplos estão usando o .NET Core, as imagens de contêiner usadas são baseadas no Windows Server NanoServer. Se você não planeja usar o .NET Core e terá como destino o .NET 4.6.1 full framework, a imagem usada deve ser o Windows Server Core e a versão 1.4+ do Orleans (que suporta apenas o .NET full framework).
Criar solução Orleans
As instruções a seguir mostram como criar uma solução regular Orleans usando as novas dotnet
ferramentas.
Por favor, adapte os comandos ao que for apropriado na sua plataforma. Além disso, a estrutura de diretórios é apenas uma sugestão. Por favor, adapte-o às suas necessidades.
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
O que fizemos até agora foi apenas um código clichê para criar a estrutura da solução e os projetos, e adicionar referências entre os projetos. Nada diferente de um projeto regular Orleans .
No momento em que este artigo foi escrito, a versão 2.0 (que é a única versão que suporta .NET Core e multiplataforma) está no Technology Preview, portanto, Orleans seus pacotes NuGet são hospedados em um feed MyGet e não publicados em Nuget.org feed oficial. Para instalar os pacotes NuGet de visualização, usaremos dotnet
a CLI forçando o feed de origem e a versão do 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, agora você tem todas as dependências básicas para executar um aplicativo simples Orleans . Note que, até agora, nada mudou em relação à sua aplicação normal Orleans . Agora, vamos adicionar algum código para que possamos fazer algo com ele.
Implemente seu Orleans aplicativo
Supondo que você esteja usando o VSCode, no diretório da solução, execute code .
. Isso abrirá o diretório no VSCode e carregará a solução.
Esta é a estrutura de solução que acabamos de criar anteriormente.
Também adicionamos arquivos Program.cs, OrleansHostWrapper.cs, IGreetingGrain.cs e GreetingGrain.cs às interfaces e projetos grain, respectivamente, e aqui está o código para esses arquivos:
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 (cliente):
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);
}
}
}
}
Não vamos entrar em detalhes sobre a implementação do grão aqui, uma vez que está fora do escopo deste artigo. Por favor, verifique outros documentos relacionados a ele. Esses arquivos são essencialmente um aplicativo mínimo Orleans e vamos começar a partir dele para avançar com o restante deste artigo.
Neste artigo, estamos usando OrleansAzureUtils
o provedor de associação, mas você pode usar qualquer outro já suportado pelo Orleans.
O Dockerfile
Para criar seu contêiner, o Docker usa imagens. Para obter mais detalhes sobre como criar o seu próprio, consulte a documentação do Docker. Neste artigo, vamos usar imagens oficiais da Microsoft. Com base nas plataformas de destino e desenvolvimento, você precisa escolher a imagem apropriada. Neste artigo, estamos usando microsoft/dotnet:1.1.2-sdk
uma imagem baseada em Linux. Você pode usar microsoft/dotnet:1.1.2-sdk-nanoserver
para Windows, por exemplo. Escolha um que se adapte às suas necessidades.
Nota para usuários do Windows: Como mencionado anteriormente, para ser multiplataforma, estamos usando o .NET Core e Orleans o Technical preview 2.0 neste artigo. Se você quiser usar o Docker no Windows com o 1.4+ totalmente lançado Orleans , você precisa usar as imagens que são baseadas no Windows Server Core, uma vez que as imagens baseadas em NanoServer e Linux, suportam apenas o .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"]
Este Dockerfile essencialmente baixa e instala o depurador VSdbg e inicia um contêiner vazio, mantendo-o vivo para sempre para que não precisemos destruir/desativar durante a depuração.
Agora, para produção, a imagem é menor, pois contém apenas o tempo de execução do .NET Core e não todo o SDK, e o dockerfile é um pouco mais simples:
Dockerfile:
FROM microsoft/dotnet:1.1.2-runtime
WORKDIR /app
ENTRYPOINT ["dotnet", "OrleansSilo.dll"]
COPY . /app
O arquivo docker-compose
O docker-compose.yml
arquivo, essencialmente define (dentro de um projeto) um conjunto de serviços e suas dependências no nível de serviço. Cada serviço contém uma ou mais instâncias de um determinado contêiner, que se baseia nas imagens selecionadas no Dockerfile. Mais detalhes sobre o docker-compose
docker-compose podem ser encontrados na documentação docker-compos.
Para uma Orleans implantação, um caso de uso comum é ter um docker-compose.yml
que contém dois serviços. Um para Orleans Silo, e outro para Orleans Cliente. O Cliente teria uma dependência do Silo e isso significa que ele só começará depois que o serviço do Silo terminar. Outro caso é adicionar um serviço/contêiner de armazenamento/banco de dados, como, por exemplo, o SQL Server, que deve começar primeiro antes do cliente e do silo, para que ambos os serviços dependam dele.
Nota
Antes de continuar a ler, tenha em atenção que o recuo é importante nos docker-compose
ficheiros. Portanto, preste atenção se tiver algum problema.
Aqui está como descreveremos nossos serviços para este artigo:
docker-compose.override.yml (Depurar):
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 (produção):
version: '3.1'
services:
orleans-client:
image: orleans-client
depends_on:
- orleans-silo
orleans-silo:
image: orleans-silo
Na produção, não mapeamos o diretório local, nem temos a build:
ação. A razão é que, na produção, as imagens devem ser construídas e enviadas para o seu próprio Docker Registry.
Junte tudo
Agora temos todas as partes móveis necessárias para executar seu Orleans aplicativo, vamos montá-lo para que possamos executar nossa Orleans solução dentro do Docker (Finalmente!).
Importante
Os comandos a seguir devem ser executados a partir do diretório da solução.
Primeiro, vamos nos certificar de que restauramos todos os pacotes NuGet de nossa solução. Você só precisa fazê-lo uma vez. Você só será obrigado a fazê-lo novamente se alterar qualquer dependência de pacote em seu projeto.
dotnet restore
Agora, vamos criar nossa solução usando dotnet
CLI como de costume e publicá-la em um diretório de saída:
dotnet publish -o ./bin/PublishOutput
Gorjeta
Estamos usando publish
aqui em vez de build, para evitar problemas com nossos assemblies carregados dinamicamente no Orleans. Ainda estamos à procura de uma solução melhor para isso.
Com o aplicativo criado e publicado, você precisa criar suas imagens do Dockerfile. Esta etapa só precisa ser executada uma vez por projeto e só deve ser executada novamente se você alterar o Dockerfile, docker-compose, ou por qualquer motivo você limpou seu registro de imagem local.
docker-compose build
Todas as imagens usadas em ambos Dockerfile
e docker-compose.yml
são extraídas do registro e armazenadas em cache em sua máquina de desenvolvimento. Suas imagens são construídas e você está pronto para ser executado.
Agora, vamos executá-lo!
# 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
#
Agora, se você executar um docker-compose ps
, verá 2 contêineres em execução para o orleansdocker
projeto:
# 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 você estiver no Windows e seu contêiner estiver usando uma imagem do Windows como base, a coluna Comando mostrará o comando relativo do PowerShell para um tail
em sistemas *NIX para que o contêiner se mantenha da mesma maneira.
Agora que você tem seus contêineres, não precisa pará-los toda vez que quiser iniciar seu Orleans aplicativo. Tudo o que você precisa é integrar seu IDE para depurar o aplicativo dentro do contêiner que foi previamente mapeado em seu docker-compose.yml
.
Dimensionamento
Depois de ter seu projeto de composição em execução, você pode facilmente escalar seu aplicativo usando docker-compose scale
o 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
Após alguns segundos, você verá os serviços dimensionados para o número específico de instâncias solicitadas.
# 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
A Command
coluna nesses exemplos está mostrando o tail
comando apenas porque estamos usando o contêiner do depurador. Se estivéssemos em produção, estaria mostrando dotnet OrleansSilo.dll
, por exemplo.
Enxame de Docker
A pilha de clusters do Docker é chamada de Swarm, para obter mais informações, consulte Docker Swarm.
Para executar este artigo em um Swarm
cluster, você não tem nenhum trabalho extra. Quando você executa docker-compose up -d
em um Swarm
nó, ele agendará contêineres com base nas regras configuradas. O mesmo se aplica a outros serviços baseados no Swarm, como o Azure ACS (no modo Swarm) e o AWS ECS Container Service. Tudo o que você precisa fazer é implantar seu Swarm
cluster antes de implantar seu aplicativo dockerizadoOrleans .
Nota
Se você estiver usando um mecanismo Docker com o modo Swarm que já tenha suporte para stack
, deploy
e compose
v3, uma abordagem melhor para implantar sua solução é docker stack deploy -c docker-compose.yml <name>
. Lembre-se de que ele requer o arquivo de composição v3 para dar suporte ao mecanismo Docker, e a maioria dos serviços hospedados, como o Azure e a AWS, ainda usa mecanismos v2 e mais antigos.
Google Kubernetes (K8s)
Se você planeja usar o Kubernetes para hospedar Orleans, há um provedor de clustering mantido pela comunidade disponível em OrleansContrib\Orleans. Clustering.Kubernetes. Lá você pode encontrar documentação e exemplos sobre como hospedar Orleans no Kubernetes perfeitamente usando o provedor.
Depurar Orleans dentro de contêineres
Agora que você sabe como executar Orleans em um contêiner do zero, é bom aproveitar um dos princípios mais importantes do Docker. Os contentores são imutáveis. E eles devem ter (quase) a mesma imagem, dependências e tempo de execução no desenvolvimento como na produção. Isso garante a boa e velha frase "Funciona na minha máquina!" nunca mais acontece. Para tornar isso possível, você precisa ter uma maneira de desenvolver dentro do contêiner e isso inclui ter um depurador anexado ao seu aplicativo dentro do contêiner.
Há várias maneiras de conseguir isso usando várias ferramentas. Depois de avaliar vários, no momento em que escrevi este artigo, acabei por escolher um que pareça mais simples e seja menos intrusivo na aplicação.
Como mencionado anteriormente neste artigo, estamos usando VSCode
para desenvolver o exemplo, então aqui está como obter o depurador anexado ao seu Orleans aplicativo dentro do contêiner.
Primeiro, altere dois arquivos dentro do seu .vscode
diretório na sua solução:
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"
}
]
}
Este arquivo essencialmente diz VSCode
que sempre que você construir o projeto, ele executará o publish
comando como fizemos manualmente anteriormente.
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"
]
}
}
]
}
Agora você pode apenas construir a solução a partir de VSCode
(que irá publicar) e iniciar o Silo e o Cliente. Ele enviará um docker exec
comando para a instância/contêiner de serviço em execução docker-compose
para iniciar o depurador para o aplicativo e pronto. Você tem o depurador anexado ao contêiner e o usa como se fosse um aplicativo em execução Orleans local. A diferença agora é que ele está dentro do contêiner e, uma vez concluído, você pode simplesmente publicar o contêiner em seu registro e puxá-lo em seus hosts do Docker em produção.