.NET Core Web Api Uygulaması Docker ile Nasıl Deploy Edilir?

Gökhan ATAN
8 min readDec 24, 2020

Herkese merhaba, bu aralar konteynır teknolojileri üzerinde çalışmalar yapıyorum ve sizlere bir .Net Core uygulamasını Docker ile nasıl deploy ederiz bunu anlatmaya çalışacağım.

Docker Nedir?

Öncelikle kısaca Docker’dan bahsetmek istiyorum. Docker açık kaynak kodlu bir konteynırlaştırma platformudur. Yani uygulamalarınızı Image’ler halinde paketlemenize ve (Docker’ı çalıştırabilen) herhangi bir platformda "konteynır" olarak çalıştırmanızı sağlar.

Docker konteynırları uygulamanın çalışması için gereken her şeyi içerdiğinden dolayı yazılımcılardan sıklıkla duyduğumuz "Benim bilgisayarımda çalışıyor" klişesini de ortadan kaldırır :)

Konteynırlar ve Sanal Makineler aynı şeyler mi?

Konteynırlar ve sanal makineler benzer teknolojilerdir ancak tamamen aynı değillerdir.

  • Sanal makineler işletim sistemi seviyesinde abstraction (izolasyon, soyutlama)sağlar.
  • Konteynırlar uygulama seviyesinde abstraction (izolasyon, soyutlama) sağlar.

Bu kavram aşağıda ki resimden daha iyi anlaşılabilir:

Docker’ ı neden kullanmalıyız?

Docker kullanımının bir çok faydası var, önemli olan bir kaçından bahsetmek istiyorum.

  • Portability(Taşınabilirlik): Oluşturduğumuz uygulama konteynırları bağımsız olduğundan Docker çalıştırabilen herhangi bir platformda çalışabilirler, buda uygulamaların ayağa kalkmalarını ve çeşitli bir çok platformda çalıştırılmasını kolaylaştırır.
  • Scalability(Ölçeklenebilirlik): Birden fazla konteynır örneği ayağa kaldırabilir, orkestrasyon ile artan yükü bu konteynır örneklerine dağıtarak azaltabilirsiniz.
  • Performance(Performans): Konteynırlar Linux Kernel çekirdeğini kullanır ve paylaşırlar. Sanal Makineler de ki gibi her birinin ayrı bir işletim sistemi olmaz.

Ben örnek uygulamamda:

  • .Net 5.0
  • VS Code
  • Ve tabiki Docker kullanacağım.

Eğer bilgisayarınızda Docker yüklü değil ise buradan indirebilirsiniz.

Ayrıca yüklerken ilgili işletim sistemine göre size yardımcı olacak dökümanıda burda bulabilirsiniz.

Hazırlıklarımız tamamsa hadi uygulamamızı oluşturalım :)

.Net Core Web Api Uygulamasını Oluşturma

Makale’nin ana konusu Docker üzerinde bir web api deploy etmek olduğu için, hazır oluşan web api projesini kullanacağım ve üzerinde herhangi bir değişiklik yapmayacağım.

Bir terminal açıyoruz, çalışacağımız klasör altına geliyoruz ve API uygulamamızı oluşturmak için aşağıda ki kod satırını yazıp çalıştırıyoruz.

dotnet new webapi -n DockerTutorialAPI

Komutu çalıştırdıktan sonra "DockerTutorialAPI" projesi oluşacaktır ve aşağıdakine benzer bir çıktı alacaksınız.

Şimdi VSCode açıyoruz:

File -> Open Folder tıklayıp yeni oluşturduğumuz DockerTutorialAPI proje dosyasını seçiyoruz.

VSCode’da açılmış DockerTutorialAPI projesi

Projemizi ayağa kaldırıp düzgün çalıştığını test edelim. Terminal de DockerTutorialAPI proje dosyası içerisinde olduğumuzdan emin olduktan sonra örnek projemizi aşağıda ki komut ile çalıştırıyoruz.

dotnet run

Komutu çalıştırdıktan sonra aşağıda ki gibi bir çıktı almalısınız.

Uygulamamızın 5000(http) ve 5001(https) portları üzerinden ayağa kalktığını görüyoruz. Hadi şimdi API uygulamamızı test edelim. Aşağıda ki linki tarayıcımız üzerinde açalım.

http://localhost:5000/WeatherForecast

Bu link aşağıda ki controller üzerinde ki Get metoduna karşılık gelir.

Ve linki tarayıcıda açtıktan sonra aşağıda ki çıktıyı alıyoruz.

Tekrardan belirtmek istiyorum makalemizin konusu API geliştirme olmadığı için uygulamamız şu an bunu yapıyor olacak. :)

Image & Containers

Uygulamamızı Docker üzerinde çalışacak hale getirmeden önce, Docker hakkında konuşurken sık sık duyacağınız iki terimi sizlere açıklamak istiyorum.

Image(Görüntü)

Docker Image’ı aslında bir şablon olarak tanımlayabiliriz. Docker üzerinde çalışabilecek bir konteynır oluşturmak için gerekli talimatları ve planları barındıran şablonlara biz aslında Docker Image diyoruz.

Kendi özel kullanımınız için kullanabileceğiniz veya diğer Docker kullanıcılarıyla herkese açık olarak paylaşabileceğiniz uygulamaları ve önceden yapılandırılmış sunucu ortamlarını paketlemek için kullanışlı bir yol sağlıyor.

Container(Konteynır)

Temel olarak konteynır, Image’ın çalıştırılabilir örneğidir. Docker Rest API veya CLI aracılığıyla konteynırlar oluşturup, başlatıp, durdurabilir veya başka bir yere taşıyabiliriz.

Nesne yönelimli programlama gözünden bu 2 terim incelendiğinde:

Image = Class

Container = Object Instance olarak eşleştirildiğini gördüm.

Bu eşleştirme %100 doğru olmasada çok yakın olabileceğini düşünüyorum. Sonuç olarak bir Image dosyasından bir çok konteynır oluşturabiliriz :)

Konteynır ve Image kavramlarından bahsettiğimize göre uygulamamızı Docker üzerinde çalıştırmak için ilk yapmamız gereken bir Docker Image oluşturmak. Bunu da projemize bir "Dockerfile" ekleyerek yapıyoruz.

Dockerfile nedir?

Dockerfile, bir kullanıcının Docker Image’ı birleştirmek için komut satırında çağırabileceği tüm komutları içeren bir metin belgesidir.

Docker, Dockerfile’daki talimatları okuyarak Docker Image’ları otomatik olarak oluşturabilir.

Dockerfile — Docker Image — Docker Container

Kısaca yapacaklarımız:

  • Dockerfile dosyasını tanımlayacağız.
  • Docker CLI "build" komutu ile Dockerfile dosyasını derleyeceğiz.
  • Docker Engine Dockerfile dosyasını parse edip Docker Image dosyasını oluşturacak.

Hadi başlayalım ve Dockerfile dosyamızı oluşturalım. İlk adım olarak projemize "Dockerfile" isimli dosya ekliyoruz. Bu arada dosyanın herhangi bir uzantısı yok.:)

Eğer VSCode kullanıyorsanız projenize Dockerfile dosyasını eklediğinizde VSCode bazı extensionları yüklemenizi önerecektir. Bu eklentileri yüklemenizi tavsiye ederim, geliştirme aşamasında Dockerfile dosyasını parse etmek gibi size çok fayda sağlayacaktır.

Şimdi Dockerfile dosyamıza aşağıda ki kod satırlarını ekleyelim. Aşağıda satır satır ne işe yaradıklarını açıklayacağım.

# Get Base Image (Full .NET Core SDK)
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build-env
WORKDIR /app
# Copy csproj and restore
COPY *.csproj ./
RUN dotnet restore
# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out
# Generate runtime image
FROM mcr.microsoft.com/dotnet/aspnet:5.0
WORKDIR /app
EXPOSE 80
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "DockerAPI.dll"]

Kodları ekledikten sonra dosyamız aşağıda ki gibi gözükmeli.

  • Line 2: Dockerfile oluşturmaya başlamadan önce ilk yapılacak şey Base Image göstermektir. Burada biz base Image olarak Microsoft’un .NET 5.0 SDK Image’ını kullanıyoruz.
  • Line 3: Uygulamamızın nerede olacağını belirttiğimiz Working Directory’i belirtiyoruz.
  • Line 6: .csproj dosyamızı bilgisayarımızdan çalışan konteynır dizinine kopyalıyoruz.(/app)
  • Line 7: dotnet restore komutu ile projenin bağımlılıklarını çözüyoruz.
  • Line 10: Proje dosyalarımızın geri kalanını çalışma dizinimize kopyalıyoruz, böylece uygulamayı oluşturabileceğiz.
  • Line 11: dotnet publish komutunu çalıştırıyoruz. Bunun bir Release build olduğunu belirtiyoruz. Publish aldığımız klasörün adının da "out" olduğunu söylüyoruz.
  • Line 14: Build ederken kullandığımız Dotnet SDK Full Image’ın aksine, oluşturacağımız Image’ımız daha yalın tutmak için burada Dotnet Runtime Image’ını kullanıyoruz. Çünkü uygulamamızın çalışması için bu Image yeterli olacaktır.
  • Line 15: Çalışma dizinimizi yeniden belirtiyoruz.
  • Line 16: Docker konteynırında ki uygulamamıza ulaşacağımız portu belirtiyoruz.
  • Line 17: Hem bağımlılık dosyalarını hemde publish aldığımız dosyaları çalışacağımız /app dizinine kopyalıyoruz.
  • Line 18: Burada Entrypoint’imizi ayarlıyoruz. Yani çalıştırılabilir bir dosya (executable) gibi kullanılmak üzere bir Image yaratıyoruz. Burada publish edilmiş dosyamız dotnet komutunu kullanır ve uygulamamızın ayağa kalmasını sağlar. Eğer komutun detaylı açıklamasını merak ediyorsanız Dotnet CLI komutları arasında bulabilirsiniz.

NOT: Docker Engine Image oluştururken her bir aşamada boş konteynır kullanır. Bu nedenle konteynır ortamının boş olduğunu varsaymalıyız ve uygulamamızın derlenmesi için .NET Sdk Base Image’ına ihtiyaç duyarız.

Dockerfile’mızı kayıt ettikten sonra ikinci bir dosyadan bahsetmek istiyorum. O da ".dockerignore" dosyası. Bu dosya, Image’mızı oluştururken hangi dosyaları almayacağımızı söylediğimiz dosyadır. Dosyanın içerisine aşağıda ki komutları yazıyoruz.

bin\
obj\

Dosyayı kaydediyoruz ve bir sonra ki adıma geçiyoruz — Image oluşturma :)

Image Oluşturma

Dockerfile dosyamızı kayıt ettikten sonra Image’mızı oluşturmaya hazırız. Docker Image’ları oluşturulurken isimlendirmeler belli bir format ile yapılır.

<Docker Hub ID>/<Project Name>:<Version>

Ben Image’ımı: gkhnatn/dockertutorialapi olarak isimlendireceğim.Siz kendi Docker Hub ID’nizi "gkhnatn" ile değiştirin. Ben isimlendirmede versiyon yazmadım, Docker Engine bunu "enyeni(latest)" olarak algılayacaktır. Eğer siz isterseniz isimlendirmeye versiyon da ekleyebilirsiniz.

Ayrıca isimlendirmede DockerHubID kullanmak zorunda da değilsiniz. Ama dağıtım için DockerHub kullanıyorsanız bunu eklemeniz daha iyi olacaktır.

Docker CLI ile Image’mızı oluşturmak için aşağıda ki komutu terminalimize yazıyor ve çalıştırıyoruz.

Not: Komutu proje dizininde çalıştırmayı unutmayalım. :)

docker build -t gkhnatn/dockertutorialapi .

Komutu çalıştırdıktan sonra aşağıdakine yakın bir çıktı görmelisiniz. Eğer Docker Extension’ını VSCode üzerine kurduysanız, sol tarafta Images’ların arasında oluşturduğumuz Image’ı görebilirsiniz.

Eğer kurulu değilse sorun değil aşağıda ki Docker CLI komutu ile de yeni oluşturduğumuz Docker Image’ı görebilirsiniz.

docker images

Komutu çalıştırdıktan sonra aşağıda ki çıktıda ki gibi Image’mızı görebiliriz.

Image’ımızı oluştu ve artık Run etmeye hazırız :)

Local’de Image çalıştırma.

Aşağıda ki Docker CLI kodu ile Image’ımızı run etmek çok kolay :)

docker run -p 8080:80 gkhnatn/dockertutorialapi

Komutu çalıştırdıktan sonra Image’ımız bir konteynır olarak çalışıyor olmalı. Burada -p ile verdiğimiz değerler önemli. Bilgisayarımızda ki 8080 portunu konteynır içinde ki 80 portuna eşleştirmiş oluyoruz.

Şimdi API’ye erişmek için 8080 portunu kullanacağız. Aşağıda ki Url’i tarayıcınız da açın. Ve uygulamanın çalıştığını göreceksiniz. :)

http://localhost:8080/WeatherForecast

Burada eşleştirdiğimiz 80 portu Dockerfile içerisinde Expose ettiğimiz porta karşılık geliyor.

Çalıştırdığımız konteynırı görmek için terminal de aşağıda ki Docker CLI komutunu yazıyoruz.

docker ps

Komutu çalıştırdıktan sonra aşağıda ki gibi çalışan konteynırı görebilirsiniz.

Veya benim ki gibi docker extension’ı yüklü VSCode üzerinde de görüntüleyebilirsiniz. :)

Konteynır’ı durdurmak için aşağıda ki Docker CLI komutu kullanılır.

Burada ki Container ID Image ismi değil, yukarıda ki docker ps komutunda ki çıktıda olan Container ID ‘dir.

docker stop <CONTAINER ID>

yada Docker Extension’ı yüklü ise sol üstte Containers alanından konteynır üzerine sağ tıklayıp stop diyebilirsiniz.

Her şey harika API’mızı bir konteynır içerisine yerleştirdik ve kendi localimizde çalıştırdık. Eğer uygulamayı sadece localimizde çalıştıracak olsaydık bu yaptıklarımız anlamsız olacaktı. Docker’ın gerçek gücü uygulamamızı başka herhangi bir yere kolaylıkla deploy etmemizi sağlamasıdır.

Oluşturduğumuz Image’ları başkalarına sunabilmeliyiz ki ihtiyacı olan herhangi biri istediği anda Image’ı indirip çalıştırabilsin. Bunu yapmamızı sağlayan ortamlardan biri de Docker Hub. :)

Docker Hub Nedir? Oluşturulan Image’ı Docker Hub’a pushlama

Docker Hub, Docker Image’larının paylaşılabileceği bir online servistir. Bu serviste Docker’ın kendisinin, ünlü şirketlerin ya da insanların oluşturduğu hazır Docker Image’ları bulunmaktadır.

Tarayıcınıza https://hub.docker.com/ yazarak Docker Hub’ı inceleyebilirsiniz.

Docker Hub üzerinde sizlerde bir hesap açıp kendi Image’larınızı yayınlayabilirsiniz. Bende oluşturduğum Docker Image’ımı kendi Docker Hub hesabım üzerinden yayınlayacağım.

Aşağıda Docker Hub hesabımda ki repositories’i görebilirsiniz. Önceden deneme yaptığım bir repo var sadece.

Şimdi yeni oluşturduğumuz Docker Image’ımızı bu hesabıma pushlayacağım.

Terminali açıyorum ve aşağıda ki komutla hesabıma giriş yapıyorum.

docker login

Bu komutu çalıştırıp username ve password bilgilerimi girip login işlemimi tamamlıyorum.

Ve aşağıda ki komut ile Image’ımı Docker Hub hesabıma pushluyorum.

docker push gkhnatn/dockertutorialapi

Burada pushdan sonra ki kısım oluşturduğum Image’ımın adı.

Komutu çalıştırdıktan sonra aşağıda ki çıktıyı alıyoruz.

İşlem bittikten sonra Image’ımı kontrol etmek için Docker Hub hesabımı açıyorum.

Ve Image’ım artık Docker Hub hesabımda yayında. Artık ihtiyacı olan herhangi biri Image’ıma rahatlıkla buradan ulaşabilir. Burada tekrar vurgulamak istiyorum, uygulamamı tüm bağımlılıkları ile beraber bir Image içerisinde yerleştirdim, ayağa kaldırmak için yapmam gereken tek şey Image’ı indirip container olarak run etmek. :)

Ayrıca oluşturduğumuz bu Image’ımızı Azure,AWS gibi bulut servislerine de kolaylıkla deploy edip yayınlayabiliriz.

Yazım burada sona erdi, umarım faydalı bir içerik olmuştur. :)

Yardımcı Kaynaklar;

https://docs.docker.com/

https://docs.microsoft.com/tr-tr/dotnet/core/tools

https://tr.wikipedia.org/wiki/Docker

--

--