Tại sao .NET 8 cần Docker?
“Code chạy tốt trên máy em nhưng lên server thì lỗi” là nỗi ám ảnh của mọi lập trình viên. Nguyên nhân thường nằm ở sự lệch pha giữa các phiên bản SDK, runtime hoặc biến môi trường. .NET 8 mang lại hiệu suất vượt trội, nhưng nếu bạn vẫn deploy theo kiểu copy file publish lên VPS, bạn đang lãng phí tiềm năng của dự án.
Container hóa (Dockerize) giúp đóng gói toàn bộ runtime và thư viện vào một Image duy nhất. Tuy nhiên, nếu không tối ưu, một Image .NET có thể nặng tới 800MB, gây lãng phí băng thông CI/CD. Bằng cách áp dụng Multi-stage Build, chúng ta có thể ép cân Image xuống chỉ còn khoảng 200MB – giúp việc deployment diễn ra trong tích tắc.
Hồi mới làm quen với Docker, mình từng mắc lỗi ngớ ngẩn: copy cả folder bin và obj vào image. Kết quả là build cực chậm và image nặng khủng khiếp. Dưới đây là quy trình chuẩn để bạn không đi vào vết xe đổ đó.
Chuẩn bị môi trường
Trước khi bắt đầu, hãy đảm bảo máy bạn đã cài đặt:
- .NET 8 SDK: Bản mới nhất để phát triển local.
- Docker Desktop: Hoặc Docker Engine nếu bạn dùng Linux.
- VS Code / Visual Studio 2022: Hỗ trợ extension Docker rất tốt.
Tạo nhanh một project Web API để thực hành:
dotnet new webapi -n MyDotnetApp
cd MyDotnetApp
dotnet run
Tối ưu Dockerfile với Multi-stage Build
Kỹ thuật này tách biệt môi trường Build (cần SDK nặng) và môi trường Runtime (chỉ cần thư viện tối thiểu). Đây là bí quyết để có một Image nhẹ và bảo mật.
1. Tạo file .dockerignore
Đừng bỏ qua bước này! Nó giúp Docker loại bỏ rác, giảm thời gian nén context khi build.
**/.git
**/.vs
**/bin
**/obj
Dockerfile
.dockerignore
2. Dockerfile chuẩn chỉnh cho .NET 8
Lưu ý: Từ .NET 8, Microsoft mặc định chạy ứng dụng ở port 8080 thay vì port 80 như các bản cũ.
# Giai đoạn 1: Build & Restore
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
# Cache layer cho NuGet: Chỉ restore nếu file .csproj thay đổi
COPY ["MyDotnetApp.csproj", "./"]
RUN dotnet restore "MyDotnetApp.csproj"
# Copy code và build ứng dụng
COPY . .
RUN dotnet build "MyDotnetApp.csproj" -c Release -o /app/build
# Giai đoạn 2: Publish
FROM build AS publish
RUN dotnet publish "MyDotnetApp.csproj" -c Release -o /app/publish /p:UseAppHost=false
# Giai đoạn 3: Final Image (Runtime duy nhất)
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
WORKDIR /app
EXPOSE 8080
# Chỉ copy những file thực sự cần thiết để chạy app
COPY --from=publish /app/publish .
ENV ASPNETCORE_ENVIRONMENT=Production
ENTRYPOINT ["dotnet", "MyDotnetApp.dll"]
Điểm cần lưu ý: Lệnh COPY csproj được đặt trước COPY . .. Nếu bạn chỉ sửa code mà không thêm thư viện NuGet, Docker sẽ dùng lại cache của bước restore, giúp tiết kiệm khoảng 1-2 phút mỗi lần build.
Quản lý cấu hình môi trường chuyên nghiệp
Trong thực tế, mỗi môi trường (Staging, Production) sẽ có một file appsettings.json riêng. Đừng bao giờ sửa cứng giá trị này trong Dockerfile.
Thay vào đó, hãy tận dụng biến môi trường ASPNETCORE_ENVIRONMENT. Khi chạy container, bạn có thể dễ dàng chuyển đổi cấu hình mà không cần build lại Image.
Kiểm tra và vận hành
Tiến hành build Image với tag cụ thể:
docker build -t my-dotnet-app:v1 .
Chạy container và map port 5000 của máy vào port 8080 của container:
docker run -d -p 5000:8080 --name my-app -e ASPNETCORE_ENVIRONMENT=Staging my-dotnet-app:v1
Truy cập http://localhost:5000/swagger để kiểm tra. Nếu muốn xem log để debug, hãy dùng lệnh: docker logs -f my-app.
Mẹo nhỏ cho Production
Luôn thiết lập Health Checks trong .NET 8. Docker hoặc Kubernetes sẽ dựa vào endpoint này để tự động khởi động lại container nếu ứng dụng bị treo (Deadlock) hoặc mất kết nối Database. Việc này giúp hệ thống của bạn tự phục hồi mà không cần can thiệp thủ công lúc nửa đêm.
Nắm vững Dockerfile và cách quản lý môi trường không chỉ giúp việc deploy nhàn hơn. Nó còn khẳng định tư duy hệ thống chuyên nghiệp của một Backend Developer thực thụ.

