Docker ile .NET Uygulamasını Konteynerleştirme
Multi-stage Dockerfile, image boyutu optimizasyonu ve docker-compose ile calistirma.
Bir ASP.NET Core uygulamasını Docker ile dağıtırken kaynak kodu derlemek ve ortaya çıkan uygulamayı çalıştırmak iki ayrı iştir. Derleme için .NET SDK gerekir. Uygulamayı başlatmak için ASP.NET Core çalışma zamanı ve yayımlanan dosyalar yeterlidir. Bu ayrımı Dockerfile’a taşıdığınızda aynı imajı yerelde deneyebilir ve dağıtım ortamına gönderebilirsiniz.
Tek projeli bir örnekle başlayın
Bu örnek, Linux konteyneri olarak çalışan ve .NET 10 hedefleyen tek bir ASP.NET Core projesi kullanır. KatalogApi.csproj, Dockerfile ve .dockerignore aynı dizinde bulunur. Proje başka bir projeye başvurmaz ve paket geri yükleme için özel bir NuGet kaynağı gerektirmez. Örneği sıfırdan kurmak için aşağıdaki komutu çalıştırıp KatalogApi dizinine geçin. Hazır şablon, kök adrese basit bir HTTP yanıtı verir.
dotnet new web --framework net10.0 --name KatalogApi
cd KatalogApi
Derleme ve çalışma aşamalarını ayırın
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY KatalogApi.csproj ./
RUN dotnet restore KatalogApi.csproj
COPY . ./
RUN dotnet publish KatalogApi.csproj -c Release -o /publish --no-restore
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
WORKDIR /app
COPY --from=build /publish/ ./
ENV ASPNETCORE_HTTP_PORTS=8080
EXPOSE 8080
USER $APP_UID
ENTRYPOINT ["dotnet", "KatalogApi.dll"]
Proje dosyasını kaynak koddan önce kopyalamak, yalnızca uygulama kodu değiştiğinde Docker’ın restore adımını önbellekten kullanabilmesini sağlar. Çözümünüzde ProjectReference, Directory.Packages.props ya da restore sırasında okunan başka dosyalar varsa onları da restore öncesinde uygun dizin yapısıyla kopyalayın. Son aşama yalnızca publish çıktısını alır. USER satırı, Microsoft’un Linux imajında tanımlı APP_UID değerini kullanır ve uygulama root yetkisi olmadan çalışır.
Docker’a gönderilen dosyaları .dockerignore ile daraltın. Aşağıdaki örnek yerel derleme çıktılarını, Git geçmişini ve yaygın gizli dosyaları dışarıda bırakır. Parola ve bağlantı bilgilerini kaynak kodun, appsettings.json dosyasının ve imajın dışında tutun. Dağıtımda uygulamaya gerekli sırları çalışma ortamının sır yöneticisi veya yalnızca ilgili servise bağlanan bir sır dosyası üzerinden verin.
**/bin
**/obj
.git
.vs
.env
.env.*
**/*.pfx
**/*.pem
İmajı oluşturun ve port eşlemesini kontrol edin
docker build --pull -t katalog-api:local .
docker run --rm -d --name katalog-api -p 127.0.0.1:8080:8080 katalog-api:local
curl -i http://127.0.0.1:8080/
docker exec katalog-api id -u
docker stop katalog-api
Kök adreste 200 ve şablonun Hello World! yanıtını, id -u çıktısında ise sıfırdan farklı bir kullanıcı kimliği bekleyin. İlk istek uygulama henüz başlarken başarısız olursa kısa süre sonra yeniden deneyin ve docker logs katalog-api ile başlangıç kayıtlarına bakın. EXPOSE satırı imajın beklediği portu belirtir. Erişimi açan seçenek -p’dir. Yukarıdaki eşleme, ana makinedeki 8080 portunu yalnızca yerel arayüzde yayımlar ve isteği konteynerin 8080 portuna yönlendirir. Ana makinede port doluysa eşlemenin ilk portunu 8081 yapıp curl isteğini de 8081’e gönderin.
Veritabanı eklerken hazır olma durumunu ve veriyi ayrı düşünün
Bir veritabanı eklediğinizde Compose iki servisi birlikte başlatabilir. Kısa depends_on yazımı başlatma sırasını belirler. Veritabanının bağlantı kabul etmesini beklemek için veritabanı servisine bir healthcheck tanımlayın ve API’nin bağımlılığında condition: service_healthy kullanın. Bu ilk başlatmayı düzenler. Çalışma sırasında kopan bağlantıları yönetmek yine uygulamanın görevidir.
Veritabanının veri dizinini adlandırılmış bir volume’a bağladığınızda konteyneri yeniden oluştururken veriyi korursunuz. Volume’un ömrü konteynerden ayrıdır. Örneğin docker compose down -v, Compose’un yönettiği adlandırılmış volume’ları da kaldırır. Geliştirme ortamında verinin gerçekten kalıcı olduğunu sınamak için bir kayıt ekleyin, veritabanı konteynerini volume’u koruyarak yeniden oluşturun ve kaydı API üzerinden tekrar okuyun.