Google Cloud에 .NET 앱 배포

Last reviewed 2022-01-19 UTC

이 문서에서는 Google Cloud에 .NET 앱을 배포하는 방법과 앱에 적합한 배포 방법을 선택하는 방법을 설명합니다.

소개

Microsoft .NET Framework는 앱 개발을 위한 풍부한 도구 및 라이브러리 세트를 제공합니다. Windows에서 Docker를 지원하고 Linux에서 .NET Core 앱을 실행할 수 있게 됨에 따라 .NET 앱은 이제 다양한 배포 대상을 지원할 수 있습니다.

효율적인 개발 및 테스트를 위해 앱 배포를 자동화하고 CI/CD(지속적 통합/지속적 배포) 파이프라인의 일부로 사용할 수 있습니다. 그러나 올바른 툴링을 선택하고 CI/CD 파이프라인을 구축하려면 먼저 프로덕션 환경에서 앱을 실행하는 방법과 사용할 배포 방법을 파악해야 합니다.

Google Cloud에 .NET 앱을 배포하는 최상의 방법은 없습니다. 가장 적합한 배포 옵션은 앱과 요구사항에 따라 달라집니다. 예를 들어 .NET Framework 전체를 설치해야 하거나 IIS에서 실행되어야 하는 앱의 경우 Windows를 기반으로 배포가 이루어져야 합니다. 반면, .NET Core에서 지원하는 기능으로 앱을 실행할 수 있는 경우 Linux에서 배포할 수 있습니다.

이 문서에서는 각 옵션이 적합한 경우의 조건을 포함하여 Google Cloud에서 .NET 앱을 실행하고 배포할 수 있는 다양한 방법을 살펴봅니다. 마지막 부분에는 .NET 앱에 가장 적합한 Google Cloud 구성요소와 방법을 결정하는 데 유용하도록 배포 옵션이 결정 트리에 요약되어 있습니다.

배포 모델

앱의 자동 배포를 수행하는 두 가지 기본 방법이 있습니다. 즉, 배포 패키지를 앱 서버로 내보내거나 앱 서버가 알려진 위치에서 앱 패키지를 가져오는 방법입니다. 다음 섹션에서는 이 두 모델의 차이점에 대해 설명합니다.

내보내기 기반 배포

내보내기 기반 배포에서 배포 아티팩트(zip 파일, NuGet 패키지 또는 다른 아티팩트)는 초기에 배포 서버에서만 사용할 수 있습니다. 배포 서버는 전용 머신이거나 CI 시스템이 가정하는 역할일 수 있습니다.

배포를 수행하기 위해 배포 서버의 프로세스가 앱 서버에 연결하고 배포 아티팩트를 복사한 다음 설치를 시작합니다. 앱 서버가 둘 이상 있는 경우 아티팩트가 모든 앱 서버에 배포되도록 이 프로세스가 병렬로 또는 순차적으로(보다 일반적) 반복됩니다.

이 흐름을 다이어그램으로 나타내면 다음과 같습니다.

내보내기 기반 배포

다양한 구성 관리 도구를 사용하여 이러한 방식으로 배포를 자동화할 수 있습니다. 이러한 도구 중 일부는 배포 단계의 순서가 스크립트와 같은 방식으로 정의되는 명령형 접근 방식을 따릅니다. 이 방법은 직관적이지만 구성 드리프트가 발생하기 쉽습니다. 즉, 일정 시간이 지난 후에 여러 머신의 상태가 동일하지 않고 의도한 상태를 완전히 반영하지 못할 수 있습니다. 따라서 많은 도구를 사용하여 원하는 상태를 정의하고 이 상태를 구현하는 데 필요한 단계를 파악할 수 있습니다.

Windows에서 이 배포 모델에 일반적으로 사용되는 도구는 다음과 같습니다.

인기 오픈소스 도구로는 Ansible, Chef Infra, Puppet이 있습니다. 이러한 도구는 주로 Linux를 대상으로 하지만 Windows 대상도 배포할 수 있습니다.

보안

배포 서버가 배포를 앱 서버로 내보내려면 백 채널을 사용할 수 있어야 합니다. 예를 들어 Web Deploy 및 Octopus Deploy는 이 작업에 커스텀 프로토콜과 포트를 사용하고 Ansible은 SSH를 사용합니다.

이 도구가 사용하는 프로토콜에 관계없이 공격자가 백 채널을 사용하여 악성 앱을 배포하지 못하도록 통신이 안전하게 보호되어야 합니다. 가장 중요한 것은 보안 통신을 위해 배포 서버가 앱 서버로 인증할 수 있어야 한다는 것입니다.

SSH는 공개 키 인증을 사용할 수 있습니다. 적절한 IAM 구성을 사용하면 Google Cloud가 SSH에 사용되는 공개 키를 앱 서버에 자동으로 배포하도록 할 수 있습니다. IAM을 사용하지 않으면 Google Cloud에서 키를 자동으로 관리할 수 없으며 개발자가 직접 이 태스크를 관리해야 합니다.

한 가지 옵션은 Active Directory입니다. 배포 서버와 앱 서버가 모두 Windows를 실행하고 Active Directory 도메인의 구성원일 경우 Kerberos를 사용하여 인증이 처리됩니다. 그러나 내결함성 Active Directory 환경을 실행할 경우 도메인 컨트롤러를 실행하기 위해 VM 인스턴스가 최소 두 개 이상 추가로 필요합니다. 구성에서 자동 확장 기능을 사용하는 경우 모든 서버도 도메인에 동적으로 가입시켜야 하므로 서버를 가동하는 프로세스가 느려집니다. 자동 확장 기능을 사용하면 비활성 컴퓨터 객체가 디렉터리에 누적되어 추가 스카벤징 로직이 필요합니다. 클라우드 기반 환경에서 Active Directory를 사용하는 경우 이러한 추가 요인을 고려해야 합니다.

Active Directory가 없으면 NTLM을 사용하거나 HTTP 기본 인증과 같은 다른 방법을 통해 인증을 처리해야 합니다. 두 방법 모두 배포 서버와 앱 서버 간에 사용자 인증 정보를 동기화하고 안전하게 저장해야 합니다. 이 두 작업은 까다로울 수 있습니다.

Linux 또는 Windows를 사용하는 경우 배포판과 앱 서버 간의 통신을 보장하려면 IAM과 별도의 메커니즘이 필요합니다. 그러나 시스템에 대한 액세스를 제어하기 위해 여러 메커니즘을 사용하면 전체적인 복잡성이 증가하고 실수로 잘못된 구성이 발생할 위험이 높아집니다.

운영체제 업데이트

앱 서버에 새로운 버전의 앱 패키지를 효율적으로 배포하는 것이 중요하지만 해당 서버에서 기본 운영체제를 서비스하는 것도 중요합니다. 즉, 보안 패치를 설치해야 합니다. 규모가 큰 서버 제품군의 경우 위험을 최소화하고 업데이트하는 동안 사용할 수 없는 서버 수를 최소화하는 방식으로 이 프로세스를 자동화해야 합니다.

운영체제 업데이트에 내보내기 방식을 사용하여 배포 서버가 앱 서버에서 OS 업데이트를 트리거하도록 할 수도 있습니다. Linux에서는 SSH를 사용하여 원격으로 업데이트 명령을 실행하는 것이 일반적입니다. Windows에서는 일반적으로 PowerShell 원격(WinRM 사용)을 사용합니다. 두 메커니즘 모두 사용자 인증 정보를 안전하게 인증하고 저장할 수 있어야 합니다.

자동 확장

앱 서버 수가 변경되지 않는 정적 환경에서 배포 서버는 모든 배포 대상을 미리 알고 있습니다. 클라우드 환경에서는 앱 서버 수를 자동으로 늘리거나 줄이는 것이 도움이 되는 경우가 많습니다. 내보내기 기반 배포를 사용하는 경우 다음과 같은 두 가지 문제가 발생합니다.

  • 새 앱 서버가 추가되면 배포 서버에 등록하여 새 서버가 향후 배포에 포함되도록 합니다.
  • 새 서버는 초기 배포판을 받아야 합니다.

자동 확장 이벤트는 배포 서버를 통해 시작되지 않습니다. 대신 배포 서버보다 낮은 수준에서 작동하는 기본 관리형 인스턴스 그룹을 통해 시작됩니다.

새 앱 서버 인스턴스는 자체적으로 배포 서버에 등록되고 새 앱 서버가 요청을 처리하기 전에 배포를 트리거해야 합니다. 다음 다이어그램은 이 프로세스를 보여줍니다.

내보내기 기반 배포로 자동 확장

배포 서버가 앱 서버에 연결하여 인증할 수 있다고 해서 이 접근 방식이 작동하는 것은 아닙니다. 또한 앱 서버는 배포 서버에 연결하여 인증해야 합니다.

마지막으로 새로 출시된 서버에는 최신 OS 보안 패치가 있어야 합니다. 자동 확장 프로세스 중에 업데이트를 시작하면 프로세스가 상당히 지연됩니다. 따라서 앱 서버 VM 생성 시 사용된 이미지에 이미 업데이트가 설치되어 있어야 합니다. 이는 다음과 같은 두 가지 방법으로 관리할 수 있습니다.

  • Google Cloud에서 제공하는 공개 이미지를 사용합니다. Google에서 이 이미지를 최신 상태로 유지합니다. 이러한 이미지에는 OS만 포함되어 있으므로 시작 스크립트를 사용하거나 앱 배포의 일부로 모든 맞춤설정(앱 코드, 유틸리티, OS 구성)을 처리해야 합니다.
  • 커스텀 OS 이미지를 유지보수하고 최신 상태로 유지합니다. 이렇게 하면 이미지에 맞춤설정을 적용할 수 있지만 배포 관리의 전반적인 복잡성이 증가합니다.

내보내기 기반 배포를 수행하는 것은 직관적이지만 보안, OS 업데이트, 자동 확장을 고려할 때 상당히 복잡할 수 있습니다. 다음 섹션에서는 가져오기 기반 배포에 대해 다룹니다. 이는 클라우드 전용 배포 방식에 가깝습니다.

가져오기 기반 배포

가져오기 기반 배포에서는 배포가 간접적인 방식으로 수행됩니다. CI 시스템은 배포 아티팩트의 새 버전을 생성한 후 아티팩트를 저장소에 게시합니다. 이 흐름을 다이어그램으로 나타내면 다음과 같습니다.

가져오기 기반 배포

배포가 수행될 때(아티팩트를 게시한 직후 또는 나중 단계에서) 배포 서버는 실제 배포판을 트리거합니다. 다시 말하지만, 배포 서버는 CI 시스템이 가정하는 별도의 시스템 또는 역할일 수 있습니다. 배포를 트리거하려면 앱 서버에 연결하여 앱 서버가 중앙 저장소에서 배포 아티팩트를 가져와서 설치하도록 해야 합니다.

내보내기 기반 모델과 가져오기 기반 모델의 차이점은 처음에는 미미한 것처럼 보일 수 있지만 가져오기 기반 배포를 수행하는 것은 몇 가지 중요한 의미가 있습니다.

  • 배포 아티팩트를 가져오도록 앱 서버를 트리거하는 작업은 앱이나 OS 수준에서 발생하지 않아도 됩니다. 대신 배포 서버는 Compute Engine에서 VM을 다시 시작하거나 대체하도록 하여 가져오기 작업을 트리거할 수 있습니다. 이를 통해 내보내기 기반 배포와 관련된 보안 문제를 방지할 수 있습니다.
  • 배포 아티팩트는 앱 파일만 포함하는 대신 앱 및 OS 업데이트 적용 프로세스를 통합하는 Docker 이미지 또는 VM 이미지일 수 있습니다.

보안

배포 서버는 특정 종류의 배포에 대해 앱 서버와 상호작용할 필요가 전혀 없습니다. 예를 들어 배포 아티팩트가 다음 중 하나인 경우 상호작용이 필요하지 않습니다.

  • VM 이미지.
  • Google Kubernetes Engine에 배포할 Docker 이미지.
  • App Engine에 배포할 패키지.

대신 배포 서버가 Google Cloud API와 상호작용하기만 하면 배포를 시작할 수 있습니다. 즉, 배포 프로세스는 IAM에서 제공하는 인증 메커니즘을 사용할 수 있으며, 그러면 키나 사용자 인증 정보를 관리할 필요가 없습니다.

앱 파일과 바이너리만 포함된 zip 또는 NuGet 패키지와 같은 배포 아티팩트를 사용하는 경우 다음과 같은 방법으로 배포를 트리거할 수 있습니다.

  • 운영체제가 시작될 때 서버가 최신 배포 아티팩트를 가져와 설치하도록 구성된 경우 Google Cloud가 VM을 다시 시작하도록 하여 업데이트를 트리거할 수 있습니다. 다시 시작하느라 불필요한 시간을 낭비하는 것처럼 보이겠지만 이렇게 하면 배포 서버를 앱 서버에 인증해야 할 필요가 없습니다.
  • 내보내기 기반 배포와 마찬가지로 배포 서버는 백 채널을 통해 원격으로 업데이트를 트리거할 수 있습니다. 그러나 이 접근 방식은 내보내기 기반 배포와 마찬가지로 보안에 영향을 주며 사용자 인증 정보 관리와 관련된 문제가 있습니다.
  • 배포 서버는 새로운 배포 아티팩트에 대한 저장소를 관찰하는 에이전트를 실행할 수 있습니다. 새 아티팩트가 감지되면 서버에서 이를 자동으로 적용할 수 있습니다. 잠재적인 문제는 여러 앱 서버가 동시에 업데이트를 설치하여 사용할 수 없게 된다는 것입니다. 이를 피하기 위해 에이전트는 저장소에서 서버 상태를 추적하고 이 서버 상태 정보를 사용하여 제어된 방식으로 업데이트를 배포할 수 있습니다.

이 경우 서버가 악성 패키지를 가져와서 설치하지 못하도록 저장소에 대한 쓰기 액세스를 제어해야 합니다.

운영체제 업데이트

Docker 또는 VM 이미지를 배포 아티팩트로 사용하면 이러한 아티팩트는 앱 파일과 종속 항목을 결합합니다. 따라서 운영체제와 앱 업데이트에 동일한 배포 메커니즘을 사용할 수 있습니다. 이 경우 새로운 배포 아티팩트를 빌드하고 두 가지 개별 사례에 게시할 수 있는지 확인해야 합니다. 첫 번째는 새로운 앱 버전이 출시되는 경우입니다. 두 번째는 운영체제 또는 다른 종속 항목에 대한 새로운 보안 업데이트가 릴리스될 때입니다.

배포 아티팩트에 앱 파일만 포함된 경우에는 운영체제를 최신 상태로 유지하는 것이 별도의 작업입니다. 따라서 내보내기 기반 배포 관련 내용에서 설명한 것과 동일한 영향이 적용됩니다.

자동 확장

앱 서버 가져오기 배포 아티팩트가 자동 확장 아이디어와 잘 맞으면 내보내기 기반 배포와 자동 확장을 결합할 경우에 발생하는 많은 복잡성을 피할 수 있습니다. 자동 확장 이벤트로 인해 새 앱 서버가 시작될 때마다 서버가 저장소에 연결하고 최신 배포 패키지를 가져와서 설치합니다.

VM 또는 Docker 이미지를 사용할 경우 이미지를 가져오는 메커니즘을 Google Cloud에서 제공합니다. zip 또는 NuGet 보관 파일과 같은 다른 패키지를 사용할 경우 시작 후 배포를 시작하도록 앱 서버를 구성해야 합니다. VM 이미지를 맞춤설정하거나 시작 스크립트를 사용하여 이 작업을 수행할 수 있습니다.

배포 대상

이전부터 .NET 앱은 Windows에서만 실행되었으며 Windows는 컨테이너를 지원하지 않았습니다. 이로 인해 앱을 실행할 환경은 선택의 여지가 없었습니다.

.NET Core의 출현으로 앱을 Windows와 Linux 중 어디서 실행할지 결정할 수 있습니다. 두 운영체제 모두 컨테이너를 지원하기 때문에 이제 대상 환경을 여러 개 중에서 선택할 수 있습니다.

운영체제

Mono는 Windows 이외의 다른 플랫폼에 .NET 앱을 배포하는 방법을 수년 동안 제안했지만 .NET Core가 출시되자 비로소 Linux는 Microsoft 개발 스택에서 완전히 지원되는 플랫폼이 되었습니다.

.NET Core는 .NET Framework의 기능 중 일부만 제공합니다. 따라서 .NET Core를 타겟팅하면 앱에 특정 제한사항이 적용됩니다. 더 중요한 것은 기존 앱의 경우 .NET Framework에서 .NET Core로 이식하는 작업이 항상 쉽고 비용 효율적이지 않을 수도 있습니다. 어떤 경우에는 전혀 가능하지 않을 수도 있습니다.

따라서 배포 모델 및 대상을 선택할 때는 기본적으로 Linux(.NET Core 필요)와 Windows(.NET Core 또는 .NET Framework 지원) 중 무엇을 사용할지 자문해 보아야 합니다.

Linux에서 .NET 앱을 실행할 경우 얻을 수 있는 이점은 다음과 같습니다.

  • 완전 관리형 환경인 App Engine 가변형 환경을 사용할 수 있습니다.
  • 컨테이너를 조정할 수 있는 관리형 환경인 GKE를 사용할 수 있습니다.
  • Windows 라이선스와 관련된 고급 Compute Engine 이미지의 추가 비용을 피할 수 있습니다.

Linux에서 .NET Core 사용 시 다음과 같은 잠재적인 단점과 이러한 이점을 저울질해야 합니다.

  • 기존 .NET 응용 프로그램을 .NET Core로 포팅하는 데 필요한 노력으로 인해 잠재적인 비용 절감 효과가 상쇄될 수 있습니다. 또는 이미 언급했듯이 기존 .NET 응용 프로그램을 .NET Core에 포팅할 수 없는 경우도 있습니다.
  • Linux는 IIS를 지원하지 않습니다. .NET Core 웹 서버인 Kestrel은 성능이 뛰어나지만 IIS와 동일한 특성 세트는 제공하지 않습니다. 따라서 Kestrel을 Nginx와 같은 웹 서버와 함께 사용해야 할 수도 있습니다.
  • Linux에 Windows 서비스와 직접적으로 동일한 기능은 없습니다. 일반적으로 Windows 서비스를 데몬으로 실행할 수 있는 Linux 콘솔 앱으로 변환할 수 있지만 이 변환이 항상 쉽지만은 않습니다.
  • Linux의 .NET Core 앱과 관련한 문제 해결 및 디버깅 작업에는 Windows에서 .NET을 사용하는 경우와 다른 도구와 기술이 필요합니다. Linux 사용 경험이 제한적인 팀이라면 이 작업이 어려울 수 있습니다.

컨테이너

컨테이너는 단일 프로세스에서 실행되는 앱에 특히 적합합니다. 예를 들면 다음과 같습니다.

  • Windows 서비스
  • 데몬 역할을 하는 Linux 콘솔 앱
  • 자체 호스팅 WCF 서비스
  • Kestrel이 호스팅하는 ASP.NET MVC 또는 Web API 앱

대다수의 .NET 앱은 IIS를 대상으로 합니다. 일반적으로 별도의 가상 디렉터리 및 앱 풀에서 여러 앱을 관리하는 데 사용되므로 단일 프로세스 패턴과 일치하지 않을 수 있습니다.

IIS 기반 환경을 컨테이너로 옮기면 다양한 방식을 사용할 수 있습니다.

  • microsoft/iis 이미지를 기본으로 사용하여 모든 가상 디렉터리와 풀이 있는 IIS를 단일 Windows 기반 Docker 이미지에 넣습니다. 앱이 밀접하게 결합되어 있지 않으면 앱을 개별적으로 업데이트하고 배포할 수 없으므로 일반적으로 이 방법을 사용하지 않는 것이 좋습니다.
  • IIS를 실행하는 앱마다 별도의 Windows 기반 Docker 이미지를 사용합니다. 이렇게 하면 앱을 독립적으로 관리할 수 있습니다. 그러나 많은 수의 컨테이너를 운영해야 하는 경우 IIS가 발생시키는 오버헤드는 무시할 수 없을 정도로 상당히 많습니다.
  • IIS의 일부 또는 모든 앱을 Kestrel로 이전합니다. Kestrel은 Windows 기반 컨테이너 또는 Linux 기반 Docker 컨테이너에 배포할 수 있으므로 컨테이너를 개별적으로 관리할 수 있습니다.

IIS는 여러 웹 앱을 단일 웹 사이트에서 실행하여 단일 도메인 이름을 공유할 수 있게 합니다. 앱을 별도의 컨테이너에 패키지하면 콘텐츠 기반 부하 분산을 사용하여 동일한 기능을 구현할 수 있습니다. 비슷한 맥락에서 Google HTTP 부하 분산기를 사용하면 Kestrel 서버 앞에 커스텀 역방향 프록시를 배포할 필요가 없습니다.

대부분의 앱은 컨테이너화할 수 있습니다. 그럴 수 없는 앱은 거의 없습니다. 그러나 일부 컨테이너화 시나리오에는 다음과 같은 문제가 있습니다.

  • IIS 관리 앱의 경우 일반적으로 앱 배포가 이미 자동화되어 있습니다. 그러나 IIS(앱 풀, 바인딩 만들기 등)를 구성하는 단계는 수동으로 수행됩니다. 컨테이너로 이동할 때 이러한 모든 초기 단계도 자동화해야 합니다.
  • 구성 파일이나 디스크에 있는 데이터에 의존하는 앱은 변경해야 할 수도 있습니다. 예를 들어 환경 변수에서 구성 정보를 얻을 수 있으며 관련 파일과 폴더를 볼륨으로 마운트할 수 있습니다. 이렇게 하면 이미지를 스테이트리스(Stateless) 상태로 환경별 구성 없이 유지할 수 있습니다.

마지막으로 Windows 기반 Docker 컨테이너를 사용할 경우 현재 Google Cloud는 Hyper-V를 지원하지 않으며 개발자가 Hyper-V 컨테이너를 실행할 수 없습니다. 따라서 Google Cloud에서는 Windows Server 컨테이너만 배포할 수 있습니다. Windows Server 컨테이너는 Hyper-V 컨테이너보다 가벼우며, 다양한 수준의 격리를 제공합니다.

배포 제약조건

이 섹션에서 설명하는 것처럼, 앱 구성 방식의 특정 요소로 인해 배포 방법에 제약이 있을 수 있습니다.

앱 아키텍처

배포 대상과 모델을 선택할 때 고려해야 할 중요한 요소는 앱의 아키텍처입니다. 모든 앱 로직이 단일 코드 기반으로 구현되고 단일 프로세스 또는 IIS 앱 풀에서 실행되는 모놀리식 아키텍처 패턴을 앱이 따를 수 있습니다. 다른 한쪽 끝에는 마이크로 서비스 패턴을 따르는 앱이 있을 수 있습니다. 이 접근 방식에서 앱은 별도의 프로세스, 별도의 IIS 앱 풀 또는 별도의 Windows 서비스로 독립적으로 실행되는 여러 서비스로 구성됩니다.

마지막으로 균일 배포 전략을 사용하여 배포되는 여러 독립형 앱이 있을 수 있습니다. 각 앱 자체는 모놀리식일 수 있습니다. 이 논의의 목적상 이 접근법은 마이크로 서비스 시나리오와 동등한 것으로 간주될 수 있습니다.

마이크로 서비스 아키텍처에서는 서비스를 고립시키고 독립적으로 관리할 수 있게 하면서 앱을 비용 효율적으로 운영하는 것이 좋습니다. 각 서비스에 전용 VM을 할당할 수 있으므로 개별적으로 서비스를 관리하고 배포할 수 있습니다. 그러나 이러한 접근 방식은 활용도가 낮은 VM을 대량으로 생성하여 불필요한 비용을 초래할 수 있습니다. 이와 같은 앱의 경우, 특히 컨테이너 기반 모델에서 보다 엄격한 패키징을 구현하는 배포 모델이 비용 면에서 더 효과적일 수 있습니다.

상태 및 스테이트리스(Stateless)

클라우드용 앱을 설계할 때는 Google Cloud 기반 저장소 서비스를 사용하여 앱을 스테이트리스(Stateless) 상태로 유지하고 상태를 외부에서 관리하세요. 스테이트리스(Stateless) 앱은 다음과 같은 다양한 장점을 제공합니다.

  • 가용성과 용량을 높이기 위해 이중으로 배포할 수 있습니다.
  • 요청은 인스턴스 간에 자유롭게 분산될 수 있습니다.
  • 자동 확장 기능과 잘 맞습니다.
  • 장애 발생 시 데이터 손실 위험 없이 환경(컨테이너 또는 VM)을 다시 만들 수 있습니다.

스테이트리(Stateless) 앱을 설계하는 것이 항상 쉽지만은 않으며, 여러 기존 앱은 이러한 방법을 따르지 않습니다. 하지만 스테이트리스(Stateless) 앱을 만들 수 있는지 여부를 분석하는 것은 여전히 그만한 가치가 있습니다.

세션 상태

ASP.NET 및 ASP.NET MVC 앱은 일반적으로 세션을 사용하여 사용자 상태를 추적하므로 앱이 스테이트풀(Stateful) 상태입니다. 그러나 세션의 영향을 제한하는 여러 가지 옵션이 있습니다.

  • 세션 데이터의 양이 적으면 암호화된 쿠키나 서명된 쿠키에 상태를 대신 저장할 수 있습니다.
  • 기본 InProc 세션 상태 공급자를 사용하는 대신 SQLServer 제공자를 사용할 수 있습니다. 그러나 이 작업은 SQL Server 인스턴스가 필요하므로 추가 비용이 발생하고 앱의 대기 시간과 가용성에 영향을 미칠 수 있습니다.
  • Cloud Load Balancing에서 세션 어피니티를 활용할 수 있습니다. 이 기능을 사용하면 단일 클라이언트의 모든 요청이 동일한 앱 인스턴스로 라우팅됩니다. 그러나 세션 어피니티를 사용하면 부하 분산의 공정성에 부정적인 영향을 줄 수 있습니다. 즉, 특정 앱 인스턴스가 다른 앱 인스턴스보다 많은 요청을 받게 될 수 있습니다. 또한 어떤 이유로든 앱 인스턴스가 종료되면 인스턴스에서 처리한 모든 세션이 손실되어 잠재적으로 최종 사용자에게 영향을 줄 수 있습니다. 따라서 세션 어피니티에 의존하는 것이 이상적인 솔루션은 아니지만 견고성과 비용 간에 실용적인 절충안이 되는 경우가 많습니다.

메모리 내 캐시

앱은 일반적으로 중복 계산이나 데이터베이스 조회를 피하기 위해 메모리 내 캐시를 사용합니다. 이 경우 여러 개의 앱 인스턴스가 동시에 실행되면 캐시가 일관성을 잃을 수 있기 때문에 문제가 됩니다.

비일관성을 방지하려면 IDistributedCache 인터페이스를 통해 또는 직접 분산 캐시를 사용합니다. Redis 또는 Memcached와 같은 캐싱 서버에서는 일반적으로 리소스 요구량이 상대적으로 적지만 전반적인 설정이 더 복잡해집니다.

스토리지

이미지, 첨부파일 또는 미디어 파일 형식의 데이터는 일반적으로 디스크에 저장됩니다. VM에서 이 목적으로 영구 디스크를 사용하는 것은 일반적으로 불가능합니다. 영구 디스크는 데이터가 여러 컴퓨터에서 공유되는 것을 방지하고 VM 인스턴스를 다시 만들면 데이터가 손실될 수 있기 때문입니다. 대신 다음 방법 중 하나를 사용할 수 있습니다.

  • 데이터를 파일 공유 서버로 이동합니다. 이렇게 하면 앱에 미치는 영향이 최소화됩니다. 그러나 가용성이 높은 SMB 또는 NFS 서버를 운영하려면 추가 비용과 유지보수 노력이 필요합니다.
  • 데이터를 Cloud Storage로 이동합니다. 이를 위해서는 앱을 변경해야 하지만 Cloud Storage는 파일 서버를 실행하는 것보다 비용 효율이 훨씬 높으며 추가 유지관리 작업이 필요하지 않습니다.
  • 데이터를 Filestore 파일 서버로 이동합니다. 이 방법을 사용하려면 앱을 약간 변경해야 할 수 있지만 일단 프로비저닝되면 다운타임 없이 필요에 따라 인스턴스 용량을 확장할 수 있습니다. Filestore는 또한 동일한 파일 시스템에 동시에 액세스하는 여러 동시 실행 애플리케이션 인스턴스를 지원합니다.
  • 데이터를 Cloud Volumes Service로 이동합니다. Cloud Volumes Service를 사용하면 NFS 및 SMB 볼륨을 지원하는 파일 기반 앱을 Google Cloud로 이동할 수 있습니다. 앱을 다시 설계할 필요가 없으며 복잡성 없이 앱에 대한 영구 스토리지를 얻을 수 있습니다.

배포 전략

새 버전의 앱을 배포할 때는 위험 요소와 최종 사용자에 미치는 영향을 최소화해야 합니다. 이를 위한 가장 일반적인 세 가지 전략은 재생성, Blue/Green, 지속적 배포입니다.

재생성 전략

재생성 전략은 모든 서버에서 실행 중인 앱을 중지하고 새 버전을 배포한 후 앱을 시작한다는 개념입니다. 이 전략에는 서비스 중단을 일으키는 명백한 단점이 있지만 앱의 두 가지 버전이 일시적으로 공존하여 공통 데이터에 액세스할 때 발생할 수 있는 잠재적인 문제가 방지됩니다.

Blue/Green 전략

Blue/Green 전략(Red/Black이라고도 함)은 새 서버 세트에 새 앱 버전을 배포한다는 개념입니다. 배포가 완료되면 모든 트래픽을 이전 서버 세트에서 새 서버 세트로 전환합니다. 이 방법은 일시적으로 프로덕션에 필요한 서버보다 두 배 많은 서버가 필요하지만 서비스 중단을 방지합니다.

이 전략의 전제 조건은 앱의 두 버전이 일시적으로 공존할 수 있고 서로 간섭하지 않는 것입니다. 데이터베이스에 액세스하는 앱의 경우 데이터베이스 스키마에 변경이 반복될 때마다 적어도 이전 버전과 호환되어야 합니다.

지속적 배포 전략

지속적 배포는 한 서버를 차례로 업데이트한다는 개념입니다. Blue/Green 전략과 마찬가지로 이는 일정 시간 동안 앱의 두 가지 버전이 공존한다는 것을 의미합니다. 그러나 Blue/Green 배포와 달리 트래픽을 이전 버전에서 새 버전으로 점진적으로 전환합니다. 더 많은 서버가 업데이트될수록 더 많은 사용자가 새 버전으로 라우팅되고, 마침내 마지막 서버가 업데이트되면 모든 사용자가 새 버전을 사용합니다. 이 접근법의 주요 이점은 모든 사용자가 영향을 받기 전에 잠재적인 문제를 조기에 발견할 수 있으므로 전반적인 위험을 낮추는 데 도움이 된다는 것입니다.

지속적 배포 전략의 경우 두 가지 버전의 앱이 공존해야 하기 때문에 버전 간 사용자 이탈을 방지하는 부하 분산기 구성이 필요한 경우도 많습니다.

배포 옵션

이 문서에서는 지금까지 배포 모델, 대상, 전략에 대해 논의했습니다. 다음 섹션에서는 Google Cloud에 .NET 앱을 배포하는 데 필요한 특정 옵션을 살펴봅니다.

GKE(Windows 또는 Linux)

GKE는 완전 관리형 Kubernetes 환경을 제공합니다. Kubernetes에는 조정 기능이 있으므로 GKE는 여러 컨테이너로 구성된 복잡한 마이크로 서비스 앱을 실행하는 데 특히 적합합니다. 그러나 마이크로 서비스 패턴을 따르지 않는 앱의 경우에도 GKE를 사용하면 리소스 효율이 높고 유지 관리가 간편한 방법으로 공유 인프라에서 여러 컨테이너를 실행할 수 있습니다.

GKE를 사용하려면 앱의 모든 부분을 Docker 컨테이너로 패키지화해야 합니다. Linux 기반 컨테이너에는 .NET Core와 Linux 기반 환경을 사용해야 합니다. CI 시스템이 Windows 기반일 경우 Linux에 컨테이너를 빌드하기가 어려울 수 있습니다. 그러나 Azure Pipelines/Team Foundation Server와 Cloud Build 모두에는 .NET Core 앱 빌드와 Linux 기반 컨테이너 이미지의 빌드 및 게시를 위한 지원 기능이 기본 제공됩니다.

GKE는 스테이트리스(Stateless) 앱에 가장 많은 유연성을 제공합니다. 스테이트풀(Stateful) 세트와 영구 볼륨을 사용하여 GKE에서 특정 종류의 스테이트풀(Stateful) 앱을 실행할 수도 있습니다.

GKE 클러스터에는 컨테이너가 예약된 노드라고 하는 여러 VM 인스턴스가 있습니다. 다중 영역 또는 지역 클러스터에서 GKE는 고가용성을 보장하기 위해 여러 영역에 노드와 워크로드를 분산시킬 수 있습니다.

가격은 실행 중인 노드 수를 기반으로 책정됩니다. 따라서 GKE는 노드가 잘 사용될 때 가장 비용 효율이 높습니다. 동일한 클러스터에서 더 큰 워크로드를 실행하거나 필요에 따라 자동으로 노드 수를 조정할 수 있습니다.

kubectl 명령어를 사용한 가져오기 기반 배포

앱을 GKE에 배포하려면 다음 두 단계를 수행해야 합니다.

  1. docker push 또는 다른 방법을 사용하여 Docker 이미지를 Artifact Registry 또는 외부 Docker 레지스트리에 게시합니다. 대개 CI 시스템에서 이 단계를 처리합니다.
  2. kubectl을 사용하여 배포 트리거. 이 단계는 CI 시스템에서 처리하거나 별도로 처리할 수 있습니다. 배포가 원격으로 시작되므로 kubectl이 Linux 또는 Windows에서 실행되는지 여부는 상관없습니다.

GKE에는 재생성 및 지속적 배포 전략에 대한 지원 기능이 내장되어 있습니다. 배포를 제어하기 위한 기본 요소는 다른 배포 전략을 허용할 만큼 충분히 유연하지만 다른 전략을 사용하려면 추가 도구 또는 스크립팅이 필요합니다.

Spinnaker를 사용한 가져오기 기반 배포

배포 조정을 위한 GKE의 기본 제공 기능이 목적에 불충분할 경우 GKE와 Spinnaker를 결합할 수 있습니다. Spinnaker에는 GKE에 대한 지원 기능이 내장되어 있어 Blue/Green 배포를 비롯한 고급 배포 전략을 구현할 수 있습니다.

Spinnaker는 관리형 서비스가 아니므로 별도로 배포 및 유지 관리해야 합니다. Spinnaker를 별도의 Linux VM 인스턴스 또는 GKE 클러스터에 배포할 수 있습니다.

Knative 및 Cloud Run

스테이트리스(Stateless) .NET Core 컨테이너의 경우 Knative와 관리형 버전인 Cloud Run은 서버리스 컨테이너 환경을 제공합니다. 서버리스 컨테이너는 인프라 관리 오버헤드 없이 프로비저닝, 자동 확장, 부하 분산과 같은 이점을 제공합니다.

Kubernetes 클러스터에 컨테이너를 배포하는 경우 Knative는 Kubernetes보다 더 높은 수준의 작은 API 표면을 제공합니다. 따라서 Knative를 사용하면 Kubernetes의 복잡성이 방지되어 컨테이너를 더욱 쉽게 배포할 수 있습니다.

Cloud Run은 Knative API를 따르지만 Google 인프라에서 실행되므로 Kubernetes 클러스터가 필요하지 않습니다. Cloud Run은 컨테이너에 서버리스 옵션을 제공합니다. 기본적으로 Cloud Run의 컨테이너는 요청 기간 동안 자동 확장되고 비용이 청구됩니다. 배포 시간은 초 단위입니다. 또한 Cloud Run은 버전 및 트래픽 분할과 같은 유용한 기능을 제공합니다.

Cloud Run for Anthos는 Knative의 단순성과 Kubernetes를 유연하게 운영할 수 있는 Cloud Run을 제공하는 보다 유연한 Cloud Run 버전입니다. 예를 들어 Cloud Run on Anthos를 사용하면 컨테이너를 실행하는 기본 인스턴스에 GPU를 추가하거나 애플리케이션을 여러 컨테이너로 확장할 수 있습니다.

Cloud Run은 Pub/Sub, Cloud Scheduler, Cloud Tasks와 같은 다른 서비스 및 Cloud SQL과 같은 백엔드와 통합됩니다. 자동 확장 웹 프런트엔드 또는 이벤트에 의해 트리거되는 내부 마이크로서비스 모두에 사용될 수 있습니다.

Compute Engine(Windows 또는 Linux)

Compute Engine을 사용하면 VM 인스턴스를 만들고 관리할 수 있습니다. 이는 광범위한 Windows Server 버전 및 Linux 배포판 외에 크기 조절 및 구성 옵션도 지원합니다. 이러한 유연성 덕분에 다양한 워크로드에 Compute Engine VM 인스턴스를 사용할 수 있습니다.

앱을 개별적으로 배포하고 유지 관리하려면 각 VM 인스턴스에 하나의 앱이나 서비스만 배포하세요. 고가용성을 보장하려면 앱마다 각기 다른 영역에 위치한 두 개 이상의 VM 인스턴스를 실행하세요. 따라서 예상 부하에 관계없이 배포할 앱 또는 서비스 수의 두 배에 해당하는 VM 인스턴스가 필요하다고 가정할 수 있습니다.

Compute Engine은 관리형 인스턴스 그룹을 통해 자동 확장을 구현하는 간단한 방법을 제공합니다. 이 문서의 뒷부분에서 설명하겠지만 관리형 인스턴스 그룹은 지속적 배포를 구현하는 방법도 제공합니다.

Compute Engine 요금은 VM 인스턴스에 따라 산정되므로 앱에 상당한 부하가 발생할 때, 즉 VM 인스턴스 사용률이 높을 때 Compute Engine에서 앱을 실행하는 것이 가장 비용 효율적이라고 가정할 수 있습니다. 반대로 서비스 및 앱 수가 많지만 평균 사용률이 낮으면 GKE와 같은 다른 배포 옵션을 사용하면 여러 앱이 워크로드 격리를 그대로 유지하면서 공통 인프라를 사용할 수 있으므로 더 경제적인 경우가 많습니다.

Windows VM 인스턴스를 실행하려면 고급 이미지를 사용해야 합니다. 이러한 이미지에는 라이선스가 부여된 Windows 사본이 포함되어 있으므로 추가 요금이 부과됩니다. 따라서 Windows VM은 라이선스 비용이 들지 않는 CentOS 또는 Debian과 같은 Linux 배포판을 사용하는 VM보다 일반적으로 비용 효율이 떨어집니다.

SSH 또는 RDP를 사용하여 VM 인스턴스를 수동으로 설정하여 앱을 수동으로 배포하거나 첫 번째 배포를 위해 머신을 준비하는 데 필요한 초기 구성을 처리할 수 있습니다. 그러나 이로 인해 다른 VM 인스턴스와 다른 고유한 구성을 갖는 머신이 생길 수 있습니다. 장기적으로 VM 인스턴스를 수동으로 설정하는 작업은 더 복잡해지고 노동 집약적인 작업이 될 수 있습니다. 따라서 반복 가능하도록 프로세스를 자동화하는 것이 좋습니다.

Compute Engine에서 앱 배포를 자동화하려면 다음 작업을 수행합니다.

  1. 첫 번째 앱 배포를 위한 VM 인스턴스 프로비저닝 및 준비.
  2. 앱 배포 수행.
  3. OS 서비스(보안 업데이트 설치).

다음 두 섹션에서는 가져오기 기반 배포 방법을 사용하여 세 가지 단계를 모두 통일된 방식으로 처리하는 방법에 대해 설명합니다. 이 섹션에 설명된 방법의 메커니즘과 도구는 다르지만 일반적인 아이디어는 GKE를 사용하여 컨테이너 기반 앱을 배포하는 방법과 유사합니다.

관리형 인스턴스 그룹을 사용한 가져오기 기반 배포

관리형 인스턴스 그룹은 자동 확장을 구현하는 데 가장 일반적으로 사용되지만 지속적 배포를 처리하는 방법도 제공합니다. 앱의 새 버전을 참조하는 인스턴스 템플릿을 만든 후에는 지속적 교체 기능을 사용하여 이전 템플릿을 사용하는 VM 인스턴스를 새 템플릿을 사용하는 인스턴스로 교체하면 됩니다.

이 접근법의 전제 조건은 앱의 새 버전이 인스턴스 템플릿으로 제공된다는 것입니다. 이는 두 가지 방법으로 구현할 수 있습니다.

  • 공개 OS 이미지 중 하나를 사용하는 인스턴스 템플릿을 정의합니다. 시작 스크립트를 사용하여 시스템을 구성하고 Cloud Storage 버킷, NuGet 저장소, Docker 레지스트리 또는 다른 소스에서 앱을 설치합니다. 다음 다이어그램은 이 접근 방식을 보여줍니다.

    관리형 인스턴스 그룹 및 공개 이미지를 사용한 가져오기 기반 배포

  • CI/CD 프로세스의 일부로 커스텀 VM 이미지를 만듭니다. 이 프로세스를 이미지 베이킹이라고도 합니다. 이 방법에서는 공개 OS 이미지 중 하나를 사용하여 새 VM 인스턴스를 생성하고, 여기에 최신 앱을 설치하고, 인스턴스에서 VM 이미지를 만들고, 이미지를 Google Cloud 프로젝트에 제공합니다. Packer와 같은 도구를 사용하여 전체 프로세스를 완전히 자동화할 수 있습니다. 그러면 인스턴스 템플릿에서 결과 이미지가 참조될 수 있습니다. 다음 다이어그램은 이 접근 방식을 보여줍니다.

    관리형 인스턴스 그룹 및 커스텀 이미지를 사용한 내보내기 기반 배포

커스텀 이미지를 생성할 경우(두 번째 옵션)의 단점은 이미지 베이킹이 상대적으로 느린 프로세스이며 수 분이 소요되는 경우가 많다는 점입니다. 따라서 이 접근법은 CI/CD 프로세스에 복잡성을 더할 뿐만 아니라 CI/CD 프로세스의 속도를 저하시킵니다. 위쪽에서 커스텀 이미지를 사용하여 새 VM을 시작하는 것은 간단하고 빠른 프로세스이므로 자동 확장 사용 시 유용합니다.

시작 스크립트를 사용하여 앱을 배포하는 경우(첫 번째 옵션) 이와 반대되는 단점이 있습니다. CI/CD 프로세스에서 이미지 베이킹의 오버헤드가 발생하지 않지만 VM 인스턴스를 만드는 프로세스가 느려집니다. 또한 시작 스크립트가 완전히 신뢰할 수 없거나 앱 바이너리가 다운로드된 시스템의 가용성이 높지 않은 경우 이 방법을 사용하면 가용성이 떨어질 수 있습니다.

앱에 가장 적합한 접근 방식은 앱 자체와 구성의 복잡성에 따라 다릅니다. 경우에 따라 두 가지 방법을 결합하는 것이 가장 좋습니다.

  • 커스텀 이미지에는 모든 구성 및 종속 항목이 포함되지만 실제 앱 바이너리는 포함되지 않습니다. 새 이미지는 구성이나 종속 항목이 변경될 때 베이킹되지만 각 앱 빌드마다 베이킹되지는 않습니다. 이는 앱 CI/CD 파이프라인의 속도 저하를 피하는 데 도움이 됩니다.
  • 앱은 시작 스크립트를 사용하여 설치됩니다. 위험과 속도 저하를 최소화하려면 이 프로세스를 최대한 간단히 유지해야 합니다.

공통 기본 구성을 가진 여러 가지 앱 또는 서비스를 배포하려는 시나리오에서 이 혼합 방식을 사용하면 수십 또는 수백 개의 거의 동일한 이미지를 빌드하고 유지해야 할 필요가 없습니다.

관리형 인스턴스 그룹을 사용하여 Linux 및 Windows 워크로드에 대한 배포를 조정할 수 있습니다. Linux의 경우 관리형 인스턴스 그룹을 사용하여 VM 인스턴스에 Docker 컨테이너를 배포하는 것이 가능하며 플랫폼에서 지원됩니다. 그러나 사용량이 많은 앱에만 권장됩니다. 다른 경우 VM별로 단일 Docker 컨테이너를 배포하면 GKE 또는 App Engine 가변형 환경을 사용하는 경우보다 별다른 이점이 없습니다.

Windows Server 컨테이너를 사용하는 경우 Compute Engine 및 관리형 인스턴스 그룹을 사용하여 컨테이너를 실행하는 방법에 대한 다음 지침을 따르세요.

  • Docker가 사전 설치된 커스텀 빌드 이미지 또는 다음 공개 이미지 중 하나를 사용합니다.
    • Windows Server 2019 Datacenter Core for Containers
    • Windows Server 2019 Datacenter for Containers
  • 시작 스크립트를 사용하여 Docker 이미지를 가져와서 VM 시작 중에 Windows Server 컨테이너로 시작할 수 있습니다. 적절한 포트 매핑을 사용하여 컨테이너 내부에서 실행 중인 서비스를 노출할 수 있습니다.

시작 스크립트는 Docker 서비스가 시작된 후에만 실행된다는 보장이 없습니다. Docker가 사용 가능해지기 전에 스크립트가 실행되는 상황을 적절하게 처리하려면 적절한 재시도 논리를 스크립트에 통합하세요.

클라우드가 아닌 환경에서 Windows 기반 이미지를 만들 때는 Microsoft Deployment Toolkit(MDT) 또는 Windows 배포 서비스(WDS)를 사용하면 됩니다. 그러나 이미지를 관리하고 커스텀 이미지를 기반으로 VM 인스턴스를 만드는 것이 Compute Engine의 핵심 기능이므로 이 추가 툴링은 필요하지 않습니다. Compute Engine은 시작 스크립트뿐만 아니라 Windows 기반 VM 인스턴스의 전문화 스크립트도 지원합니다. 따라서 일반적으로 커스텀 unattend.xml 파일로 작업할 필요가 없습니다. 그러나 이미지를 만들기 전에 GCESysprep을 사용하여 Windows 설치를 일반화하는 것이 중요합니다.

Spinnaker를 사용한 가져오기 기반 배포

관리형 인스턴스 그룹은 지속적 배포를 구현할 수 있는 가볍고 강력한 방법을 제공하지만 특정 앱의 경우 관리형 인스턴스 그룹의 기능만으로 부족할 수 있습니다. 보다 정교한 배포 전략과 파이프라인을 구현하려면 Spinnaker를 사용하면 됩니다.

Compute Engine에서 배포를 조정하기 위해 Spinnaker가 취한 기본 접근 방식은 이전 섹션에서 설명한 것과 유사합니다. 즉, 이미지 베이킹에도 의존합니다. 따라서 동일한 고려 사항이 적용됩니다.

Spinnaker는 관리형 서비스가 아니므로 앱과 별도로 배포 및 유지보수해야 합니다. Spinnaker는 별도의 Linux VM 인스턴스 또는 GKE 클러스터에 배포할 수 있습니다.

내보내기 기반 원격 배포

이전 섹션에서 설명한 가져오기 기반 배포 옵션은 다양한 이점을 제공합니다. 하지만 모든 종류의 앱에 적합한 것은 아닙니다. 특히 스테이트풀(Stateful) 앱에는 이 방식이 적합하지 않으며 내보내기 기반 방식이 더 적합할 수 있습니다.

내보내기 기반 방식에서는 세 가지 배포 작업(VM 인스턴스 프로비저닝, 앱 배포 수행 및 OS 서비스)을 개별적으로 처리해야 합니다. 세 가지 작업 모두에 동일한 툴링을 사용할 수 있지만 각 작업마다 다른 도구를 사용하는 경우는 드뭅니다.

Terraform과 같은 자동화 도구를 사용하여 다른 인프라와 동일한 방식으로 앱 서버 VM 인스턴스를 프로비저닝할 수 있습니다. 시작 또는 전문화 스크립트를 사용하여 앱 배포를 자동화하는 데 필요한 도구를 설치할 수 있습니다. 예를 들어 Puppet, Chef 또는 Octopus Deploy를 사용하는 경우 이러한 도구를 위한 에이전트 소프트웨어가 설치되어 있는지 확인해야 합니다.

보안 측면에서 공격 대상을 줄이려면 배포 서버와 앱 서버 VM 인스턴스에서 실행되는 모든 에이전트 간의 통신에 내부 네트워크가 사용되어야 합니다. 또한 사용 중인 포트가 공개 인터넷에 노출되지 않아야 합니다.

자동 확장이 사용되지 않는 환경에서는 Windows 기반 앱 서버를 Active Directory 도메인에 가입시켜야 구성을 중앙 집중식으로 처리할 수 있습니다. 또한 Active Directory를 사용하면 OS 서비스와 같은 관리 작업을 제어할 수 있습니다.

배포 옵션 선택

이 문서 앞부분의 설명처럼 Google Cloud에 .NET 앱을 배포하는 최상의 방법은 없습니다. 가장 적합한 배포 옵션은 앱과 요구사항에 따라 달라집니다. 적합한 모델을 선택할 때 처음으로 해야 할 질문으로는 .NET Core와 .NET Framework 중 무엇을 사용할 것인가? 그리고 Linux와 Windows 중 어디에 배포할 것인가?가 있습니다. 대상 운영 체제를 확인한 후 다음 의사 결정 트리를 사용하여 적합한 배포 모델을 파악하세요.

Linux에 .NET Core 앱을 배포하는 경우:

.NET Core 및 Linux를 사용한 배포 의사 결정 트리

Windows에 .NET Core 또는 .NET Framework 앱을 배포하는 경우:

Windows를 사용한 배포 의사 결정 트리

다음 단계