PRD: .NET 5 → .NET 8 클라우드 네이티브 마이그레이션¶
워크숍 용도: 모듈 2 — 레거시 코드베이스 현대화를 위한 실습 예제입니다. agy 엄격 모드(strict mode), AGENTS.md를 사용한 에이전트 자체 온보딩, 서브에이전트 계획 수립, 그리고
ctrl+g플랜 편집을 시연합니다. 대상 리포지토리에는 GCP 클라우드 솔루션 아키텍트가 작성한 참조용modernization-prompt.md가 포함되어 있으며, 이는 마이그레이션 작업을 위한 프롬프트 엔지니어링의 완벽한 모범 사례입니다.
문제¶
부분적으로 업그레이드된 ASP.NET 애플리케이션(ContosoUniversity)은 Entity Framework 6 및 레거시 Generic Host 패턴(Startup.cs + Program.cs)과 함께 .NET 5에서 실행됩니다. .NET 5는 2022년 5월에 지원이 종료되었습니다. 이 앱은 SQL Server 기반의 EF6를 사용하지만 PostgreSQL과 함께 Cloud Run을 대상으로 해야 합니다. 컨테이너화, 구조화된 로깅 및 정상적인 종료 처리가 부족합니다.
비즈니스 동인¶
| 동인 | 영향 |
|---|---|
| 보안 규정 준수 | .NET 5는 EOL(수명 종료) 상태로 보안 패치가 제공되지 않습니다. 규정 준수 인증을 차단합니다. |
| 배포 속도 | 수동 VM 배포에서 Cloud Run에 3분 만에 컨테이너를 푸시하는 방식으로 변경 |
| 확장성 | Cloud Run은 트래픽에 따라 0에서 N개의 인스턴스로 자동 확장됩니다. |
| 비용 | Windows Server 라이선스 제거 — Cloud Run의 Linux 컨테이너는 비용이 약 70% 더 저렴합니다. |
| 데이터 계층 | 관리형 Cloud SQL을 위해 EF6/SQL Server에서 EF Core 8/PostgreSQL로 마이그레이션 |
대상 저장소¶
ContosoUniversity — Google Cloud .NET 현대화 데모
이 저장소는 자체 검증을 위해 레거시 앱(dotnet-migration-sample/)과 완료된 목표 상태(dotnet-migration-sample-modernized/)를 모두 제공합니다. 학생들은 오직 dotnet-migration-sample/ 디렉터리에서만 작업합니다.
git clone --depth 1 https://github.com/GoogleCloudPlatform/cloud-solutions.git
cd cloud-solutions/projects/dotnet-modernization-demo/dotnet-migration-sample
보너스 리소스: 저장소에는 GCP 팀에서 작성한 225줄 분량의 프로덕션 수준 마이그레이션 프롬프트인
modernization-prompt.md가 포함되어 있습니다. 마이그레이션 작업을 위한 프롬프트 엔지니어링을 학습하려면 에이전트의 접근 방식과 이 참조 자료를 비교해 보세요.
범위¶
포함 범위¶
- 대상 프레임워크를 .NET 5에서 .NET 8로 업그레이드
- 제네릭 호스트 패턴(
Startup.cs)을 최소 호스팅 API(WebApplication.CreateBuilder())로 교체 - Entity Framework 6을 Entity Framework Core 8로 마이그레이션
- 데이터베이스 공급자를 SQL Server에서 PostgreSQL(Npgsql)로 변경
- Cloud Run 호환 Dockerfile 및 Docker Compose 구성 생성
- 구조화된 로깅, PORT 바인딩 및 SIGTERM 정상 종료 구현
제외 범위¶
- 비즈니스 로직 변경 (충실한 1:1 기능 복제)
- 프런트엔드 재설계 (Razor 뷰는 그대로 유지하며 컴파일 가능 여부만 확인)
- 데이터베이스 스키마 변경 (EF Core는 동일한 스키마에 매핑되어야 함)
마이그레이션 체크리스트¶
0단계: 컨텍스트 엔지니어링 — 에이전트 자체 온보딩¶
마이그레이션 코드를 작성하기 전에, 에이전트는 코드베이스에 대한 자체적인 이해를 구축해야 합니다.
- [ ] 엄격한 모드 설정 — 조사 중 우발적인 파일 쓰기를 방지합니다:
- [ ] 코드베이스 조사:
Analyze the ContosoUniversity application. Map:
1. Current framework version and all NuGet dependencies
2. The Startup.cs/Program.cs hosting pattern
3. All System.Data.Entity (EF6) usage across DAL, controllers, and migrations
4. Configuration sources (appsettings.json, web.config remnants)
5. Google Cloud integrations (Diagnostics, logging)
- [ ] 분석을 기반으로 마이그레이션을 인식하는 AGENTS.md 생성
- [ ] 진행하기 전에 생성된 AGENTS.md를 검토 및 승인
- [ ] 1단계 전에 리뷰 요청 모드로 전환:
1단계: TFM 및 패키지 업그레이드¶
- [ ]
ContosoUniversity.csproj업데이트:<TargetFramework>net5.0</TargetFramework>→net8.0으로 변경 - [ ] 모든 NuGet 패키지를 .NET 8 호환 버전으로 업데이트:
Microsoft.AspNetCore.Mvc.NewtonsoftJson→ 8.0.xSystem.ComponentModel.Annotations→ 8.0.xSystem.Configuration.ConfigurationManager→ 8.0.xGoogle.Cloud.Diagnostics.AspNetCore→ 최신 8.0 호환 버전- [ ]
Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers패키지 제거 (더 이상 필요하지 않음) - [ ]
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>제거 및Properties/AssemblyInfo.cs삭제 - [ ]
dotnet restore실행 — 패키지 충돌 해결
2단계: 호스팅 현대화¶
- [ ]
Startup.cs+Program.cs(Generic Host 패턴)를 최소 호스팅 API로 교체:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
// ... service registration
var app = builder.Build();
// ... middleware pipeline
app.Run();
- [ ]
ConfigureServices()본문을 최상위builder.Services블록으로 이동 - [ ]
Configure()본문을 최상위app.Use*()파이프라인으로 이동 - [ ]
CreateHostBuilder비밀 구성 로딩을 새 패턴으로 마이그레이션 - [ ] Cloud Run을 위한 PORT 바인딩 구성:
app.Run("http://0.0.0.0:" + port) - [ ] SIGTERM 정상 종료 핸들러 추가
- [ ] 마이그레이션 완료 후
Startup.cs삭제
3단계: Entity Framework 6 → EF Core 8¶
- [ ]
EntityFramework6.4.4 패키지 제거 - [ ]
Microsoft.EntityFrameworkCore및Npgsql.EntityFrameworkCore.PostgreSQL8.0.x 추가 - [ ]
SchoolContext리팩터링: System.Data.Entity가져오기 교체 →Microsoft.EntityFrameworkCoreOnModelCreating에서DbModelBuilder교체 →ModelBuilderPluralizingTableNameConvention제거 → 명시적인.ToTable()호출 추가MapToStoredProcedures()제거 (EF Core에서 지원되지 않음)- 생성자
SchoolContext(string connectString) : base(connectString)교체 →SchoolContext(DbContextOptions<SchoolContext> options) : base(options) - [ ] DI에 DbContext 등록:
builder.Services.AddDbContext<SchoolContext>(options => options.UseNpgsql(...)) - [ ]
context.Database.EnsureCreated()를 사용하여SchoolInitializer.cs리팩터링 →DbInitializer.cs - [ ]
SchoolConfiguration.cs제거 (Database.SetInitializer<T>()는 EF6 전용임) - [ ]
SchoolInterceptorLogging.cs및SchoolInterceptorTransientErrors.cs(EF6 인터셉터) 제거 →ILoggerFactory를 통한 EF Core 로깅으로 교체 - [ ] 모든 EF6 마이그레이션 파일 삭제 (
Migrations/2014*.cs,Migrations/Configuration.cs) - [ ] 모든 컨트롤러를 업데이트하여
System.Data.Entity가져오기를 제거하고RetryLimitExceededException(EF6) 수정 → EF Core 동등 항목으로 교체 - [ ]
dotnet build실행 — 모든 컴파일 오류 수정
4단계: 컨테이너화 및 Cloud Run¶
- [ ] 다단계
Dockerfile생성:
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app .
USER 1000
EXPOSE 8080
ENTRYPOINT ["dotnet", "ContosoUniversity.dll"]
- [ ]
.dockerignore추가 (bin/,obj/,.git/제외) - [ ] PostgreSQL + 앱 서비스가 포함된
compose.yaml생성: pg_isready상태 확인이 있는 PostgreSQL 컨테이너- 환경 변수를 통한 연결 문자열이 있는 앱 컨테이너
version속성 없음 (Compose 사양에서 더 이상 사용되지 않음)- [ ] Cloud Logging을 위한 구조화된 JSON 로깅 구성:
builder.Logging.AddJsonConsole() - [ ]
docker build --check .실행 — 모든 Docker 빌드 검사 통과 - [ ]
docker compose up --build --detach실행 — 앱이 시작되고 데이터베이스가 초기화되는지 확인
5단계: 검증 및 테스트¶
- [ ]
dotnet build가 오류나 경고 없이 컴파일됨 - [ ] Docker 이미지가 Linux에서 빌드되고 실행됨 (Windows 컨테이너 아님)
- [ ] 컨테이너가 비루트 사용자(UID 1000)로 실행됨
- [ ] 모든 HTTP 엔드포인트가 올바르게 응답함 (CRUD 작업을 위한 GET, POST)
- [ ] 첫 실행 시 데이터베이스가 시드 데이터로 초기화됨
- [ ] 애플리케이션이 POST/DELETE 작업에 대해 위조 방지 토큰을 올바르게 처리함
- [ ] 구조화된 JSON 로그가
docker compose logs에 나타남 - [ ] 소스 코드에 연결 문자열이나 자격 증명이 없음
에이전트가 수행해야 할 작업¶
이 PRD는 에이전트의 다음 능력을 테스트하도록 설계되었습니다:
- 자체 컨텍스트 부트스트랩 — 시작하기 전에 엄격 모드(strict mode)와 코드베이스 조사를 사용하여 AGENTS.md를 작성합니다 (0단계).
- 레거시 패턴 이해 — EF6 관용구(
DbModelBuilder, 인터셉터,Database.SetInitializer)를 인식하고 이를 EF Core의 동등한 요소로 매핑합니다. - 단계별 계획 준수 — 실행하기 전에
ctrl+g를 사용하여 계획을 편집하고 승인합니다. - 기계적 리팩토링 수행 — EF6에서 EF Core로의 마이그레이션은 모든 컨트롤러와 모델 파일에 영향을 미칩니다.
- 자체 작업 검증 — 각 단계 후에
dotnet build및docker compose up을 실행합니다. - 단계가 잘못된 경우
/rewind사용 — 이것은 실패가 아니라 체크포인트입니다.
인수 조건¶
- [ ] 마이그레이션 컨텍스트를 담고 있는
AGENTS.md가 프로젝트 루트에 존재함 - [ ] .NET 8에서
dotnet build가 오류 없이 컴파일됨 - [ ] 코드베이스 어디에도
System.Data.Entityimport문이 남아있지 않음 - [ ]
Startup.cs가 없음 — 앱이Program.cs에서 최소 호스팅 API를 사용함 - [ ]
EntityFramework6.x 패키지가Microsoft.EntityFrameworkCore8.x로 완전히 대체됨 - [ ] Docker 이미지가 Linux에서 비루트 사용자로 빌드되고 실행됨
- [ ]
docker compose up이 앱과 PostgreSQL을 성공적으로 시작하고 데이터베이스를 시드함 - [ ] 소스 코드에 연결 문자열이나 자격 증명이 없음
- [ ] 애플리케이션이 콜드 스타트 후 2초 이내에 상태 확인(health check)에 응답함