dotnet publish를 사용하여 .NET 앱 컨테이너화

컨테이너에는 변경할 수 없는 인프라를 제공하고, 이식 가능한 아키텍처를 제공하고, 확장성을 사용하는 등의 많은 기능과 이점이 있습니다. 이미지를 사용하여 로컬 개발 환경이나 프라이빗 클라우드 또는 퍼블릭 클라우드용 컨테이너를 생성할 수 있습니다. 이 자습서에서는 dotnet publish 명령을 사용하여 .NET 애플리케이션을 컨테이너화하는 방법을 알아봅니다.

사전 요구 사항

다음 필수 구성 요소를 설치합니다.

이러한 필수 조건 외에도 .NET의 Worker Services를 숙지하는 것이 좋습니다.

.NET 앱 만들기

컨테이너화할 .NET 앱이 필요하므로 먼저 템플릿에서 새 앱을 만듭니다. 아직 수행하지 않은 경우 터미널을 열고, 작업 폴더(sample-directory)를 만들고, 해당 폴더 안에 있도록 디렉터리를 변경합니다. 작업 폴더에서 다음 명령을 실행하여 Worker라는 하위 디렉터리에서 새 프로젝트를 만듭니다.

dotnet new worker -o Worker -n DotNet.ContainerImage

폴더 트리는 다음과 같습니다.

📁 sample-directory
    └──📂 Worker
        ├──appsettings.Development.json
        ├──appsettings.json
        ├──DotNet.ContainerImage.csproj
        ├──Program.cs
        ├──Worker.cs
        └──📂 obj
            ├── DotNet.ContainerImage.csproj.nuget.dgspec.json
            ├── DotNet.ContainerImage.csproj.nuget.g.props
            ├── DotNet.ContainerImage.csproj.nuget.g.targets
            ├── project.assets.json
            └── project.nuget.cache

dotnet new 명령은 Worker라는 새 폴더를 만들고 실행 시 1초마다 메시지를 기록하는 작업자 서비스를 생성합니다. 터미널 세션에서 디렉터리를 변경하고 Worker 폴더로 이동합니다. dotnet run 명령을 사용하여 앱을 시작합니다.

dotnet run
Building...
info: DotNet.ContainerImage.Worker[0]
      Worker running at: 10/18/2022 08:56:00 -05:00
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: .\Worker
info: DotNet.ContainerImage.Worker[0]
      Worker running at: 10/18/2022 08:56:01 -05:00
info: DotNet.ContainerImage.Worker[0]
      Worker running at: 10/18/2022 08:56:02 -05:00
info: DotNet.ContainerImage.Worker[0]
      Worker running at: 10/18/2022 08:56:03 -05:00
info: Microsoft.Hosting.Lifetime[0]
      Application is shutting down...
Attempting to cancel the build...

작업자 템플릿은 무기한 반복됩니다. 취소 명령 CTRL+C를 사용하여 앱을 중지합니다.

NuGet 패키지 추가

현재 Microsoft.NET.Build.Containers NuGet 패키지는 비 웹 프로젝트를 컨테이너로 게시해야 합니다. Microsoft.NET.Build.Containers NuGet 패키지를 작업자 템플릿에 추가하려면 다음 dotnet add package 명령을 실행합니다.

dotnet add package Microsoft.NET.Build.Containers

웹앱을 빌드하고 .NET SDK 7.0.300 이상을 사용하는 경우 패키지가 필요하지 않습니다. SDK에는 동일한 기능이 기본으로 제공됩니다.

컨테이너 이미지 이름 설정

앱을 컨테이너로 게시할 때 사용할 수 있는 다양한 구성 옵션이 있습니다.

기본적으로 컨테이너 이미지 이름은 프로젝트의 AssemblyName입니다. 해당 이름이 컨테이너 이미지 이름으로 유효하지 않은 경우 다음 프로젝트 파일과 같이 ContainerRepository을(를) 지정하여 재정의할 수 있습니다.

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

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <UserSecretsId>dotnet-DotNet.ContainerImage-2e40c179-a00b-4cc9-9785-54266210b7eb</UserSecretsId>
    <ContainerRepository>dotnet-worker-image</ContainerRepository>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
  </ItemGroup>
</Project>

자세한 내용은 ContainerRepository를 참조하세요.

기본적으로 컨테이너 이미지 이름은 프로젝트의 AssemblyName입니다. 해당 이름이 컨테이너 이미지 이름으로 유효하지 않은 경우 다음 프로젝트 파일과 같이 ContainerImageName(구식) 또는 선호하는 ContainerRepository을(를) 지정하여 재정의할 수 있습니다.

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

  <PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <UserSecretsId>dotnet-DotNet.ContainerImage-2e40c179-a00b-4cc9-9785-54266210b7eb</UserSecretsId>
    <ContainerImageName>dotnet-worker-image</ContainerImageName>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
    <PackageReference Include="Microsoft.NET.Build.Containers" Version="7.0.401" />
  </ItemGroup>
</Project>

자세한 내용은 ContainerImageName을 참조하세요.

.NET 앱 게시

.NET 앱을 컨테이너로 게시하려면 다음 dotnet publish 명령을 사용합니다.

dotnet publish --os linux --arch x64 /t:PublishContainer -c Release

위의 .NET CLI 명령은 앱을 컨테이너로 게시합니다.

  • Linux를 OS 대상으로 지정(--os linux).
  • x64 아키텍처 지정(--arch x64).
  • 릴리스 구성 사용(-c Release).

중요

컨테이너를 로컬로 빌드하려면 Docker 디먼이 실행 중이어야 합니다. 앱을 컨테이너로 게시하려고 할 때 이 디먼이 실행 중이지 않으면 다음과 유사한 오류가 발생합니다.

..\build\Microsoft.NET.Build.Containers.targets(66,9): error MSB4018:
   The "CreateNewImage" task failed unexpectedly. [..\Worker\DotNet.ContainerImage.csproj]

컨테이너화 중인 앱의 유형에 따라 명령줄 스위치(옵션)가 달라질 수 있습니다. 예를 들어 /t:PublishContainer 인수는 웹이 아닌 .NET 앱(예: consoleworker 템플릿)에만 필요합니다. 웹 템플릿의 경우 /t:PublishContainer 인수를 -p:PublishProfile=DefaultContainer로 바꿉니다. 자세한 내용은 .NET SDK 컨테이너 빌드, 문제 #141을 참조하세요.

이 명령은 예제 출력과 유사한 출력을 생성합니다.

Determining projects to restore...
  All projects are up-to-date for restore.
  DotNet.ContainerImage -> .\Worker\bin\Release\net8.0\linux-x64\DotNet.ContainerImage.dll
  DotNet.ContainerImage -> .\Worker\bin\Release\net8.0\linux-x64\publish\
  Building image 'dotnet-worker-image' with tags latest on top of base image mcr.microsoft.com/dotnet/aspnet:8.0
  Pushed container 'dotnet-worker-image:latest' to Docker daemon
Determining projects to restore...
  All projects are up-to-date for restore.
  DotNet.ContainerImage -> .\Worker\bin\Release\net7.0\linux-x64\DotNet.ContainerImage.dll
  DotNet.ContainerImage -> .\Worker\bin\Release\net7.0\linux-x64\publish\
  Building image 'dotnet-worker-image' with tags 1.0.0 on top of base image mcr.microsoft.com/dotnet/aspnet:7.0
  Pushed container 'dotnet-worker-image:1.0.0' to Docker daemon

이 명령은 작업자 앱을 게시 폴더로 컴파일하고 컨테이너를 로컬 Docker 레지스트리에 푸시합니다.

컨테이너 이미지 구성

MSBuild 속성을 통해 생성된 컨테이너의 여러 측면을 제어할 수 있습니다. 일반적으로 Dockerfile의 명령을 사용하여 일부 구성을 설정할 수 있는 경우 MSBuild를 통해 동일한 작업을 수행할 수 있습니다.

참고 항목

이에 대한 유일한 예외는 RUN 명령입니다. 컨테이너를 빌드하는 방식으로 인해 에뮬레이트할 수 없습니다. 이 기능이 필요한 경우 Dockerfile을 사용하여 컨테이너 이미지를 빌드해야 합니다.

ContainerArchiveOutputPath

.NET 8부터 컨테이너를 tar.gz 보관으로 직접 만들 수 있습니다. 이 기능은 워크플로가 간단하지 않고 이미지를 푸시하기 전에 이미지에 대해 검사 도구를 실행해야 하는 경우에 유용합니다. 보관이 만들어지면 이를 이동하거나 검사하거나 로컬 Docker 툴체인에 로드할 수 있습니다.

보관 계층에 게시하려면 dotnet publish 명령에 ContainerArchiveOutputPath 속성을 추가합니다. 예를 들면 다음과 같습니다.

dotnet publish \
  -p PublishProfile=DefaultContainer \
  -p ContainerArchiveOutputPath=./images/sdk-container-demo.tar.gz

폴더 이름이나 특정 파일 이름의 경로를 지정할 수 있습니다. 폴더 이름을 지정하면 이미지 보관 파일에 대해 생성된 파일 이름이 $(ContainerRepository).tar.gz이(가) 됩니다. 이러한 보관 파일은 모든 ContainerImageTags에 대해 단일 파일이 만들어지는 경우에만 내부에 여러 태그를 포함할 수 있습니다.

컨테이너 이미지 명명 구성

컨테이너 이미지는 특정 명명 규칙을 따릅니다. 이미지의 이름은 레지스트리, 선택적 포트, 리포지토리, 선택적 태그 및 패밀리 등의 여러 부분으로 구성됩니다.

REGISTRY[:PORT]/REPOSITORY[:TAG[-FAMILY]]

예를 들어 정규화된 mcr.microsoft.com/dotnet/runtime:8.0-alpine 이미지 이름을 생각해 볼 수 있습니다.

  • mcr.microsoft.com은(는) 레지스트리입니다(이 경우 Microsoft 컨테이너 레지스트리를 나타냅니다).
  • dotnet/runtime은(는) 리포지토리입니다(user/repository(으)로 간주하기도 합니다).
  • 8.0-alpine은(는) 태그 및 패밀리입니다(패밀리는 OS 패키징을 명확하게 하는 데 도움이 되는 선택적 지정자입니다).

다음 섹션에서 설명하는 일부 속성은 생성된 이미지 이름 부분을 관리하는 것과 관계가 있습니다. 이미지 이름과 빌드 속성 간의 관계를 매핑하는 다음 테이블을 살펴보세요.

이미지 이름 부분 MSBuild 속성 예제 값
REGISTRY[:PORT] ContainerRegistry mcr.microsoft.com:443
PORT ContainerPort :443
REPOSITORY ContainerRepository dotnet/runtime
TAG ContainerImageTag 8.0
FAMILY ContainerFamily -alpine
이미지 이름 부분 MSBuild 속성 예제 값
REGISTRY[:PORT] ContainerRegistry mcr.microsoft.com:443
PORT ContainerPort :443
REPOSITORY ContainerImageName dotnet/runtime
TAG ContainerImageTag 8.0

다음 섹션에서는 생성된 컨테이너 이미지를 제어하는 데 사용할 수 있는 다양한 속성을 설명합니다.

ContainerBaseImage

컨테이너 기본 이미지 속성은 이미지의 기준으로 사용되는 이미지를 제어합니다. 기본적으로 다음 값은 프로젝트의 속성에 따라 유추됩니다.

  • 프로젝트가 자체 포함형인 경우 mcr.microsoft.com/dotnet/runtime-deps 이미지가 기본 이미지로 사용됩니다.
  • 프로젝트가 ASP.NET Core 프로젝트인 경우 mcr.microsoft.com/dotnet/aspnet 이미지가 기본 이미지로 사용됩니다.
  • 그렇지 않으면 mcr.microsoft.com/dotnet/runtime 이미지가 기본 이미지로 사용됩니다.

이미지의 태그는 선택한 TargetFramework의 숫자 구성 요소로 유추됩니다. 예를 들어 net6.0을(를) 대상으로 하는 프로젝트는 유추된 기본 이미지의 6.0 태그를 생성하고, net7.0-linux 프로젝트는 7.0 태그를 사용하는 식입니다.

여기서 값을 설정하는 경우 원하는 태그를 포함하여 기본으로 사용할 이미지의 정규화된 이름을 설정해야 합니다.

<PropertyGroup>
    <ContainerBaseImage>mcr.microsoft.com/dotnet/runtime:8.0</ContainerBaseImage>
</PropertyGroup>
<PropertyGroup>
    <ContainerBaseImage>mcr.microsoft.com/dotnet/runtime:7.0</ContainerBaseImage>
</PropertyGroup>

ContainerFamily

.NET 8부터 ContainerFamily MSBuild 속성을 사용하여 Microsoft에서 제공하는 다른 컨테이너 이미지 제품군을 앱의 기본 이미지로 선택할 수 있습니다. 이 값을 설정하면 선택한 TFM별 태그의 끝에 이 값이 추가되어 태그가 변경됩니다. 예를 들어 .NET 기본 이미지의 Alpine Linux 변형을 사용하려면 ContainerFamily을(를) alpine(으)로 설정할 수 있습니다.

<PropertyGroup>
    <ContainerFamily>alpine</ContainerFamily>
</PropertyGroup>

위의 프로젝트 구성은 .NET 8 대상 앱에 대해 최종적으로 8.0-alpine 태그를 생성합니다.

이 필드는 자유 양식이며 종종 다른 운영 체제 배포, 기본 패키지 구성 또는 기본 이미지를 변경한 다른 버전을 선택하는 데 사용할 수 있습니다. ContainerBaseImage이(가) 설정된 경우 이 필드는 무시됩니다. 자세한 내용은 .NET 컨테이너 이미지를 참조하세요.

ContainerRuntimeIdentifier

ContainerBaseImage가 둘 이상의 플랫폼을 지원하는 경우 컨테이너 런타임 식별자 속성은 컨테이너에서 사용하는 운영 체제와 아키텍처를 제어합니다. 예를 들어 mcr.microsoft.com/dotnet/runtime 이미지는 현재 동일한 태그 뒤에 있는 linux-x64, linux-arm, linux-arm64win10-x64 이미지를 모두 지원하므로 이 가운데 어떤 버전을 사용하려는지 도구가 알 수 있게 하는 방법이 필요합니다. 기본적으로 컨테이너를 게시할 때 선택한 RuntimeIdentifier 값으로 설정됩니다. 이 속성은 명시적으로 설정할 필요가 거의 없습니다. 대신 dotnet publish 명령에 옵션을 -r 사용합니다. 사용자가 선택한 이미지가 사용자가 선택한 RuntimeIdentifier을(를) 지원하지 않는 경우 이미지가 지원하는 RuntimeIdentifiers를 설명하는 오류가 발생합니다.

이 속성을 전혀 사용할 필요가 없도록 항상 ContainerBaseImage 속성을 정규화된 이미지 이름(태그 포함)으로 설정할 수 있습니다.

<PropertyGroup>
    <ContainerRuntimeIdentifier>linux-arm64</ContainerRuntimeIdentifier>
</PropertyGroup>

.NET에서 지원하는 런타임 식별자에 관한 자세한 내용은 RID 카탈로그를 참조하세요.

ContainerRegistry

컨테이너 레지스트리 속성은 새로 만든 이미지가 푸시될 대상 레지스트리를 제어합니다. 기본적으로 로컬 Docker 디먼으로 푸시되지만 원격 레지스트리를 지정할 수도 있습니다. 인증이 필요한 원격 레지스트리를 사용하는 경우에는 잘 알려진 docker login 메커니즘을 사용하여 인증합니다. 자세한 내용은 컨테이너 레지스트리 인증을 참조하세요. 이 속성을 사용하는 구체적인 예제는 다음 XML 예제를 참조하세요.

<PropertyGroup>
    <ContainerRegistry>registry.mycorp.com:1234</ContainerRegistry>
</PropertyGroup>

이 도구는 Docker 레지스트리 HTTP API V2를 지원하는 모든 레지스트리에 대한 게시를 지원합니다. 여기에는 다음 레지스트리가 명시적으로 포함됩니다(암시적으로는 더 많을 수 있습니다).

이러한 레지스트리 작업에 대한 참고 사항은 레지스트리별 참고 사항을 참조하세요.

ContainerRepository

컨테이너 리포지토리는 이미지 자체의 이름입니다(예: dotnet/runtime 또는 my-app). 기본적으로 프로젝트의 AssemblyName이 사용됩니다.

<PropertyGroup>
    <ContainerRepository>my-app</ContainerRepository>
</PropertyGroup>

ContainerImageName

컨테이너 이미지 이름은 이미지 자체의 이름(예: dotnet/runtime 또는 my-app)을 제어합니다. 기본적으로 프로젝트의 AssemblyName이 사용됩니다.

<PropertyGroup>
    <ContainerImageName>my-app</ContainerImageName>
</PropertyGroup>

참고 항목

.NET 8부터는 ContainerImageName이(가) ContainerRepository을(를) 위해 사용되지 않습니다.

이미지 이름은 하나 이상의 슬래시로 구분된 세그먼트로 구성되며, 각 세그먼트는 소문자 영숫자, 마침표, 밑줄 및 대시만 포함할 수 있으며 문자 또는 숫자로 시작해야 합니다. 다른 문자를 사용하면 오류가 발생합니다.

ContainerImageTag(s)

컨테이너 이미지 태그 속성은 이미지에 대해 생성된 태그를 제어합니다. 단일 태그를 지정하려면 ContainerImageTag을(를), 여러 태그를 지정하려면 ContainerImageTags을(를) 사용합니다.

Important

ContainerImageTags을(를) 사용하면 여러 개의 이미지가 고유한 태그당 하나씩 표시됩니다.

태그는 종종 다른 버전의 앱을 참조하는 데 사용되지만, 태그가 다른 운영 체제 배포 또는 다른 구성을 참조할 수도 있습니다.

.NET 8부터 태그가 제공되지 않는 경우 기본값은 latest입니다.

기본적으로 프로젝트의 Version이 태그 값으로 사용됩니다.

기본값을 재정의하려면 다음 중 하나를 지정합니다.

<PropertyGroup>
    <ContainerImageTag>1.2.3-alpha2</ContainerImageTag>
</PropertyGroup>

여러 태그를 지정하려면 여러 TargetFrameworks를 설정하는 것과 유사하게 ContainerImageTags 속성에 세미콜론으로 구분된 태그 집합을 사용합니다.

<PropertyGroup>
    <ContainerImageTags>1.2.3-alpha2;latest</ContainerImageTags>
</PropertyGroup>

태그에는 최대 127개의 영숫자 문자, 마침표, 밑줄 및 대시만 포함할 수 있습니다. 영숫자 문자 또는 밑줄로 시작해야 합니다. 다른 양식을 사용하면 오류가 발생합니다.

참고 항목

ContainerImageTags을(를) 사용할 때 태그는 ; 문자로 구분됩니다. 명령줄에서 dotnet publish을(를) 호출하는 경우(대부분의 CI/CD 환경과 마찬가지로), 작은 따옴표 '(으)로 값의 바깥을 감싸고 큰따옴표 "(으)로 안을 감싸야 합니다(예: ='"tag-1;tag-2"'). 다음 dotnet publish 명령을 생각해 볼 수 있습니다.

dotnet publish -p ContainerImageTags='"1.2.3-alpha2;latest"'

이를 통해 두 개의 이미지 my-app:1.2.3-alpha2과(와) my-app:latest이(가) 생성됩니다.

ContainerImageTags 속성에 문제가 발생하는 경우 환경 변수 ContainerImageTags의 범위를 지정하는 것이 좋습니다.

ContainerImageTags='1.2.3;latest' dotnet publish

ContainerLabel

컨테이너 레이블은 컨테이너에 메타데이터 레이블을 추가합니다. 레이블은 런타임에 컨테이너에 영향을 주지 않지만 보안 스캐너 및 기타 인프라 도구에서 사용할 버전과 작성 메타데이터를 저장하는 데 자주 사용됩니다. 원하는 수의 컨테이너 레이블을 지정할 수 있습니다.

ContainerLabel 노드에는 다음 두 가지 특성이 있습니다.

  • Include: 레이블의 키
  • Value: 레이블 값(비어 있을 수 있음)
<ItemGroup>
    <ContainerLabel Include="org.contoso.businessunit" Value="contoso-university" />
</ItemGroup>

기본적으로 생성되는 레이블 목록은 기본 컨테이너 레이블을 참조하세요.

컨테이너 실행 구성

컨테이너의 실행을 제어하려면 다음 MSBuild 속성을 사용할 수 있습니다.

ContainerWorkingDirectory

컨테이너 작업 디렉터리 노드는 다른 명령이 실행되지 않는 경우 명령이 실행되는 디렉터리를 나타내는 컨테이너의 작업 디렉터리를 제어합니다.

기본적으로 /app 디렉터리 값은 작업 디렉터리로 사용됩니다.

<PropertyGroup>
    <ContainerWorkingDirectory>/bin</ContainerWorkingDirectory>
</PropertyGroup>

ContainerPort

컨테이너 포트는 컨테이너의 알려진 포트 목록에 TCP 또는 UDP 포트를 추가합니다. 이렇게 하면 Docker와 같은 컨테이너 런타임에서 이러한 포트를 호스트 컴퓨터에 자동으로 매핑할 수 있습니다. 컨테이너에 대한 설명서로 자주 사용되지만 자동 포트 매핑을 사용하도록 설정하는 데도 사용할 수 있습니다.

ContainerPort 노드에는 다음 두 가지 특성이 있습니다.

  • Include: 노출할 포트 번호
  • Type: 기본값은 tcp이고, 유효한 값은 tcp 또는 udp입니다.
<ItemGroup>
    <ContainerPort Include="80" Type="tcp" />
</ItemGroup>

.NET 8부터 ContainerPort은(는) 잘 알려진 몇 가지 ASP.NET 환경 변수에 기반하여 명시적으로 제공되지 않을 때 유추됩니다.

  • ASPNETCORE_URLS
  • ASPNETCORE_HTTP_PORTS
  • ASPNETCORE_HTTPS_PORTS

이러한 환경 변수가 있는 경우 해당 값은 구문 분석되고 TCP 포트 매핑으로 변환됩니다. 이러한 환경 변수는 기본 이미지( 있는 경우) 또는 ContainerEnvironmentVariable 항목을 통해 프로젝트에 정의된 환경 변수에서 읽힙니다. 자세한 내용은 ContainerEnvironmentVariable을 참조하세요.

ContainerEnvironmentVariable

컨테이너 환경 변수 노드를 사용하면 컨테이너에 환경 변수를 추가할 수 있습니다. 환경 변수는 컨테이너에서 즉시 실행되는 애플리케이션에서 액세스할 수 있으며 실행 중인 애플리케이션의 런타임 동작을 변경하는 데 자주 사용됩니다.

ContainerEnvironmentVariable 노드에는 다음 두 가지 특성이 있습니다.

  • Include: 환경 변수의 이름
  • Value: 환경 변수의 값
<ItemGroup>
  <ContainerEnvironmentVariable Include="LOGGER_VERBOSITY" Value="Trace" />
</ItemGroup>

자세한 내용은 .NET 환경 변수를 참조하세요.

컨테이너 명령 구성

기본적으로 컨테이너 도구는 앱에 대해 생성된 AppHost 이진 파일(앱에서 AppHost를 사용하는 경우) 또는 dotnet 명령과 앱의 DLL을 사용하여 앱을 시작합니다.

하지만 ContainerAppCommand, ContainerAppCommandArgs, ContainerDefaultArgs, 및 ContainerAppCommandInstruction의 조합을 사용하여 앱이 실행되는 방식을 제어할 수 있습니다.

이러한 다양한 구성 요소는 서로 다른 기본 이미지가 서로 다른 컨테이너 ENTRYPOINTCOMMAND 속성의 조합으로 이루어지기 때문에 존재하며, 모든 구성 지점을 지원할 수 있어야 합니다. 대부분의 앱에서 기본값을 사용할 수 있지만 앱 시작 동작을 사용자 지정하려면 다음을 수행해야 합니다.

  • 실행할 이진 파일을 식별하고 ContainerAppCommand(으)로 설정
  • 애플리케이션을 실행하기 위한 필수 인수를 식별하고 ContainerAppCommandArgs(으)로 설정
  • 사용자가 재정의할 수 있는 선택 인수(있는 경우)를 식별하고 ContainerDefaultArgs(으)로 설정
  • ContainerAppCommandInstruction을(를) DefaultArgs(으)로 설정

자세한 내용은 다음 구성 항목을 참조하세요.

ContainerAppCommand

앱 명령 구성 항목은 앱의 논리적 진입점입니다. 대부분의 앱에서 이는 앱에 대해 생성된 실행 가능한 이진 파일인 AppHost에 해당됩니다. 앱에서 AppHost를 생성하지 않는 경우 이 명령은 일반적으로 dotnet <your project dll>입니다. 이러한 값은 기본 컨테이너에서 ENTRYPOINT 값 뒤에 적용되거나 ENTRYPOINT이(가) 정의되어 있지 않은 경우 직접 적용됩니다.

ContainerAppCommand 구성에는 단일 Include 속성이 있으며, 이는 진입점 명령에 사용할 명령, 옵션 또는 인수를 나타냅니다.

<ItemGroup Label="ContainerAppCommand Assignment">
  <!-- This is how you would start the dotnet ef tool in your container -->
  <ContainerAppCommand Include="dotnet" />
  <ContainerAppCommand Include="ef" />

  <!-- This shorthand syntax means the same thing, note the semicolon separating the tokens. -->
  <ContainerAppCommand Include="dotnet;ef" />
</ItemGroup>

ContainerAppCommandArgs

이 앱 명령 인수 구성 항목은 앱에 논리적으로 필요하며 ContainerAppCommand에 적용되어야 하는 인수를 나타냅니다. 기본적으로 앱에 대해 생성되는 항목은 없습니다. 있는 경우 인수는 실행 시 컨테이너에 적용됩니다.

ContainerAppCommandArgs 구성에는 단일 Include 속성이 있으며, 이는 ContainerAppCommand 명령에 적용할 옵션 또는 인수를 나타냅니다.

<ItemGroup>
  <!-- Assuming the ContainerAppCommand defined above, 
       this would be the way to force the database to update.
  -->
  <ContainerAppCommandArgs Include="database" />
  <ContainerAppCommandArgs Include="update" />

  <!-- This is the shorthand syntax for the same idea -->
  <ContainerAppCommandArgs Include="database;update" />
</ItemGroup>

ContainerDefaultArgs

이 기본 인수 구성 항목은 앱에 대해 사용자가 재정의할 수 있는 인수를 나타냅니다. 이는 앱을 실행할 때 필요할 수 있는 기본값을, 쉽게 시작할 수 있고 사용자 지정하기도 쉬운 방법으로 제공하는 좋은 방법입니다.

ContainerDefaultArgs 구성에는 단일 Include 속성이 있으며, 이는 ContainerAppCommand 명령에 적용할 옵션 또는 인수를 나타냅니다.

<ItemGroup>
  <!-- Assuming the ContainerAppCommand defined above, 
       this would be the way to force the database to update.
  -->
  <ContainerDefaultArgs Include="database" />
  <ContainerDefaultArgs Include="update" />

  <!-- This is the shorthand syntax for the same idea -->
  <ContainerDefaultArgs Include="database;update" />
</ItemGroup>

ContainerAppCommandInstruction

앱 명령의 명령 구성은 컨테이너에서 실행되는 최종 명령을 형성하기 위해 ContainerEntrypoint, ContainerEntrypointArgs, ContainerAppCommand, ContainerAppCommandArgs, 및 ContainerDefaultArgs이(가) 조합되는 방식을 제어하는 데 도움이 됩니다. 이는 기본 이미지에 ENTRYPOINT이(가) 존재하는지 여부에 따라 크게 달라집니다. 이 속성은 "DefaultArgs", "Entrypoint", "None" 세 가지 값 중 하나를 사용합니다.

  • Entrypoint:
    • 이 모드에서 진입점은 ContainerAppCommand, ContainerAppCommandArgsContainerDefaultArgs(으)로 정의됩니다.
  • None:
    • 이 모드에서 진입점은 ContainerEntrypoint, ContainerEntrypointArgsContainerDefaultArgs(으)로 정의됩니다.
  • DefaultArgs:
    • 가장 복잡한 모드입니다. ContainerEntrypoint[Args] 항목 중 아무것도 없는 경우 ContainerAppCommand[Args]ContainerDefaultArgs을(를) 사용하여 진입점과 명령을 만듭니다. dotnet 또는 /usr/bin/dotnet에 하드 코딩된 기본 이미지의 기본 이미지 진입점을 건너뛰어 사용자가 완전히 제어할 수 있습니다.
    • ContainerEntrypoint과(와) ContainerAppCommand이(가) 둘 다 있는 경우 ContainerEntrypoint이(가) 진입점이 되고 ContainerAppCommand이(가) 명령이 됩니다.

참고 항목

ContainerEntrypointContainerEntrypointArgs 구성 항목은 .NET 8부터 더 이상 사용되지 않습니다.

Important

이는 고급 사용자를 위한 것으로, 대부분의 앱은 진입점을 이 정도까지 사용자 지정할 필요가 없습니다. 자세한 내용을 확인하고 시나리오에 대한 사용 사례를 제공하려는 경우 GitHub: .NET SDK 컨테이너 빌드 토론을 참조하세요.

ContainerUser

사용자 구성 속성은 컨테이너의 실행 역할이 되는 기본 사용자를 제어합니다. 이는 종종 컨테이너를 비루트 사용자로 실행하는 데 사용되며, 이러한 사용은 보안 모범 사례에 해당합니다. 이 구성에는 알아야 할 몇 가지 제약 조건이 있습니다.

  • 사용자 이름, Linux 사용자 ID, 그룹 이름, Linux 그룹 ID, username:groupname 및 기타 ID 변형 등 다양한 형식을 사용할 수 있습니다.
  • 지정된 사용자 또는 그룹이 이미지에 있는지 확인하지 않습니다.
  • 특히 파일 시스템 권한 등과 관련하여 사용자를 변경하면 앱의 동작이 변경될 수 있습니다.

이 필드의 기본값은 프로젝트 TFM과 대상 운영 체제에 따라 다릅니다.

  • .NET 8 이상을 대상으로 하고 Microsoft 런타임 이미지를 사용하는 경우:
    • Linux에서는 루트 없는 사용자 app이(가) 사용됨(사용자 ID에서 참조됨).
    • Windows에서는 루트 없는 사용자 ContainerUser이(가) 사용됨
  • 그렇지 않으면 사용되는 기본 ContainerUser이(가) 없음
<PropertyGroup>
  <ContainerUser>my-existing-app-user</ContainerUser>
</PropertyGroup>

APP_UID 환경 변수는 컨테이너에서 사용자 정보를 설정하는 데 사용됩니다. 이 값은 기본 이미지에 정의된 환경 변수에서 가져오거나(예: Microsoft .NET 이미지) 구문 ContainerEnvironmentVariable을(를) 통해 직접 설정할 수 있습니다.

하지만 ContainerEntrypointContainerEntrypointArgs을(를) 사용하여 앱이 실행되는 방식을 제어할 수 있습니다.

ContainerEntrypoint

컨테이너 진입점은 컨테이너가 시작될 때 호출되는 실행 파일인 컨테이너의 ENTRYPOINT을 사용자 지정하는 데 사용할 수 있습니다. 기본적으로 앱 호스트를 만드는 빌드의 경우 ContainerEntrypoint로 설정됩니다. 실행 파일을 만들지 않는 빌드의 경우 dotnet path/to/app.dllContainerEntrypoint로 사용됩니다.

ContainerEntrypoint 노드에는 다음과 같은 단일 특성이 있습니다.

  • Include: ContainerEntrypoint 명령에 사용할 명령, 옵션 또는 인수

예를 들어 다음 샘플 .NET 프로젝트 항목 그룹을 고려해 보세요.

<ItemGroup Label="Entrypoint Assignment">
  <!-- This is how you would start the dotnet ef tool in your container -->
  <ContainerEntrypoint Include="dotnet" />
  <ContainerEntrypoint Include="ef" />

  <!-- This shorthand syntax means the same thing.
       Note the semicolon separating the tokens. -->
  <ContainerEntrypoint Include="dotnet;ef" />
</ItemGroup>

ContainerEntrypointArgs

컨테이너 진입점 인수 노드는 ContainerEntrypoint에 제공되는 기본 인수를 제어합니다. ContainerEntrypoint가 사용자가 자체적으로 사용하려는 프로그램인 경우에 이 노드를 사용해야 합니다. 기본적으로 사용자를 대신해서 ContainerEntrypointArgs가 만들어지지는 않습니다.

ContainerEntrypointArg 노드에는 다음과 같은 단일 특성이 있습니다.

  • Include: ContainerEntrypoint 명령에 적용할 옵션 또는 인수

다음 예제 .NET 프로젝트 항목 그룹을 고려해 보세요.

<ItemGroup>
  <!-- Assuming the ContainerEntrypoint defined above,
       this would be the way to update the database by
       default, but let the user run a different EF command. -->
  <ContainerEntrypointArgs Include="database" />
  <ContainerEntrypointArgs Include="update" />

  <!-- This is the shorthand syntax for the same idea -->
  <ContainerEntrypointArgs Include="database;update" />
</ItemGroup>

기본 컨테이너 레이블

레이블은 컨테이너 이미지에 일관된 메타데이터를 제공하는 데 자주 사용됩니다. 이 패키지는 생성된 이미지의 유지 관리 가능성을 높이기 위해 몇 가지 기본 레이블을 제공합니다.

  • org.opencontainers.image.created는 현재 UTC DateTime의 ISO 8601 형식으로 설정됩니다.

자세한 내용은 기존 레이블 인프라를 기준으로 기존 레이블 구현을 참조하세요.

리소스 정리

이 문서에서는 .NET 작업자를 컨테이너 이미지로 게시했습니다. 원할 경우 이 리소스를 삭제합니다. 설치된 이미지 목록을 보려면 docker images 명령을 사용합니다.

docker images

다음 예제 출력을 고려해 보세요.

REPOSITORY            TAG       IMAGE ID       CREATED          SIZE
dotnet-worker-image   1.0.0     25aeb97a2e21   12 seconds ago   191MB

이미지 파일이 클 수 있습니다. 일반적으로 앱을 테스트하고 개발하는 동안 만든 임시 컨테이너를 제거합니다. 일반적으로 해당 런타임을 기반으로 다른 이미지를 빌드할 계획인 경우에는 설치된 런타임과 함께 기본 이미지를 유지합니다.

이미지를 삭제하려면 이미지 ID를 복사하고 docker image rm 명령을 실행합니다.

docker image rm 25aeb97a2e21

다음 단계