اشتباه رایج در داکر

یک اشتباه رایج در Dockerfile برای ASP.NET Core

یک اشتباه رایج در Dockerfile برای ASP.NET Core

یکی از اشتباه‌هایی که هنگام Dockerize کردن برنامه‌های ASP.NET Core زیاد دیده می‌شود، استفاده از یک Image عمومی مثل Ubuntu و نصب کردن همه ابزارهای موردنیاز داخل آن است.

مثلاً:

FROM ubuntu

RUN apt-get update
RUN apt-get install ...

این روش لزوماً اشتباه نیست، اما برای یک ASP.NET Core Application معمولاً انتخاب مناسبی نیست.

چرا؟

چون برای اجرای یک برنامه ASP.NET Core نیازی نداریم تمام ابزارهای توسعه و Build را داخل Image نهایی داشته باشیم.

مشکل چیست؟

فرض کنید Application ما با .NET ساخته شده است.

برای Build کردن پروژه به ابزارهایی مثل .NET SDK نیاز داریم، اما بعد از اینکه Application Build شد، برای اجرای آن دیگر به SDK احتیاجی نداریم.

پس چرا SDK را داخل Production Image نگه داریم؟

اینجاست که Multi-stage Build در Docker کاربرد پیدا می‌کند.

Multi-stage Build چیست؟

در Multi-stage Build می‌توانیم فرآیند Build و اجرای Application را از یکدیگر جدا کنیم.

در مرحله اول، از Image مربوط به .NET SDK استفاده می‌کنیم:

FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build

WORKDIR /src

COPY . .

RUN dotnet publish -c Release -o /app/publish

اینجا Image مربوط به SDK فقط وظیفه Build و Publish کردن Application را دارد.

بعد یک Stage جدید برای اجرای Application ایجاد می‌کنیم:

FROM mcr.microsoft.com/dotnet/aspnet:9.0

WORKDIR /app

COPY --from=build /app/publish .

ENTRYPOINT ["dotnet", "MyApi.dll"]

در این مرحله دیگر SDK را همراه Application به Production نمی‌بریم.

در واقع:

        Source Code
             │
             ▼
     ┌─────────────────┐
     │   .NET SDK       │
     │      Build       │
     └────────┬────────┘
              │
              │ dotnet publish
              ▼
        Published App
              │
              ▼
     ┌─────────────────┐
     │ .NET ASP.NET     │
     │     Runtime      │
     └────────┬────────┘
              │
              ▼
        Production

SDK و Runtime چه تفاوتی دارند؟

به شکل ساده:

SDK

برای توسعه و Build کردن Application استفاده می‌شود.

مثلاً:

dotnet restore
dotnet build
dotnet test
dotnet publish

ASP.NET Core Runtime

برای اجرای Application استفاده می‌شود.

بنابراین در Production معمولاً لازم نیست SDK را همراه Application نگه داریم.

چرا Multi-stage Build بهتر است؟

1. Image نهایی کوچک‌تر می‌شود

Image مربوط به SDK ابزارهای زیادی برای توسعه و Build دارد.

وقتی فقط فایل‌های Publish شده را به Runtime Image منتقل می‌کنیم، بخش زیادی از این ابزارها اصلاً وارد Image نهایی نمی‌شوند.

در نتیجه حجم Image می‌تواند کمتر شود.

2. Deployment تمیزتر می‌شود

Production Container فقط چیزهایی را دارد که برای اجرای Application لازم است.

این موضوع باعث می‌شود ساختار Deployment ساده‌تر و قابل مدیریت‌تر باشد.

3. Attack Surface کاهش پیدا می‌کند

هر ابزار و Package اضافی که داخل Production Image قرار می‌گیرد، بخشی از محیطی است که باید مدیریت و به‌روزرسانی شود.

با جدا کردن Build Environment از Runtime Environment، چیزهای غیرضروری را از Production حذف می‌کنیم.

البته کوچک‌تر بودن Image به تنهایی به معنی امن بودن Container نیست، اما حذف ابزارهای غیرضروری یکی از قدم‌های خوب برای کاهش Attack Surface است.

یک Dockerfile کامل‌تر برای ASP.NET Core

برای یک پروژه واقعی می‌توانیم چیزی شبیه این داشته باشیم:

FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build

WORKDIR /src

COPY . .

RUN dotnet publish -c Release -o /app/publish


FROM mcr.microsoft.com/dotnet/aspnet:9.0

WORKDIR /app

COPY --from=build /app/publish .

ENTRYPOINT ["dotnet", "MyApi.dll"]

نکته مهم اینجاست که:

FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build

برای Build است.

اما:

FROM mcr.microsoft.com/dotnet/aspnet:9.0

برای Runtime و اجرای Application است.

پس قرار نیست Image مربوط به SDK وارد Production شود.

یک نکته مهم

Multi-stage Build فقط مخصوص ASP.NET Core نیست.

همین الگو را می‌توان برای بسیاری از Applicationهایی که فرآیند Build و Runtime متفاوتی دارند استفاده کرد.

ایده اصلی بسیار ساده است:

چیزی که برای Build لازم داریم، لزوماً نباید در Production وجود داشته باشد.

اگر Dockerfile پروژه ASP.NET Core شما یک Image سنگین دارد، یکی از اولین چیزهایی که باید بررسی کنید همین موضوع است.

Build Environment را از Runtime Environment جدا کنید. 🐳

دیدگاه‌ خود را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

پیمایش به بالا