단일 파일 배포

모든 애플리케이션 종속 파일을 하나의 이진 파일로 묶으면 애플리케이션 개발자가 애플리케이션을 단일 파일로 배포할 수 있습니다. 단일 파일 배포는 프레임워크 종속 배포 모델자체 포함 애플리케이션에 모두 사용할 수 있습니다.

자체 포함 애플리케이션의 단일 파일 크기는 런타임 및 프레임워크 라이브러리를 포함하기 때문에 큽니다. .NET 6에서는 자르기 호환 애플리케이션의 전체 크기를 줄이기 위해 잘린 상태로 게시할 수 있습니다. 단일 파일 배포 옵션을 ReadyToRunTrim 게시 옵션과 함께 사용할 수 있습니다.

Important

Windows 7에서 단일 파일 앱을 실행하려면 .NET 런타임 6.0.3 이상을 사용해야 합니다.

샘플 프로젝트 파일

다음은 단일 파일 게시를 지정하는 샘플 프로젝트 파일입니다.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <PublishSingleFile>true</PublishSingleFile>
    <SelfContained>true</SelfContained>
    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
  </PropertyGroup>

</Project>

위 속성에는 다음과 같은 함수가 있습니다.

  • PublishSingleFile. 단일 파일 게시를 사용하도록 설정합니다. dotnet build 중에 단일 파일 경고도 사용하도록 설정합니다.
  • SelfContained. 앱이 독립형인지, 프레임워크 종속형인지 결정합니다.
  • RuntimeIdentifier. 대상 지정하는 OS 및 CPU 형식을 지정합니다. 기본적으로 <SelfContained>true</SelfContained>도 설정합니다.

단일 파일 앱은 항상 OS 및 아키텍처에 따라 다릅니다. Linux x64, Linux Arm64, Windows x64 등과 같은 각 구성에 대해 게시해야 합니다.

*.runtimeconfig.json*.deps.json과 같은 런타임 구성 파일은 단일 파일에 포함됩니다. 추가 구성 파일이 필요한 경우 단일 파일 옆에 배치할 수 있습니다.

단일 파일 앱 게시

dotnet publish 명령을 사용하여 단일 파일 애플리케이션을 게시합니다.

  1. <PublishSingleFile>true</PublishSingleFile>를 프로젝트 파일에 추가합니다.

    이 변경으로 인해 자체 포함 게시 시 단일 파일 앱이 생성됩니다. 빌드 중에 단일 파일 호환성 경고도 표시됩니다.

    <PropertyGroup>
        <PublishSingleFile>true</PublishSingleFile>
    </PropertyGroup>
    
  2. dotnet publish -r <RID>를 사용하여 특정 런타임 식별자에 대한 앱을 게시합니다.

    다음 예제에서는 Windows용 앱을 자체 포함 단일 파일 애플리케이션으로 게시합니다.

    dotnet publish -r win-x64

    다음 예제에서는 Linux용 앱을 프레임워크 종속 단일 파일 애플리케이션으로 게시합니다.

    dotnet publish -r linux-x64 --self-contained false

빌드 중에 파일 분석을 사용하도록 설정하려면 프로젝트 파일에 <PublishSingleFile>을 설정해야 하지만 다음 옵션을 dotnet publish 인수로 전달할 수도 있습니다.

dotnet publish -r linux-x64 -p:PublishSingleFile=true --self-contained false

자세한 내용은 .NET CLI를 사용하여 .NET Core 앱 게시를 참조하세요.

파일이 포함되지 않도록 제외

다음 메타데이터를 설정하면 특정 파일이 단일 파일에 포함되지 않도록 명시적으로 제외할 수 있습니다.

<ExcludeFromSingleFile>true</ExcludeFromSingleFile>

예를 들어, 일부 파일을 게시 디렉터리에 저장하지만 파일에 묶이지 않도록 하려면 다음을 수행합니다.

<ItemGroup>
  <Content Update="Plugin.dll">
    <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
    <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
  </Content>
</ItemGroup>

번들 내에 PDB 파일 포함

어셈블리의 PDB 파일은 아래 설정을 사용하여 어셈블리 자체(.dll)에 포함할 수 있습니다. 기호는 어셈블리의 일부이므로 애플리케이션의 일부이기도 합니다.

<DebugType>embedded</DebugType>

예를 들어 어셈블리의 프로젝트 파일에 다음 속성을 추가하여 해당 어셈블리에 PDB 파일을 포함합니다.

<PropertyGroup>
  <DebugType>embedded</DebugType>
</PropertyGroup>

기타 고려 사항

단일 파일 애플리케이션에는 기본적으로 번들로 제공되지 않고 애플리케이션과 함께 관련된 모든 PDB 파일이 있습니다. 빌드하는 프로젝트의 어셈블리 내부에 PDB를 포함하려면 DebugTypeembedded로 설정합니다. 번들 내에 PDB 파일 포함을 참조하세요.

관리되는 C++ 구성 요소는 단일 파일 배포에 적합하지 않습니다. 단일 파일과 호환되도록 C# 또는 관리되지 않는 다른 C++ 언어로 애플리케이션을 작성하는 것이 좋습니다.

네이티브 라이브러리

관리되는 DLL만 앱과 함께 단일 실행 파일로 번들됩니다. 앱이 시작되면 관리형 DLL이 추출되어 메모리에 로드되며 폴더로 추출되지 않습니다. 이 방식을 사용하면 관리되는 이진 파일이 단일 파일 번들에 포함되지만 코어 런타임 자체의 네이티브 이진 파일은 별도의 파일입니다.

추출을 위해 해당 파일을 포함하고 하나의 출력 파일을 가져오려면 IncludeNativeLibrariesForSelfExtract 속성을 true로 설정합니다.

IncludeAllContentForSelfExtract를 지정하면 실행 파일을 실행하기 전에 관리되는 어셈블리를 포함한 모든 파일이 추출됩니다. 이는 드물게 발생하는 애플리케이션 호환성 문제에 도움이 될 수 있습니다.

Important

추출을 사용하는 경우 앱이 시작되기 전에 파일이 디스크에 추출됩니다.

  • DOTNET_BUNDLE_EXTRACT_BASE_DIR 환경 변수가 경로로 설정된 경우 파일은 해당 경로 아래의 디렉터리에 추출됩니다.
  • 그렇지 않고 Linux 또는 macOS에서 실행 중인 경우 파일은 $HOME/.net 아래의 디렉터리에 추출됩니다.
  • Windows에서 실행하는 경우 파일은 %TEMP%/.net 아래의 디렉터리에 추출됩니다.

변조를 방지하려면 다른 권한을 가진 사용자나 서비스가 이러한 디렉터리에 쓸 수 없어야 합니다. 대부분의 Linux 및 macOS 시스템에서는 /tmp 또는 /var/tmp를 사용하지 마세요.

참고 항목

systemd와 같은 일부 Linux 환경에서는 $HOME이 정의되지 않았기 때문에 기본 추출이 작동하지 않습니다. 이러한 경우에는 $DOTNET_BUNDLE_EXTRACT_BASE_DIR을 명시적으로 설정하는 것이 좋습니다.

systemd의 경우 좋은 대안은 서비스 단위 파일에서 DOTNET_BUNDLE_EXTRACT_BASE_DIR%h/.net으로 정의하는 것입니다. 그러면 서비스를 실행하는 계정에 대해 systemd$HOME/.net으로 올바르게 확장됩니다.

[Service]
Environment="DOTNET_BUNDLE_EXTRACT_BASE_DIR=%h/.net"

API 비호환성

일부 API는 단일 파일 배포와 호환되지 않습니다. 애플리케이션이 이러한 API를 사용하는 경우 수정이 필요할 수 있습니다. 사용 중인 타사 프레임워크나 패키지에도 이러한 API 중 하나가 사용될 수 있으며, 이 경우 수정이 필요할 수 있습니다. 문제의 가장 일반적인 원인은 애플리케이션과 함께 제공되는 파일 또는 DLL의 파일 경로에 대한 종속성입니다.

아래 표에는 단일 파일 사용을 위한 관련 런타임 라이브러리 API 세부 정보가 나와 있습니다.

API 참고 항목
Assembly.CodeBase PlatformNotSupportedException을 버립니다.
Assembly.EscapedCodeBase PlatformNotSupportedException을 버립니다.
Assembly.GetFile IOException을 버립니다.
Assembly.GetFiles IOException을 버립니다.
Assembly.Location 빈 문자열을 반환합니다.
AssemblyName.CodeBase null을(를) 반환합니다.
AssemblyName.EscapedCodeBase null을(를) 반환합니다.
Module.FullyQualifiedName <Unknown> 값이 포함된 문자열을 반환하거나 예외를 throw합니다.
Marshal.GetHINSTANCE -1이 반환됩니다.
Module.Name <Unknown> 값이 포함된 문자열을 반환합니다.

일반적인 시나리오를 해결하기 위한 몇 가지 권장 사항이 있습니다.

묶음 전 사후 처리 이진 파일

일부 워크플로에서는 묶음 전에 이진 파일 사후 처리가 필요합니다. 일반적인 예는 서명입니다. dotnet SDK는 단일 파일 묶음 직전에 이진 파일을 처리할 수 있도록 MSBuild 확장 지점을 제공합니다. 사용 가능한 API는 다음과 같습니다.

  • GenerateSingleFileBundle 이전에 호출될 대상 PrepareForBundle
  • 번들로 묶을 모든 파일을 포함하는 <ItemGroup><FilesToBundle /></ItemGroup>
  • apphost 템플릿을 지정하는 속성 AppHostFile. 사후 처리에서는 앱 호스트를 처리에서 제외할 수 있습니다.

여기에 연결하려면 PrepareForBundleGenerateSingleFileBundle 사이에서 실행될 대상을 만들어야 합니다.

다음 .NET 프로젝트 Target 노드 예를 고려합니다.

<Target Name="MySignedBundledFile" BeforeTargets="GenerateSingleFileBundle" DependsOnTargets="PrepareForBundle">

도구가 서명 과정에서 파일을 복사해야 할 수도 있습니다. 원본 파일이 빌드가 소유하지 않은 공유 항목인 경우(예: 파일이 NuGet 캐시에서 가져온 경우) 이런 일이 발생할 수 있습니다. 이러한 경우 도구는 수정된 복사본을 가리키도록 해당 FilesToBundle 항목의 경로를 수정합니다.

단일 파일 앱에서 어셈블리 압축

포함된 어셈블리에서 압축을 사용하도록 설정하여 단일 파일 앱을 만들 수 있습니다. EnableCompressionInSingleFile 속성을 true로 설정합니다. 생성된 단일 파일에는 모든 포함된 어셈블리가 압축되어 실행 파일의 크기를 크게 줄일 수 있습니다.

압축에는 성능 비용이 필요합니다. 애플리케이션을 시작할 때 어셈블리를 메모리에 압축 해제해야 하며 이 작업은 시간이 걸립니다. 압축을 사용하기 전에 압축 사용하도록 설정에 따른 크기 변경과 시작 비용을 모두 측정하는 것이 좋습니다. 그 영향은 애플리케이션마다 크게 다를 수 있습니다.

단일 파일 앱 검사

단일 파일 앱은 ILSpy 도구를 사용하여 검사할 수 있습니다. 이 도구는 애플리케이션에 번들로 포함된 모든 파일을 표시하고 관리되는 어셈블리의 콘텐츠를 검사할 수 있습니다.

참고 항목