-
[.NET 11] Native AOT 기본 활성화와 컨테이너 이미지 초경량화 세팅Microsoft .NET/ASP.Net & ASP.Net Core 2026. 11. 11. 11:58

.NET 11에서 SDK의 Native AOT CLI 호스트가 기본 활성화됐습니다. 애플리케이션 쪽에서는 여전히
PublishAot를 명시해야 하며, 컨테이너 발행에는 재현 가능한 이미지 다이제스트와 레이어 재사용이 추가됐습니다. 이 글은 ASP.NET Core 앱을 AOT로 게시하고 컨테이너 이미지를 최소 구성으로 만드는 절차입니다.절차
- .NET 11에서 기본이 된 것과 아닌 것 구분
- AOT 게시 설정
- 컨테이너 발행 설정
- 이미지 크기 축소 옵션
- 재현 가능한 빌드와 다이제스트 고정
- 실행 검증
- 실패하는 지점과 대응
1. 기본이 된 것과 아닌 것
dotnetCLI 호스트가 Native AOT로 빌드되어 기본 실행됩니다.dotnet --version,dotnet --info, 각 명령의--help,dotnet --cli-schema,dotnet sln list|migrate|remove는 관리형 런타임 없이 동작합니다.- 전역 도구·외부 명령 실행도 AOT 경로에서 프로세스를 띄우므로,
dotnet ef같은 명령에서 관리형 CLI 기동 시간(600~700ms)을 건너뜁니다. - MSBuild 서버가 기본으로 켜져 CLI 호출 사이에 상주합니다.
- 애플리케이션 AOT 게시는 기본이 아닙니다.
PublishAot=true를 프로젝트에 지정해야 합니다.
기본값을 끄는 환경 변수는 다음과 같습니다. CI에서 메모리·동시성이 문제가 될 때만 개별로 끕니다.
export DOTNET_CLI_ENABLEAOT=false # AOT CLI 호스트 비활성 export DOTNET_CLI_USE_MSBUILD_SERVER=false # MSBuild 서버 상주 비활성2. AOT 게시 설정
웹 API 최소 구성으로 시작합니다.
PublishAot와 런타임 식별자를 지정하는 것이 전부입니다.<PropertyGroup> <TargetFramework>net11.0</TargetFramework> <PublishAot>true</PublishAot> <RuntimeIdentifier>linux-x64</RuntimeIdentifier> <InvariantGlobalization>true</InvariantGlobalization> <StripSymbols>true</StripSymbols> </PropertyGroup>dotnet publish -c Release게시 결과는
bin/Release/net11.0/linux-x64/publish아래의 단일 네이티브 실행 파일입니다. 관리형 DLL이 없으므로 실행에는 .NET 런타임이 필요하지 않습니다..NET 11 SDK에서는 AOT 게시 시 전체 빌드를 생략하는 동작 변경이 있습니다. 게시 전에 별도로
dotnet build를 돌려 경고를 먼저 확인하는 편이 안전합니다.dotnet build -c Release # 트림·AOT 경고(IL2026, IL3050) 확인 dotnet publish -c Release3. 컨테이너 발행 설정
SDK의 컨테이너 발행을 쓰면 Dockerfile 없이 이미지를 만듭니다.
<PropertyGroup> <ContainerRepository>myregistry/myapi</ContainerRepository> <ContainerFamily>noble-chiseled</ContainerFamily> <ContainerBaseImage>mcr.microsoft.com/dotnet/runtime-deps:11.0-noble-chiseled</ContainerBaseImage> </PropertyGroup>dotnet publish -c Release /t:PublishContainerContainerBaseImage를 지정하지 않으면 SDK가 런타임에 맞는 기본 이미지를 고릅니다. AOT 게시에서는 런타임 DLL이 필요 없으므로runtime-deps계열이 기준입니다. chiseled 이미지는 셸과 패키지 관리자가 없어 공격면이 작습니다.레지스트리에 바로 올리려면 저장소를 지정하고 인증을 붙입니다.
docker login myregistry.example.com dotnet publish -c Release /t:PublishContainer \ -p:ContainerRegistry=myregistry.example.com \ -p:ContainerImageTag=1.0.04. 이미지 크기 축소 옵션
InvariantGlobalization=true: ICU 데이터를 제거합니다. 문화권별 정렬·형식 지정이 필요한 서비스에는 쓰지 않습니다.UseSystemResourceKeys=true: 프레임워크 예외 메시지를 리소스에서 빼고 짧은 키로 대체합니다. 로그 가독성이 떨어집니다.StripSymbols=true: 디버그 심볼을 산출물에서 제거합니다.IlcOptimizationPreference=Size: 속도 대신 크기를 우선합니다.EventSourceSupport=false: 진단 이벤트를 제거합니다. 관측 도구가 EventSource를 쓰면 끄지 않습니다.
크기 비교는 태그를 고정해 두고 측정합니다.
docker images myregistry/myapi --format '{{.Tag}}\t{{.Size}}'5. 재현 가능한 빌드와 다이제스트 고정
.NET 11 컨테이너 발행은
SOURCE_DATE_EPOCH를 기준으로 이미지 메타데이터의 타임스탬프를 고정해, 같은 입력이면 같은 다이제스트가 나오도록 지원합니다. 커밋 시각을 값으로 넘깁니다.export SOURCE_DATE_EPOCH=$(git log -1 --format=%ct) dotnet publish -c Release /t:PublishContainer -p:ContainerImageTag=1.0.0 docker inspect --format '{{index .RepoDigests 0}}' myregistry/myapi:1.0.0대상 매니페스트가 이미 있으면 중복 레이어 업로드를 건너뛰므로, 태그만 바꿔 다시 올리는 파이프라인의 푸시 시간이 줄어듭니다.
6. 실행 검증
- 이미지가 실행되는지 확인합니다.
- 셸이 없는 이미지이므로
docker exec로 내부를 뒤지는 방식은 쓰지 않습니다. - 네이티브 바이너리의 의존 라이브러리는 호스트에서 확인합니다.
docker run --rm -p 8080:8080 myregistry/myapi:1.0.0 curl -i http://localhost:8080/health # 네이티브 실행 파일의 링크 상태 확인 ldd bin/Release/net11.0/linux-x64/publish/MyApildd결과에not found가 있으면 컨테이너 베이스 이미지에 해당 라이브러리가 없다는 뜻입니다.runtime-deps계열을 쓰고 있는지, 배포 대상 배포판과 태그가 맞는지 확인합니다.7. 실패하는 지점과 대응
- 리플렉션 기반 직렬화, 동적 프록시, 런타임 코드 생성은 AOT에서 동작하지 않습니다. System.Text.Json은 source generator를 사용합니다.
- 오래된 라이브러리의
RequiresUnreferencedCode,RequiresDynamicCode경고는 게시 전에 정리합니다. - MVC 컨트롤러·Razor 기반 앱은 AOT 게시 대상이 아닙니다. Minimal API나 gRPC처럼 요청 파이프라인이 단순한 구성이 기준입니다.
- 크로스 컴파일은 플랫폼 링커가 필요합니다. Windows에서 linux-x64를 만들려면 크로스 툴체인이 준비돼야 하며, 여의치 않으면 CI 컨테이너에서 빌드합니다.
- 시작 시간은 줄지만 빌드 시간은 늘어납니다. 캐시가 없는 CI에서는 게시 단계가 병목이 되므로, AOT 산출물 캐시를 잡아 둡니다.
# CI에서 AOT 빌드할 때의 최소 예시 FROM mcr.microsoft.com/dotnet/sdk:11.0 AS build WORKDIR /src COPY . . RUN dotnet publish -c Release -r linux-x64 --self-contained \ -p:PublishAot=true -o /out FROM mcr.microsoft.com/dotnet/runtime-deps:11.0-noble-chiseled WORKDIR /app COPY --from=build /out/MyApi /app/MyApi EXPOSE 8080 ENTRYPOINT ["/app/MyApi"]정리
.NET 11에서 기본이 된 것은
dotnetCLI 호스트의 AOT 실행과 MSBuild 서버 상주이고, 애플리케이션 AOT는PublishAot를 지정해야 합니다. 컨테이너는runtime-depschiseled 베이스에 SDK 컨테이너 발행을 붙이고,InvariantGlobalization·UseSystemResourceKeys·StripSymbols로 크기를 줄인 뒤SOURCE_DATE_EPOCH로 다이제스트를 고정하면 됩니다.'Microsoft .NET > ASP.Net & ASP.Net Core' 카테고리의 다른 글
[ASP.NET Core] SignalR 분산 환경 구축: Redis 백플레인(Backplane)과 웹소켓 스케일아웃 (0) 2026.11.11 [ASP.NET Core] Serilog 구조화 로깅(Structured Logging)과 Seq 연동 실무 세팅 (0) 2026.11.11 [.NET 11] .NET 11 GA 정식 릴리즈 핵심 변경점과 실무 마이그레이션 가이드 (0) 2026.11.11 [ASP.NET Core] Swagger UI에 JWT 인증(Authorize) 추가하기 (0) 2026.11.10 [ASP.NET Core] CORS 오류 "blocked by CORS policy" 원인과 설정 (0) 2026.11.10