共用方式為


Docker 部署

提示

即使熟悉 Docker 或 Orleans,還是建議閱讀本文至結尾,以避免已知因應措施的潛在問題。

本文及其範例是進行中的工作。 歡迎使用意見反應、PR 或建議。

將 Orleans 解決方案部署至 Docker

由於 Docker 協調器和叢集堆疊的設計,部署 Orleans 至 Docker 可能會很棘手。 最複雜的部分是理解 Docker Swarm 中的 疊加網路 概念,以及 Kubernetes 的網路模型。

Docker 容器和網路模型主要是針對執行無狀態和固定容器而設計。 啟動運行 Node.js 或 Nginx 應用程式的叢集是相當容易的。 不過,使用更複雜的方案,例如真正的叢集或分散式應用程式(如基於Orleans的應用程式),可能會面臨設定上的困難。 這是可能的,但不像部署 Web 型應用程式那麼簡單。

Docker 叢集牽涉到將多個主機分組,以作為單一資源集區運作,並使用 容器 Orchestrator 進行管理。 Docker Inc. 提供 Swarm 作為其選項,而 Google 則提供 Kubernetes (也稱為 K8s)。 DC/OSMesos 等其他協調器存在,但本檔著重於 Swarm 和 K8,因為它們使用得更廣。

支援在任何地方 Orleans 執行的相同粒紋介面和實作也會在 Docker 容器上執行。 在 Docker 容器中執行 Orleans 應用程式不需要任何特殊考慮。

這裏討論的概念同時適用於的 .NET Core 和 .NET Framework 4.6.1 版本 Orleans。 不過,為了說明 Docker 和 .NET Core 的跨平台本質,使用 .NET Core 的範例著重於 。 可能需要視需要提供平臺特定詳細數據(Windows/Linux/macOS)。

必要條件

本文假設已安裝下列必要條件:

  • Docker:D ocker4X 具有適用於主要支援平臺的易於使用安裝程式。 其中包含 Docker 引擎和 Docker Swarm。
  • Kubernetes (K8s):Google 的容器協調流程供應專案。 其中包含安裝 Minikube(本地 K8s 部署)和 kubectl 的指引,並涵蓋相依性。
  • .NET:.NET 的跨平台類別。
  • Visual Studio Code (VSCode):可以使用任何慣用的 IDE。 VSCode 在這裡使用,因為它是跨平臺,確保範例在所有平臺上都能運作。 安裝 VSCode 之後,請安裝 C# 擴充功能

重要

如果未使用它,則不需要 Kubernetes 安裝。 Docker4X 安裝程式已經包含 Swarm,因此 Swarm 不需要額外的安裝。

注意

在 Windows 上,Docker 安裝程式會在安裝期間啟用 Hyper-V。 由於本文及其範例使用 .NET Core,因此所使用的容器映像是以 Windows Server NanoServer 為基礎。 如果計劃改用 .NET Framework 4.6.1,請使用以 Windows Server Core 和 Orleans 1.4+ 版為基礎的映射(僅支援 .NET Framework)。

建立 Orleans 解決方案

下列指示示範如何使用 Orleans 工具建立標準 dotnet 解決方案。

視需要針對平台調整命令。 目錄結構只是建議;視需要進行調整。

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

到目前為止,只已經建立了方案結構和專案的樣板代碼,並在它們之間新增參考。 這與設定一般 Orleans 專案並無不同。

本文撰寫時, Orleans 2.0(支援 .NET Core 和跨平台開發)處於技術預覽狀態。 其 NuGet 套件裝載在 MyGet 供應源上,而不是官方 NuGet.org 供應源。 為了安裝預覽版 NuGet 套件,請使用 dotnet CLI 並指定 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

好吧,執行簡單 Orleans 應用程式的所有基本相依性現在都已就緒。 請注意,從一般 Orleans 應用程式設定到此時沒有任何變更。 現在,讓我們新增一些程序代碼,使其運作正常。

實作 Orleans 應用程式

假設使用 VSCode ,請從方案目錄執行 code . 。 此命令會在 VSCode 中開啟目錄,並載入解決方案。

這是先前建立的解決方案結構。

Visual Studio Code:已選取 Program.cs 的 Explorer。

Program.csOrleansHostWrapper.csIGreetingGrain.csGreetingGrain.cs 檔案也分別新增至介面和粒紋專案。 以下是這些檔案的程式代碼:

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 (定址接收器):

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 (用戶端):

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

此處未涵蓋粒紋實作詳細數據,因為它不在本文的討論範圍內。 如需詳細資訊,請參閱其他相關文件。 這些檔案代表最少 Orleans 的應用程式,可作為本文其餘部分的起點。

本文使用 OrleansAzureUtils 會員提供者,但可以使用任何其他 Orleans 支援的提供者。

Dockerfile

Docker 會使用映像來建立容器。 如需建立自定義映像的詳細資訊,請參閱 Docker 檔。 本文使用官方 Microsoft影像。 根據目標和開發平臺,挑選適當的映像。 microsoft/dotnet:1.1.2-sdk是一個基於 Linux 的映像,用於此處。 例如, microsoft/dotnet:1.1.2-sdk-nanoserver 對於 Windows,可以使用。 選擇符合需求的。

Windows 使用者的注意事項:如先前所述,為了維護跨平臺相容性,本文會使用 .NET Core 和 Orleans Technical Preview 2.0。 若要在 Windows 上使用完整發行的Orleans 1.4+ Docker,請使用以 Windows Server Core 為基礎的映像,因為 NanoServer 和以 Linux 為基礎的映像僅支援 .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"]

Dockerfile 基本上會下載並安裝 VSdbg 調試程式,並啟動空的容器,使其無限期保持運作,因此不需要在偵錯期間卸除並重複啟動。

現在,針對生產環境,映像會更小,因為它只包含 .NET Core 運行時間,而不是整個 SDK。 Dockerfile 也更簡單:

Dockerfile

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

docker-compose 檔案

檔案 docker-compose.yml 會在服務層級的項目內定義一組服務及其相依性。 根據 Dockerfile 中選取的映像,每個服務都包含一個或多個特定容器的實例。 在 docker-compose中找到關於的更多詳細資訊。

Orleans針對部署,常見的使用案例牽涉到包含兩個服務的docker-compose.yml檔案:一個用於OrleansSilo,另一個用於Orleans用戶端。 客戶端服務依賴Silo服務,只有在Silo服務運行後才會啟動。 另一種情境可能涉及新增儲存或資料庫服務/容器(例如 SQL Server),這應該在客戶端和儲存容器之前啟動。 在此情況下,客戶端和儲存穀倉服務會相依於資料庫服務。

注意

在繼續閱讀之前,請注意縮排在檔案中是很重要的。 如果發生問題,請留意。

本文中對這些服務的描述方式如下:

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

version: '3.1'

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

在生產環境中,本機目錄不會被映射,build: 動作也不會被包含。 原因是在生產環境中,映像檔應該建置並推送至私人 Docker 儲存庫。

將所有項目放在一起

既然所有必要的元件都已就緒,讓我們將它們放在一起,在 Docker 內執行 Orleans 解決方案。

重要

您應該從解決方案目錄執行下列命令。

首先,請確保解決方案的所有 NuGet 套件已恢復。 這通常只需要執行一次,除非套件相依性變更。

dotnet restore

現在,如往常使用 dotnet CLI 建置解決方案,並將它發佈至輸出目錄:

dotnet publish -o ./bin/PublishOutput

提示

publish 在這裡被使用以替代 build ,以避免在 Orleans 中動態載入的元件出現問題。 仍在尋求更好的解決方案。

建置和發佈應用程式後,使用 Dockerfiles 建置 Docker 映像。 此步驟通常需要為每個項目執行一次。 只有在 Dockerfile 或 docker-compose 檔案變更,或基於任何原因清除本地映像檔註冊表時,才需要再次進行此操作。

docker-compose build

Dockerfiledocker-compose.yml 中使用的所有基底圖像都會從登錄提取,並在開發機器上快取。 應用程式映像已建置,且所有專案都已準備好執行。

現在,讓我們執行應用程式!

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

現在,執行 docker-compose ps 會顯示出在 orleansdocker 專案中運行的兩個容器。

# 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

注意

如果 Windows 和容器使用 Windows 基底映射, [命令 ] 資料行會顯示 *NIX 系統上的 PowerShell 對等命令 tail ,讓容器以類似的方式執行。

既然容器正在執行,每次應用程式需要啟動時 Orleans 就不需要停止容器。 只要整合 IDE 以偵錯容器內的應用程式,該容器先前已在 中 docker-compose.yml對應。

調整大小

Compose 專案執行之後,使用 docker-compose scale 命令輕鬆地擴展或縮減應用程式:

# 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

幾秒鐘之後,服務會調整為所要求的特定實例數目。

# 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

重要

Command 這些範例中的欄會顯示tail命令,因為使用了調試器容器。 在生產環境中,它會顯示 dotnet OrleansSilo.dll,例如。

Docker Swarm

Docker 的叢集堆疊稱為 Swarm。 如需詳細資訊,請參閱 Docker Swarm

若要在叢集中執行本文 Swarm 所述的應用程式,不需要額外的工作。 在docker-compose up -d節點上執行Swarm會根據設定的規則排程容器。 這同樣適用於其他 Swarm 型服務,例如 Azure Kubernetes Service (AKS) (在 Swarm 模式中)和 AWS 彈性容器服務 (ECS)。 只要在部署 Swarm 應用程式之前先部署Orleans叢集。

注意

如果使用 Docker 引擎搭配支援 stackdeploy、和 compose v3 的 Swarm 模式,則部署解決方案的一個更好方法是 docker stack deploy -c docker-compose.yml <name>。 請記住,這需要與 Docker 引擎相容的 v3 撰寫檔案。 許多託管服務,例如 Azure 和 AWS 仍然使用 v2 和舊版引擎。

Google Kubernetes (K8s)

如果計劃使用 Kubernetes 來託管 Orleans,可在 OrleansContrib\Orleans.Clustering.Kubernetes 取得社群維護的叢集提供者。 您可以在該處,使用提供者,在 Kubernetes 中順暢地尋找裝載的檔和範例 Orleans 。

在容器內偵錯 Orleans

既然已經理解從頭開始在容器中執行 Orleans,那麼充分利用 Docker 最重要的原則之一:不變性,是很有益的。 容器在開發時應該有與生產環境相同的映像、相依性和運行時間。 這種做法有助於防止傳統 「它在我的計算機上運作! 」問題。 若要達成此可能性,需要容器 內部 開發的方法,包括將調試程式附加至在其中執行的應用程式。

有多種方法可以使用各種工具來達成此目的。 在撰寫時評估數個選項之後,選擇了對應用程式似乎較簡單且較不干擾的選項。

如先前所述, VSCode 用來開發範例。 以下說明如何將除錯程式附加至 Orleans 容器內的應用程式:

首先,修改方案中目錄內的 .vscode 兩個檔案:

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

這個檔案基本上會告知 VSCode 每當專案建置時,它會執行 publish 命令,類似於先前手動完成的方式。

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

現在,從 VSCode 建置解決方案(也會發佈)並啟動 Silo 和 Client 組態。 VSCode 會將 docker exec 命令傳送至執行 docker-compose 中的服務實例/容器,以啟動附加至應用程式的調試程式。 就是這樣! 偵錯工具會附加至容器,因此可以像偵錯本機執行的 Orleans 應用程式一樣使用。 主要差異在於應用程式會在容器內執行。 開發完成後,請將容器映射發佈至登錄,並將其提取至生產環境的 Docker 主機。