File-based App으로 리눅스 웹 서버 컨테이너 띄우기

너무나 당연한 이야기지만, File-based App 코드 파일 하나만 있으면 리눅스 네이티브 서버 애플리케이션도 Docker 컨테이너로 csproj 파일 없이 빌드가 바로 가능합니다.

예를 들어 다음과 같이 WebApp.cs 파일이 있다고 가정해보겠습니다.

#!/usr/bin/env dotnet
#:sdk Microsoft.NET.Sdk.Web

var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddEnvironmentVariables();
builder.Logging.AddConsole();

var app = builder.Build();
app.MapGet("/", () => "Hello, World!");
app.Run();

그리고 Containerfile (혹은 Dockerfile)을 다음과 같이 작성할 수 있습니다.

FROM mcr.microsoft.com/dotnet/sdk:10.0.100-preview.7-noble-aot-amd64 AS build
WORKDIR /build
ADD WebApp.cs .
RUN dotnet publish ./WebApp.cs -o bin/

FROM mcr.microsoft.com/dotnet/aspnet:10.0.0-preview.7-noble-amd64
WORKDIR /app
COPY --from=build /build/bin/ .
ENTRYPOINT [ "./WebApp" ]

기존의 전통적인 sln, csproj 계통 파일들의 경우는 Dockerfile/Containerfile 빌드 절차가 효율성을 추구해야 한다는 명분 때문에 꽤 복잡했었습니다. 메타데이터 역할을 하는 sln/csproj 파일만 따로 먼저 컨테이너 안으로 복사해서 nuget 패키지만 복원하고, 그 다음 소스 코드를 모두 추가해서 빌드하는 식으로 진행했었지요.

그러나 이 모든 과정이 File-based App에서는 파일 하나로 Virtual Project 형성이 끝나기 때문에, 그저 dotnet publish 명령어 한 방이면 바이너리 파일이 곧장 만들어지게 됩니다. 물론, AOT 빌드를 원하지 않는다면 #:property PublishAot=false 지시자만 상단에 넣어주어도 되겠고, 더 나아가서 dotnet run WebApp.cs 로 실행해도 무방할 것입니다.

그리고 컨테이너 빌드/실행 방법은 다음과 같습니다.

# Build (podman 혹은 docker 모두 사용 가능)
podman build -t aspxtest:latest -f Containerfile .

# Run (podman 혹은 docker 모두 사용 가능)
podman run --rm -dt --name aspxtest -p 8080:8080 aspxtest:latest

# Remove (podman 혹은 docker 모두 사용 가능)
podman stop aspxtest

11월 11일 이전까지는 Beta, 혹은 RC 버전에 계속 머무르게 되므로 베이스 이미지에 붙는 태그 이름이 굉장히 길지만, 출시일 이후로 베이스 이미지 태그 지정은 훨씬 더 간소해지게 될겁니다. :smiley:

8 Likes

WSL2 기준으로 이렇게 하면 도커파일도 필요없네요!

$ echo 'Console.WriteLine("Hello, World");' > sample.cs
$ dotnet publish sample.cs /t:PublishContainer --os linux --arch x64
$ docker run --rm sample
Hello, World
4 Likes

맞습니다. 참고로 WSL 2가 굳이 필요한 이유가, IL Compiler가 크로스 컴파일 빌드를 지원하지 않기 때문인 점이 있습니다. (AOT 빌드를 컨테이너 환경이 아닌 현재 실행 중인 OS에서 실행하는 동작이 있어서인듯 합니다.)

.nuget\packages\microsoft.dotnet.ilcompiler\10.0.0-preview.7.25380.108\build\Microsoft.NETCore.Native.Publish.targets(61,5): error : Cross-OS native compilation is not supported.

서버의 경우 AOT 사용을 엄격하게 고집해야 할 필요성이 조금은 상쇄되는 점이 있으니, 빌드 과정을 유연하게 만들고 싶다면 AOT 빌드를 끄고, OS에 관계없이 Dockerfile 없는 컨테이너 퍼블리싱이 가능합니다. 그리고 ContainerRepository 프로퍼티를 지정하여 이미지 이름도 미리 지정이 가능합니다.

#!/usr/bin/env dotnet
#:sdk Microsoft.NET.Sdk.Web
#:property ContainerRepository=aspxtest
#:property PublishAot=false

var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddEnvironmentVariables();
builder.Logging.AddConsole();

var app = builder.Build();
app.MapGet("/", () => "Hello, World!");
app.Run();
dotnet publish WebApp.cs --os linux --arch x64 /t:PublishContainer

반대로 네이티브 리눅스 환경에서 빌드할 수 있거나 WSL 2를 사용하는데 불편함이 없다면, AOT 빌드를 켜고 사용해도 괜찮습니다. :smiley:

3 Likes