다음을 통해 공유


Docker 배포

Docker 또는 Orleans에 익숙하더라도 해결 방법이 있는 문제에 직면할 수 있으므로 이 문서를 끝까지 읽는 것이 좋습니다.

이 문서와 해당 샘플은 진행 중인 작업입니다. 어떤 피드백, PR 또는 제안이라도 환영합니다.

Docker에 Orleans 솔루션 배포

Docker 오케스트레이터 및 클러스터링 스택이 디자인된 방식을 고려할 때 Docker에 Orleans를 배포하는 것은 까다로울 수 있습니다. 가장 복잡한 것은 Docker Swarm 및 Kubernetes 네트워킹 모델의 오버레이 네트워크 개념을 이해하는 것입니다.

Docker 컨테이너 및 네트워킹 모델은 대부분 상태 비저장 컨테이너와 변경할 수 없는 컨테이너를 실행하도록 설계되었습니다. 따라서 node.js 또는 Nginx 애플리케이션을 실행하는 클러스터를 회전하는 것은 매우 쉽습니다. 그러나 실제 클러스터형 또는 분산 애플리케이션(예: Orleans 기반 애플리케이션)과 같이 좀 더 정교한 것을 사용하려고 하면 결국 설정에 문제가 발생합니다. 가능하지만 웹 기반 애플리케이션만큼 간단하지는 않습니다.

Docker 클러스터링은 컨테이너 오케스트레이터를 사용하여 관리되는 단일 리소스 풀로 작동하도록 여러 호스트를 함께 배치하는 것으로 구성됩니다. Docker Inc.Swarm을 컨테이너 오케스트레이션에 대한 옵션으로 제공하고 Google에는 Kubernetes(즉, K8s)가 있습니다. DC/OS, Mesos와 같은 다른 오케스트레이터가 있지만 이 문서에서는 더 널리 사용되는 Swarm 및 K8s에 대해 설명합니다.

Orleans가 이미 지원되는 모든 위치에서 실행되는 동일한 조직 인터페이스 및 구현이 Docker 컨테이너에서도 실행됩니다. Docker 컨테이너에서 애플리케이션을 실행하기 위해 특별히 고려할 사항은 없습니다.

여기서 설명하는 개념은 Orleans의 .NET Core 및 .NET 4.6.1 버전 모두에서 사용할 수 있지만 Docker 및 .NET Core의 플랫폼 간 특성을 설명하기 위해 .NET Core를 사용하는 경우를 고려하여 예제에 집중합니다. 플랫폼별(Windows/Linux/OSX) 세부 정보는 이 문서에서 제공할 수 있습니다.

사전 요구 사항

이 문서에서는 다음과 같은 필수 구성 요소가 설치되어 있다고 가정합니다.

  • Docker - Docker4X에는 지원되는 주요 플랫폼에 사용하기 쉬운 설치 프로그램이 있습니다. Docker 엔진과 Docker Swarm도 포함됩니다.
  • Kubernetes(K8s) - 컨테이너 오케스트레이션에 대한 Google의 제안입니다. 여기에는 모든 종속성과 함께 Minikube(K8s의 로컬 배포) 및 kubectl을 설치하기 위한 지침이 포함되어 있습니다.
  • .NET - .NET의 플랫폼 간 버전
  • VSCode(Visual Studio Code) - 원하는 IDE를 사용할 수 있습니다. VSCode는 교차 플랫폼이므로 이를 사용하여 모든 플랫폼에서 작동하도록 합니다. VSCode를 설치한 후 C# 확장을 설치합니다.

중요

Kubernetes를 사용하지 않을 경우에는 설치할 필요가 없습니다. Docker4X 설치 프로그램에는 이미 Swarm이 포함되어 있으므로 이를 사용하기 위해 추가 설치가 필요하지 않습니다.

참고

Windows에서 Docker 설치 프로그램은 설치 프로세스에서 Hyper-V를 사용하도록 설정합니다. 이 문서와 해당 예제에서는 .NET Core를 사용하므로 사용되는 컨테이너 이미지는 Windows Server NanoServer를 기반으로 합니다. .NET Core를 사용하지 않고 .NET 4.6.1 전체 프레임워크를 대상으로 하는 경우 사용되는 이미지는 Windows Server Core 및 1.4 이상 버전의 Orleans(.NET 전체 프레임워크만 지원)여야 합니다.

Orleans 솔루션 만들기

다음 지침에서는 새 dotnet 도구를 사용하여 일반 Orleans 솔루션을 만드는 방법을 보여 줍니다.

플랫폼에 적합한 모든 명령에 맞게 조정하세요. 또한 디렉터리 구조는 제안 사항일 뿐입니다. 필요에 맞게 조정하세요.

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 패키지를 설치하려면 MyGet에서 원본 피드 및 버전을 강제 적용하는 dotnet CLI를 사용합니다.

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가 선택된 편집기.

또한 Program.cs, OrleansHostWrapper.cs, IGreetingGrain.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 이미지를 사용할 것입니다. 대상 및 개발 플랫폼에 따라 적절한 이미지를 선택해야 합니다. 이 문서에서는 Linux 기반 이미지인 microsoft/dotnet:1.1.2-sdk를 사용하고 있습니다. 예를 들어 Windows용 microsoft/dotnet:1.1.2-sdk-nanoserver를 사용할 수 있습니다. 요구 사항에 맞는 항목을 선택합니다.

Windows 사용자에 대한 참고 사항: 앞에서 설명한 것처럼 교차 플랫폼을 위해 이 문서에서는 .NET Core 및 Orleans 기술 미리 보기 2.0을 사용하고 있습니다. Windows에서 완전히 릴리스된 Orleans 1.4 이상과 함께 Docker를 사용하려면 NanoServer 및 Linux 기반 이미지가 .NET Core만 지원하므로 Windows Server 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 디버거를 다운로드 및 설치하고 빈 컨테이너를 시작하여 디버깅하는 동안 해체/해제할 필요가 없도록 영구적으로 유지합니다.

이제 프로덕션의 경우 전체 SDK가 아닌 .NET Core 런타임만 포함하고 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에 대한 자세한 내용은 docker-compose 설명서에서 찾을 수 있습니다.

Orleans 배포의 경우 일반적인 사용 사례는 두 개의 서비스를 포함하는 docker-compose.yml을 사용하는 것입니다. 하나는 Orleans 사일로용이고 다른 하나는 Orleans 클라이언트용입니다. 클라이언트는 사일로에 대한 종속성을 가지며 이는 사일로 서비스가 작동한 후에만 시작된다는 것을 의미합니다. 또 다른 경우는 클라이언트와 사일로 앞에 먼저 시작해야 하는 SQL Server와 같은 스토리지/데이터베이스 서비스/컨테이너를 추가하는 것이므로 두 서비스 모두 종속성을 가져야 합니다.

참고 항목

자세한 내용을 읽기 전에 docker-compose 파일에서 들여쓰기문제를 참고하세요. 따라서 문제가 있는 경우 주의하세요.

이 문서에 대한 서비스를 설명하는 방법은 다음과 같습니다.

docker-compose.override.yml(디버그):

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(프로덕션):

version: '3.1'

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

프로덕션에서는 로컬 디렉터리를 매핑하지 않으며 build: 작업도 없습니다. 그 이유는 프로덕션 환경에서 이미지를 빌드하고 자체 Docker 레지스트리로 푸시해야 하기 때문입니다.

모든 항목을 함께 넣기

이제 Orleans 애플리케이션을 실행하는 데 필요한 모든 이동 부분이 있으므로 Docker 내에서 Orleans 솔루션을 실행할 수 있도록 통합하겠습니다.

Important

솔루션 디렉터리에서 다음 명령을 수행해야 합니다.

먼저 솔루션에서 모든 NuGet 패키지를 복원해 보겠습니다. 이 작업은 한 번만 필요합니다. 프로젝트에 대한 패키지 종속성을 변경하는 경우에만 이 작업을 다시 수행해야 합니다.

dotnet restore

이제 평소와 같이 dotnet CLI를 사용하여 솔루션을 빌드하고 출력 디렉터리에 게시해 보겠습니다.

dotnet publish -o ./bin/PublishOutput

Orleans에서 동적으로 로드된 어셈블리의 문제를 방지하기 위해 빌드 대신 publish를 사용합니다. 계속해서 더 나은 해결책을 찾고 있습니다.

애플리케이션을 빌드하고 게시하면 Dockerfile 이미지를 빌드해야 합니다. 이 단계는 프로젝트당 한 번만 수행해야 하며 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 프로젝트에 대해 2개의 컨테이너가 실행되는 것을 볼 수 있습니다.

# 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 시스템의 tail에 대한 PowerShell 상대 명령을 표시합니다.

컨테이너를 설치했으므로 Orleans 애플리케이션을 시작할 때마다 컨테이너를 중지할 필요가 없습니다. IDE를 통합하여 이전에 docker-compose.yml에 매핑된 컨테이너 내에서 애플리케이션을 디버그하기만 하면 됩니다.

크기 조정

작성 프로젝트가 실행되면 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 클러스터에서 이 문서를 실행하기 위한 추가 작업이 필요하지 않습니다. Swarm 노드에서 docker-compose up -d를 실행하면 구성된 규칙에 따라 컨테이너를 예약합니다. Azure ACS(Swarm 모드) 및 AWS ECS 컨테이너 서비스와 같은 다른 Swarm 기반 서비스에도 동일하게 적용됩니다. docker화된Orleans Orleans 애플리케이션을 배포하기 전에 Swarm 클러스터를 배포하기만 하면 됩니다.

참고 항목

이미 stack, deploycompose v3을 지원하는 Swarm 모드에서 Docker 엔진을 사용하는 경우 솔루션을 배포하는 더 나은 방식은 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"
        }
    ]
}

이 파일은 기본적으로 프로젝트를 빌드할 때마다 이전에 수동으로 했던 것처럼 publish 명령을 실행할 것임을 VSCode에 알려줍니다.

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(게시 예정)에서 솔루션을 빌드하고 사일로와 클라이언트를 모두 시작할 수 있습니다. 실행 중인 docker-compose 서비스 인스턴스/컨테이너에 docker exec 명령을 보내 애플리케이션에 대한 디버거를 시작합니다. 컨테이너에 디버거를 연결하고 로컬에서 실행 중인 Orleans 애플리케이션인 것처럼 사용합니다. 이제 차이점은 컨테이너 내부에 있으며 완료되면 레지스트리에 컨테이너를 게시하고 프로덕션의 Docker 호스트에서 끌어올 수 있다는 것입니다.