일반 웹 애플리케이션 아키텍처

이 콘텐츠는 .NET Docs 또는 오프라인으로 읽을 수 있는 다운로드 가능한 무료 PDF로 제공되는 eBook, ASP.NET Core 및 Azure를 사용하여 최신 웹 애플리케이션 설계에서 발췌한 내용입니다.

Architect Modern Web Applications with ASP.NET Core and Azure eBook cover thumbnail.

"좋은 아키텍처가 비싸다고 생각되면 나쁜 아키텍처를 시도해 보세요." - 브라이언 풋과 조셉 요더

대부분의 기존 .NET 애플리케이션은 단일 IIS appdomain에서 실행되는 실행 파일 또는 단일 웹 애플리케이션에 해당하는 단일 단위로 배포됩니다. 이 방법은 가장 간단한 배포 모델이며 다양한 내부 애플리케이션과 작은 퍼블릭 애플리케이션에 매우 적합합니다. 하지만 이 단일 배포 단위를 사용하더라도 대부분의 중요한 업무용 애플리케이션은 여러 레이어로 논리적 분리 시 이점을 얻을 수 있습니다.

모놀리식 애플리케이션이란?

모놀리식 애플리케이션은 그 동작에 있어서 완전히 독립적인 애플리케이션입니다. 작업을 수행하는 과정에서 다른 서비스 또는 데이터 저장소와 상호 작용할 수도 있지만, 동작의 핵심은 자체 프로세스 내에서 실행되고 전체 애플리케이션은 일반적으로 하나의 단위로 배포됩니다. 이러한 애플리케이션을 수평으로 확장해야 하는 경우 일반적으로 전체 애플리케이션이 여러 서버 또는 가상 머신에서 중복됩니다.

올인원 애플리케이션

애플리케이션 아키텍처에 허용되는 최소 프로젝트 수는 하나입니다. 이 아키텍처에서 애플리케이션의 전체 로직은 단일 프로젝트에 포함되고, 단일 어셈블리로 컴파일되고, 단일 단위로 배포됩니다.

새 ASP.NET Core 프로젝트는 Visual Studio에서 만들었든 아니면 명령줄에서 만들었든, 간단한 "올인원" 모놀리스로 시작됩니다. 프레젠테이션, 비즈니스 및 데이터 액세스 논리를 포함하여 애플리케이션의 모든 동작을 포함합니다. 그림 5-1은 단일 프로젝트 앱의 파일 구조를 보여줍니다.

A single project ASP.NET Core app

그림 5-1. 단일 프로젝트 ASP.NET Core 앱.

단일 프로젝트 시나리오에서는 폴더를 사용하여 문제를 격리합니다. 기본 템플릿에는 데이터 및 서비스에 대한 추가 폴더 외에도 Models, Views 및 Controllers의 MVC 패턴 책임에 대한 별도의 폴더가 포함됩니다. 이 정렬에서 프레젠테이션 세부 정보는 되도록이면 Views 폴더로 제한되어야 하고, 데이터 액세스 구현 세부 정보는 Data 폴더에 보관되는 클래스로 제한되어야 합니다. 비즈니스 논리는 Models 폴더 내부의 서비스 및 클래스에 상주해야 합니다.

단일 프로젝트 모놀리식 솔루션은 간단하지만 몇 가지 단점이 있습니다. 프로젝트의 크기와 복잡성이 증가하면 파일 및 폴더의 수도 계속해서 함께 증가합니다. 사전순으로 그룹화되지 않은 여러 폴더에 UI(사용자 인터페이스) 문제(모델, 보기, 컨트롤러)가 있습니다. 이 문제는 Filters 또는 ModelBinders 같은 UI 수준의 구성이 자체 폴더에 추가될 때에만 악화됩니다. 비즈니스 논리는 Models 폴더와 Services 폴더 사이에 흩어져 있으며, 어떤 폴더의 어떤 클래스가 무엇에 의존해야 하는지 명확한 표시가 없습니다. 이와 같이 프로젝트 수준에서 깔끔하게 정리되지 않기 때문에 스파게티 코드로 이어지는 경우가 자주 있습니다.

이 문제를 해결하기 위해 종종 애플리케이션은 각 프로젝트가 애플리케이션의 특정 레이어에 상주하는 것으로 간주되는 다중 프로젝트 솔루션으로 발전합니다.

레이어란 무엇입니까?

증가하는 애플리케이션 복잡성을 관리하는 한 가지 방법은 애플리케이션의 책임이나 문제에 따라 애플리케이션을 나누는 것입니다. 이 방법은 문제 분리 원칙을 따르며, 개발자가 특정 기능이 어디에 구현되는지 쉽게 찾을 수 있도록 증가하는 코드베이스를 정리하는 데 도움이 됩니다. 하지만 계층화 아키텍처는 코드 구성 이상의 여러 가지 장점이 있습니다.

코드를 여러 레이어로 구성하면 공통 하위 수준 기능을 애플리케이션 전체에서 재사용할 수 있습니다. 이러한 재사용은 작성할 코드의 양이 줄어들고 애플리케이션에서 DRY(반복 금지) 원칙에 따라 단일 구현을 표준화할 수 있다는 장점이 있습니다.

계층화 아키텍처를 사용하면 애플리케이션에서 다른 레이어와 통신할 수 있는 레이어를 제한할 수 있습니다. 이 아키텍처는 캡슐화를 달성하는 데 도움이 됩니다. 한 레이어가 변경되거나 대체되면 해당 레이어와 함께 작동하는 레이어만 영향을 받습니다. 어떤 레이어가 어떤 레이어에 종속되는지를 제한하면 단일 변경 내용이 전체 애플리케이션에 영향을 미치지 않도록 변경의 영향을 줄일 수 있습니다.

레이어(및 캡슐화)를 사용하면 애플리케이션 내에서 훨씬 간단하게 기능을 대체할 수 있습니다. 예를 들어 애플리케이션에서 처음에는 지속성을 위해 자체 SQL Server 데이터베이스를 사용하지만, 나중에는 클라우드 기반 지속성 전략 또는 웹 API 뒤에 있는 것을 사용할 수 있습니다. 애플리케이션이 논리적 계층 내에서 지속성 구현을 적절하게 캡슐화한 경우 해당 SQL Server 관련 계층을 동일한 퍼블릭 인터페이스를 구현하는 새 계층으로 바꿀 수 있습니다.

향후 요구 사항의 변화에 따라 구현을 교환할 가능성 외에도, 애플리케이션 레이어를 사용하면 테스트 목적으로 구현을 쉽게 교환할 수 있습니다. 애플리케이션의 실제 데이터 레이어 또는 UI 레이어에 대해 작동하는 테스트를 작성하는 대신, 테스트 시 이러한 레이어를 요청에 대한 알려진 응답을 제공하는 가짜 구현으로 바꿀 수 있습니다. 이 방법을 사용하면 일반적으로 애플리케이션의 실제 인프라에 대해 테스트를 실행할 때보다 테스트를 훨씬 쉽게 작성하고 훨씬 빠르게 실행할 수 있습니다.

논리적 레이어링은 엔터프라이즈 소프트웨어 애플리케이션에서 코드 구성을 향상하는 일반적인 방법이며, 코드를 레이어로 구성할 수 있는 여러 가지 방법이 있습니다.

참고

레이어는 애플리케이션 내부의 논리적 분리를 나타냅니다. 애플리케이션 논리가 별도의 서버 또는 프로세스에 물리적으로 분산된 경우 이러한 별도의 실제 배포 대상을 계층이라고 부릅니다. N 레이어 애플리케이션을 단일 계층에 배포할 수 있으며, 이는 매우 일반적입니다.

기존의 "N 레이어" 아키텍처 애플리케이션

그림 5-2는 애플리케이션 논리를 레이어로 구성하는 가장 일반적인 예입니다.

Typical application layers

그림 5-2. 일반적인 애플리케이션 레이어.

이러한 레이어를 종종 줄여서 UI, BLL(비즈니스 논리 레이어) 및 DAL(데이터 액세스 레이어)이라고 합니다. 이 아키텍처를 사용하면 사용자는 BLL하고만 상호 작용하는 UI 레이어를 통해 요청을 만듭니다. 그러면 BLL은 데이터 액세스 요청을 위해 DAL을 호출할 수 있습니다. UI 레이어는 DAL에 대한 요청을 직접 만들면 안 되고, 다른 방법을 통해 지속성과 직접 상호 작용해서도 안 됩니다. 마찬가지로, BLL은 DAL을 통해서만 지속성과 상호 작용해야 합니다. 이러한 방식으로 레이어마다 잘 알려진 책임이 있습니다.

이 기존 레이어링 방식의 단점 중 하나는 컴파일 시간 종속성이 위에서 아래로 흐른다는 점입니다. 즉, UI 레이어가 BLL에 종속되고, BLL은 DAL에 종속됩니다. 다시 말해서, 일반적으로 애플리케이션에서 가장 중요한 논리를 보관하는 BLL이 데이터 액세스 구현 세부 정보(및 존재하는 데이터베이스)에 종속됩니다. 이러한 아키텍처에서 비즈니스 논리를 테스트하기가 어려운 경우가 종종 있으며, 테스트 데이터베이스가 필요합니다. 다음 섹션에서 설명드리겠지만, 종속성 반전 원칙을 사용하여 이 문제를 해결할 수 있습니다.

그림 5-3은 애플리케이션을 책임(또는 레이어)에 따라 세 개 프로젝트로 분할하는 예제 솔루션을 보여줍니다.

A simple monolithic application with three projects

그림 5-3. 세 개 프로젝트가 있는 간단한 모놀리식 애플리케이션입니다.

이 애플리케이션은 구성을 목적으로 여러 프로젝트를 사용하지만 여전히 단일 단위로 배포되고 그 클라이언트는 단일 웹앱과 상호 작용합니다. 따라서 배포 프로세스가 매우 간단합니다. 그림 5-4는 Azure를 사용하여 이러한 앱을 호스팅하는 방법을 보여 줍니다.

Simple deployment of Azure Web App

그림 5-4. Azure 웹앱의 간단한 배포

애플리케이션 요구 사항이 증가하면 좀 더 복잡하고 강력한 배포 솔루션이 필요할 수 있습니다. 그림 5-5는 추가 기능을 지원하는 좀 더 복잡한 배포 계획의 예를 보여줍니다.

Deploying a web app to an Azure App Service

그림 5-5. Azure App Service에 웹앱 배포

내부적으로 책임을 기반으로 이 프로젝트를 여러 프로젝트로 정리하면 애플리케이션의 유지 관리 용이성이 향상됩니다.

이 단위를 수직 확장 또는 수평 확장하여 클라우드 기반 주문형 확장성의 장점을 누릴 수 있습니다. 수직 확장이란 앱을 호스팅하는 서버에 추가 CPU, 메모리, 디스크 공간 또는 기타 리소스를 추가하는 것을 의미합니다. 수평 확장이란 물리적 서버,가상 머신 또는 컨테이너인지와 상관 없이 서버의 추가 인스턴스를 추가하는 것을 의미합니다. 앱이 여러 인스턴스에서 호스트되는 경우 부하 분산 장치를 사용하여 개별 앱 인스턴스에 요청을 할당합니다.

Azure에서 웹 애플리케이션을 확장하는 가장 간단한 방법은 애플리케이션의 App Service 계획에서 수동으로 확장하는 것입니다. 그림 5-6은 앱에 서비스를 제공하는 인스턴스 수를 구성하는 적절한 Azure 대시보드 화면을 보여줍니다.

App Service Plan scaling in Azure

그림 5-6. Azure에서 App Service 계획의 크기를 조정합니다.

클린 아키텍처

종속성 반전 원칙과 DDD(도메인 중심 디자인) 원칙을 따르는 애플리케이션은 비슷한 아키텍처에 도달하는 경향이 있습니다. 이 아키텍처는 수년 동안 여러 가지 이름으로 불렸습니다. 첫 번째 이름 중 하나는 육각형 아키텍처이고, 그 다음은 포트 및 어댑터(Ports-and-Adapters)였습니다. 최근에는 양파형 아키텍처 또는 클린 아키텍처로 불렸습니다. 두 번째 이름인 클린 아키텍처는 이 eBook에서 이 아키텍처에 대한 이름으로 사용됩니다.

eShopOnWeb 참조 애플리케이션은 프로젝트에 코드를 구성하는 데 클린 아키텍처 접근 방법을 사용합니다. ardalis/cleanarchitecture GitHub 리포지토리에서 자체 ASP.NET Core 솔루션의 시작 지점으로 사용할 수 있는 솔루션 템플릿을 찾거나 NuGet에서 템플릿을 설치하면 됩니다.

클린 아키텍처는 비즈니스 논리와 애플리케이션 모델을 애플리케이션의 중심에 놓습니다. 비즈니스 논리가 데이터 액세스 또는 다른 인프라 고려 사항에 따라 달라지는 것이 아니라 이 종속성을 반전하여 인프라 및 구현 세부 사항이 애플리케이션 코어에 따라 달라집니다. 이 기능은 Application Core에서 추상화 또는 인터페이스를 정의하여 달성된 후 인프라 계층에서 정의된 형식에 따라 구현됩니다. 이 아키텍처를 시각화하는 일반적인 방법은 양파와 비슷한 일련의 동심원을 사용하는 것입니다. 그림 5-7은 이 아키텍처 표현 스타일의 예를 보여 줍니다.

Clean Architecture; onion view

그림 5-7. 클린 아키텍처; 양파형 보기

이 다이어그램에서 종속성은 가장 안쪽에 있는 원을 향해 흐릅니다. Application Core는 이 다이어그램의 중심에 있는 해당 위치에서 해당 이름을 사용합니다. 또한 Application Core가 다른 애플리케이션 계층에 종속되지 않음을 다이어그램에서 확인할 수 있습니다. 정중앙에는 애플리케이션의 엔터티 및 인터페이스가 있습니다. 그 바로 바깥에는(여전히 Application Core 안에 있지만) 일반적으로 내부 원에 정의된 인터페이스를 구현하는 도메인 서비스가 있습니다. Application Core 밖에서는 UI 및 인프라 계층이 Application Core에 종속되지만 서로 종속되지는 않습니다(반드시).

그림 5-8은 UI와 다른 레이어 간에 종속성을 좀 더 잘 반영하는 더 일반적인 수평 방향 레이어 다이어그램입니다.

Clean Architecture; horizontal layer view

그림 5-8. 클린 아키텍처; 수평 방향 레이어 보기

실선 화살표는 컴파일 시간 종속성을 나타내고, 파선 화살표는 런타임 전용 종속성을 나타냅니다. 클린 아키텍처를 사용하면 UI 레이어는 컴파일 시 Application Core에서 정의된 인터페이스와 함께 작동하며, 인프라 계층에 정의된 구현 형식에 대해서는 모르는 것이 가장 좋습니다. 하지만 런타임 시 앱이 실행되려면 이러한 구현 형식이 필요하며, 따라서 구현 형식이 있어야 하고 종속성 주입을 통해 Application Core 인터페이스에 연결되어야 합니다.

그림 5-9는 이러한 권장 사항에 따라 빌드할 때의 ASP.NET Core 애플리케이션 아키텍처를 자세히 보여줍니다.

ASP.NET Core architecture diagram following Clean Architecture

그림 5-9. 클린 아키텍처를 따르는 ASP.NET Core 아키텍처 다이어그램.

Application Core는 인프라에 종속되지 않기 때문에 이 레이어에 대한 자동화된 단위 테스트를 작성하기가 매우 쉽습니다. 그림 5-10 및 5-11은 테스트가 이 아키텍처와 얼마나 잘 맞는지를 보여줍니다.

UnitTestCore

그림 5-10. 격리 상태로 Application Core 단위 테스트.

IntegrationTests

그림 5-11. 외부 종속성으로 인프라 구현 통합 테스트.

UI 레이어는 인프라 프로젝트에 정의된 형식에 조금도 종속되지 않으므로 테스트를 쉽게 하기 위해서든 아니면 애플리케이션 요구 사항의 변화에 대응하기 위해서든 구현을 교체하기가 매우 쉽습니다. ASP.NET Core는 종속성 주입을 기본적으로 사용하고 지원하기 때문에 특수 모놀리식 애플리케이션을 만드는 가장 적합한 방식은 이 아키텍처입니다.

모놀리식 애플리케이션의 경우 Application Core, 인프라 및 UI 프로젝트는 모두 단일 애플리케이션으로 실행됩니다. 런타임 애플리케이션 아키텍처는 그림 5-12처럼 보일 수 있습니다.

ASP.NET Core Architecture 2

그림 5-12. 샘플 ASP.NET Core 앱의 런타임 아키텍처.

클린 아키텍처에서 코드 구성

클린 아키텍처 솔루션에서는 프로젝트마다 명확한 책임이 있습니다. 따라서 각 프로젝트에 속하는 특정 형식이 있으며 해당 프로젝트에서 이러한 형식에 해당하는 폴더를 자주 볼 수 있습니다.

애플리케이션 코어

Application Core는 비즈니스 모델을 보관하며, 비즈니스 모델에는 엔터티, 서비스 및 인터페이스가 포함됩니다. 이러한 인터페이스는 데이터 액세스, 파일 시스템 액세스, 네트워크 호출 등의 인프라를 사용하여 수행되는 작업의 추상화를 포함합니다. 경우에 따라 이 레이어에 정의된 서비스 또는 인터페이스가 UI 또는 인프라에 종속되지 않은 비 엔터티 형식과 함께 작동해야 합니다. 이러한 동작은 간단한 DTO(데이터 전송 개체)로 정의할 수 있습니다.

Application Core 형식
  • 엔터티(유지되는 비즈니스 모델 클래스)
  • 집계(엔터티 그룹)
  • 인터페이스
  • Domain Services
  • 사양
  • 사용자 지정 예외 및 가드 절
  • 도메인 이벤트 및 처리기

인프라

인프라 프로젝트는 일반적으로 데이터 액세스 구현을 포함합니다. 일반적인 ASP.NET Core 웹 애플리케이션에서는 EF(Entity Framework) DbContext, 정의된 EF Core Migration 개체 및 데이터 액세스 구현 클래스가 해당 구현에 포함됩니다. 데이터 액세스 구현 코드를 추상화하는 가장 일반적인 방법은 리포지토리 디자인 패턴을 사용하는 것입니다.

인프라 프로젝트는 데이터 액세스 구현 외에도 인프라 문제와 상호 작용해야 하는 서비스 구현을 포함해야 합니다. 이러한 서비스는 Application Core에 정의된 인터페이스를 구현해야 하며, 따라서 인프라에 Application Core 프로젝트에 대한 참조가 있어야 합니다.

인프라 형식
  • EF Core 형식(DbContext, Migration)
  • 데이터 액세스 구현 형식(리포지토리)
  • 인프라 관련 서비스(예: FileLogger 또는 SmtpNotifier)

UI 계층

ASP.NET Core MVC 애플리케이션의 사용자 인터페이스 레이어는 애플리케이션의 진입점입니다. 이 프로젝트는 Application Core 프로젝트를 참조해야 하고, 그 형식은 Application Core에 정의된 인터페이스를 통해 인프라와 엄격하게 상호 작용해야 합니다. 어느 인프라 계층 형식의 직접 인스턴스화 또는 정적 호출도 UI 레이어에서 허용되어서는 안 됩니다.

UI 계층 형식
  • 컨트롤러
  • 사용자 지정 필터
  • 사용자 지정 미들웨어
  • 보기
  • ViewModels
  • Startup 클래스

Startup 클래스 또는 Program.cs 파일은 애플리케이션을 구성하고 구현 형식을 인터페이스에 연결하는 작업을 담당합니다. 이 논리를 수행하는 곳을 앱의 컴퍼지션 루트라고 하며, 이곳에서는 런타임 시 종속성 주입이 정상적으로 작동합니다.

참고

앱을 시작하는 동안 종속성 주입을 연결하려면 UI 계층 프로젝트가 인프라 프로젝트를 참조해야 할 수 있습니다. 이 종속성은 제거할 수 있으며, 가장 쉬운 방법은 어셈블리에서의 형식 로드를 기본적으로 지원하는 사용자 지정 DI 컨테이너를 사용하는 것입니다. 이 샘플의 목적에 따른 가장 간단한 방법은 UI 프로젝트가 인프라 프로젝트를 참조하도록 허용하는 것입니다(그러나 개발자는 인프라 프로젝트에서의 형식에 대한 실제 참조를 앱의 컴퍼지션 루트로 제한해야 합니다).

모놀리식 애플리케이션 및 컨테이너

단일 모놀리식 배포 기반 웹 애플리케이션 또는 서비스를 빌드하고 컨테이너로 배포할 수 있습니다. 애플리케이션 내에서는 모놀리식이 아닐 수 있지만 여러 라이브러리, 구성 요소 또는 레이어로 구성됩니다. 외부적으로는 단일 프로세스, 단일 웹 애플리케이션 또는 단일 서비스가 있는 단일 컨테이너입니다.

이 모델을 관리하려면 애플리케이션을 나타내는 단일 컨테이너를 배포합니다. 크기를 조정하려면 부하 분산 장치 앞에 여러 복사본을 추가하면 됩니다. 단일 컨테이너 또는 VM에서 단일 배포를 관리하면 단순성을 제공합니다.

Figure 5-13

그림 5-13에서 보여준 대로 각 컨테이너 내에 여러 구성 요소/라이브러리 또는 내부 레이어를 포함할 수 있습니다. 하지만 이 모놀리식 패턴은 “컨테이너는 한 가지 작업을 하나의 프로세스에서 수행합니다” 라는 컨테이너 원칙과 충돌할 수 있습니다.

이 방법의 단점은 애플리케이션이 커지면 크기를 조정해야 한다는 것입니다. 전체 애플리케이션의 크기를 조정하는 경우에는 문제가 되지 않습니다. 그러나 대부분의 경우 애플리케이션의 일부는 크기 조정이 필요하고, 나머지 구성 요소는 활용도가 떨어집니다.

일반적인 전자상거래를 예로 들자면, 크기 조정이 필요할 가능성이 높은 부분은 제품 정보 구성 요소입니다. 제품을 구매하는 고객보다 제품을 살펴보는 고객이 훨씬 많습니다. 많은 고객이 결제 파이프라인을 사용하지 않고 자신의 바구니를 사용합니다. 적은 수의 고객이 주석을 추가하거나 자신의 구매 기록을 봅니다. 또한 얼마 되지 않는 직원들이 한 지역에서 근무하며 콘텐츠와 마케팅 캠페인을 관리해야 합니다. 모놀리식 디자인을 확장하면 모든 코드가 여러 번 배포됩니다.

하지만 “모든 것을 확장”하는 문제 외에도 단일 구성 요소를 변경하려면 전체 애플리케이션을 모두 다시 테스트하고 전체 인스턴스를 모두 다시 배포해야 합니다.

모놀리식 접근 방식이 주로 사용되며, 많은 조직에서 이 아키텍처 접근 방법을 개발 중입니다. 좋은 결과를 얻은 곳도 많지만, 한계에 부딪힌 곳도 많습니다. SOA(서비스 지향 아키텍처)를 빌드하기에는 도구 및 인프라 사용 방법이 너무 어려웠고 앱이 커지기 전에는 필요성을 느끼지도 않았기 때문에 많은 조직에서 이 모델을 사용하여 애플리케이션을 디자인했습니다. 모놀리식 방식의 한계에 도달한 것 같으면 앱을 분할하여 컨테이너를 보다 효율적으로 활용할 수 있으며, 그 다음 논리적 단계는 마이크로 서비스가 될 수도 있습니다.

Figure 5-14

각 인스턴스의 전용 VM을 사용하여 Microsoft Azure에 모놀리식 애플리케이션을 배포할 수 있습니다. Azure Virtual Machine Scale Sets를 사용하여 VM 크기를 쉽게 조정할 수 있습니다. Azure App Services는 VM을 관리하지 않고 모놀리식 애플리케이션을 실행하고 인스턴스 크기를 쉽게 조정할 수 있습니다. Azure App Services는 배포를 단순화할 뿐만 아니라 Docker 컨테이너의 단일 인스턴스를 실행할 수 있습니다. Docker를 사용하면 단일 VM을 Docker 호스트로 배포하고 여러 인스턴스를 실행할 수 있습니다. 그림 5-14처럼 Azure 분산 장치를 사용하여 크기 조정을 관리할 수 있습니다.

기존의 배포 기술로 다양한 호스트에 대한 배포를 관리할 수 있습니다. Docker 호스트는 docker run 같은 명령을 사용하여 수동으로 관리하거나 CD(지속적인 업데이트) 파이프라인 같은 자동화를 통해 관리할 수 있습니다.

컨테이너로 배포된 모놀리식 애플리케이션

모놀리식 애플리케이션 배포 관리에 컨테이너를 사용하면 이점이 있습니다. 컨테이너 인스턴스의 크기를 확장하는 것은 추가 VM을 배포하는 것보다 훨씬 쉽고 빠릅니다. 가상 머신 확장 집합을 사용하여 VM 크기를 조정하는 경우에도 생성될 때까지 시간이 걸립니다. 앱 인스턴스로 배포되는 경우 앱 구성은 VM의 일부로 관리됩니다.

Docker 이미지로 업데이트를 배포하는 것이 훨씬 더 빠르고 네트워크 효율적입니다. Docker 이미지는 일반적으로 몇 초 내에 시작되어 롤아웃 속도가 향상됩니다. Docker 인스턴스를 중지하는 방법은 아주 간단합니다. docker stop 명령을 실행하면 일반적으로 몇 초 내에 완료됩니다.

컨테이너는 기본적으로 변경할 수 없도록 설계되므로 손상된 VM에 관해 걱정할 필요가 없는 한편, 업데이트 스크립트는 디스크에 남아 있는 일부 특정 구성 또는 파일을 고려하지 않을 수 있습니다.

간단한 웹 애플리케이션의 모놀리식 배포에는 Docker 컨테이너를 사용할 수 있습니다. 이 방법은 연속 통합과 지속적인 배포 파이프라인을 개선하며 프로덕션에 배포를 달성하는 데에도 도움이 됩니다. 더 이상 “내 머신에서는 되는데 프로덕션에서는 되지 않는” 문제가 발생하지 않습니다.

마이크로 서비스 기반 아키텍처에는 다양한 이점이 있지만 그에 따른 복잡성도 고려해야 합니다. 혜택에 비해 비용이 더 많이 들어서, 단일 컨테이너 또는 소수의 컨테이너에서 실행되는 모놀리식 배포 애플리케이션을 사용하는 것이 더 나은 경우도 있습니다.

모놀리식 애플리케이션은 잘 분리된 마이크로 서비스로 쉽게 분할되지 않을 수 있습니다. 마이크로 서비스는 복원력이 우수한 애플리케이션을 제공하기 위해 서로 독립적으로 작업을 수행해야 합니다. 애플리케이션의 독립된 기능 조각을 제공할 수 없는 경우 애플리케이션을 분리하면 복잡성만 더할 뿐입니다.

애플리케이션의 기능을 독립적으로 확장할 필요가 없을 수 있습니다. 많은 애플리케이션에서는 단일 인스턴스를 초과하여 확장해야 하는 경우 전체 인스턴스를 복제하는 비교적 단순한 과정을 통해 수행할 수 있습니다. 추가 작업을 통해 애플리케이션을 불연속 서비스로 분리하더라도 애플리케이션의 전체 인스턴스 스케일링이 간단하고 비용 효율적인 경우 이점이 매우 적습니다.

또한 애플리케이션의 개발 초기에는 자연적인 기능 경계를 명확하게 알지 못할 수 있습니다. 최소 기능 제품을 개발할 때는 자연적인 분리가 아직 발생하지 않을 수 있습니다. 이러한 조건 중 일부는 일시적일 수 있습니다. 모놀리식 애플리케이션을 만들어 시작하고 나중에 일부 기능을 분리하여 마이크로 서비스로 개발하고 배포할 수 있습니다. 애플리케이션의 문제 영역에는 다른 조건이 필요할 수 있습니다. 즉, 애플리케이션은 여러 마이크로 서비스로 분리되지 않을 수 있습니다.

애플리케이션을 다수의 불연속 프로세스로 분리하면 오버헤드도 발생합니다. 기능을 다른 프로세스로 분리하는 작업이 더 어려워지며 통신 프로토콜이 더 복잡해집니다. 서비스 간에 메서드 호출 대신 비동기적인 통신을 사용해야 합니다. 마이크로 서비스 아키텍처로 이동하면 이벤트 버스 처리, 메시지 복원력 및 다시 시도, 최종 일관성 등 eShopOnContainers 애플리케이션의 마이크로 서비스 버전에서 구현된 빌드 블록을 많이 추가해야 합니다.

훨씬 더 간단한 eShopOnWeb 참조 애플리케이션은 단일 컨테이너 모놀리식 컨테이너 사용을 지원합니다. 애플리케이션에는 기존 MVC 보기, 웹 API 및 Razor Pages를 포함하는 하나의 웹 애플리케이션이 포함됩니다. 원한다면 별도의 API 프로젝트를 실행해야 하는 애플리케이션의 Blazor 기반 관리자 구성 요소를 실행할 수도 있습니다.

이 애플리케이션은 docker-compose builddocker-compose up 명령을 사용하여 솔루션 루트에서 시작할 수 있습니다. 이 명령은 웹 프로젝트의 루트에서 찾은 Dockerfile을 사용하여 웹 인스턴스에 대한 컨테이너를 구성하며, 특정 포트에서 해당 컨테이너를 실행합니다. GitHub에서 이 애플리케이션에 대한 소스를 다운로드하고 로컬에서 실행할 수 있습니다. 이 모놀리식 애플리케이션도 컨테이너 환경에서의 배포를 통해 이점을 얻습니다.

첫째, 컨테이너화된 배포는 애플리케이션의 모든 인스턴스가 동일한 환경에서 실행되는 것을 의미합니다. 이 방법에는 초기 테스트와 개발이 이루어지는 개발자 환경이 포함됩니다. 개발 팀은 프로덕션 환경과 일치하는 컨테이너화된 환경에서 애플리케이션을 실행할 수 있습니다.

둘째, 컨테이너화된 애플리케이션은 더욱 저렴한 비용으로 스케일 아웃됩니다. 컨테이너 환경에서는 기존의 VM 환경보다 더 많은 리소스를 공유할 수 있습니다.

마지막으로, 애플리케이션을 컨테이너화하면 비즈니스 논리와 스토리지 서버 사이에서 강제 분할이 발생합니다. 애플리케이션이 확장되면 여러 컨테이너는 모두 단일 실제 스토리지 매체를 사용하게 됩니다. 이 스토리지 미디엄은 일반적으로 SQL Server 데이터베이스를 실행하는 고가용성의 서버입니다.

Docker 지원

eShopOnWeb 프로젝트는 .NET에서 실행됩니다. 따라서 Linux 기반 또는 Windows 기반 컨테이너에서 실행할 수 있습니다. Docker 배포에서는 SQL Server에 대해서 동일한 호스트 유형을 사용할 수 있습니다. 사람들은 Linux 기반 컨테이너를 선호하며 여기에서는 더 작은 공간을 사용할 수 있습니다.

솔루션 탐색기에서 프로젝트를 마우스 오른쪽 단추로 클릭하고 추가>Docker 지원을 선택하면 Visual Studio 2017 이상을 사용하여 기존 애플리케이션에 Docker 지원을 추가할 수 있습니다. 이 단계를 통해 필요한 파일을 추가하고 해당 파일을 사용하도록 프로젝트를 수정합니다. 현재 eShopOnWeb 샘플에는 이러한 파일이 이미 준비되어 있습니다.

솔루션 수준의 docker-compose.yml 파일에는 빌드할 이미지 및 시작할 컨테이너에 대한 정보가 포함됩니다. 이 파일을 통해 docker-compose 명령을 사용하여 동시에 여러 애플리케이션을 시작할 수 있습니다. 이 경우에는 웹 프로젝트를 시작하기만 합니다. 별도 데이터베이스 컨테이너와 같은 종속성을 구성하는 데 이를 사용할 수 있습니다.

version: '3'

services:
  eshopwebmvc:
    image: eshopwebmvc
    build:
      context: .
      dockerfile: src/Web/Dockerfile
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
    ports:
      - "5106:5106"

networks:
  default:
    external:
      name: nat

docker-compose.yml 파일은 Web 프로젝트에서 Dockerfile을 참조합니다. Dockerfile은 사용할 기본 컨테이너 및 애플리케이션의 구성 방식을 지정하는 데 사용됩니다. Web' Dockerfile:

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /app

COPY *.sln .
COPY . .
WORKDIR /app/src/Web
RUN dotnet restore

RUN dotnet publish -c Release -o out

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS runtime
WORKDIR /app
COPY --from=build /app/src/Web/out ./

ENTRYPOINT ["dotnet", "Web.dll"]

Docker 문제 해결

컨테이너화된 애플리케이션을 한 번 실행하고 나면 사용자가 실행을 중지할 때까지 계속 실행됩니다. docker ps 명령으로 실행 중인 컨테이너를 볼 수 있습니다. docker stop 명령을 사용하여 실행 중인 컨테이너를 중지하고 컨테이너 ID를 지정할 수 있습니다.

실행 중인 Docker 컨테이너는 포트로 바인딩될 수 있지만, 그렇지 않다면 개발 환경에서 사용해 볼 수도 있습니다. 실행 중인 Docker 컨테이너와 동일한 포트를 사용하여 애플리케이션을 실행 또는 디버깅하려고 하면, 서버가 해당 포트에 바인딩할 수 없다는 내용의 오류가 표시됩니다. 다시 한번 컨테이너를 중지하여 문제를 해결해야 합니다.

Visual Studio를 사용하여 애플리케이션에 Docker 지원을 추가하려는 경우 Docker Desktop이 실행되고 있는지 확인합니다. 마법사를 시작할 때 Docker Desktop이 실행되지 않은 경우 마법사가 올바르게 실행되지 않습니다. 또한 마법사는 올바른 Docker 지원을 추가하기 위해 현재 선택한 컨테이너를 검사합니다. Windows 컨테이너에 대한 지원을 추가하려는 경우 구성된 Windows 컨테이너에서 Docker Desktop이 실행되는 동안 마법사를 실행해야 합니다. Linux 컨테이너에 대한 지원을 추가하려는 경우 구성된 Linux 컨테이너를 통해 Docker가 실행되는 동안 마법사를 실행해야 합니다.

참조 – 공통 웹 아키텍처