Volume — Docker #S1B4

Cihat Solak
lTunes Tribe
Published in
6 min readOct 25, 2021

MVC Dockerize — Docker #S1B3 bölümünden sonra containerlarda verileri nasıl depolayacağımız konusunu ele alacağız. Her bir durum için birer örnekle gerçek hayat senaryosunu yakalamadan önce bir varlığın stateful (durumsal) veya stateless (durumsuz) olması, etkileşim durumunun ne sıklıkla kayıt edildiğine ve bilgilerin nasıl saklandığına bağlı olduğu hatırlayalım.

Nedir? — Docker Volume
Nedir? — Docker Volume

Stateless (Durumsuz) 😴

Durum bilgisi olmayan uygulamalar tek başına anlaşılabilirlerdir. Geçmişe dayalı işlemlerle ilgili bilgi veya referans bulundurmazlar ve her işlem sanki ilk defa yapılıyormuş gibi davranış sergilerler. İşleyişe bakıldığında bir hizmet veya işlev sağlar. Çevrim içi arama motorları bu duruma bir örnektir. Arama motorunda bir şeyler aradığımız anda kesintiye uğrarsak yeni bir işlem başlatmamız yeterlidir. Stateless (Durumsuz) işlemleri otomat olarak düşünebiliriz, tek bir istek ve yanıt!

Stateful (Durumsal) 🤯

Durum bilgisi olan uygulamalar, çevrim içi bankacılık veya e-posta gibi döngüseldir. Geçmiş işlemler bağlamında gerçekleştirilirler ve mevcut işlem geçmişteki işlemlerden etkilenebilir. Fakat bu tür uygulamalar kesintiye uğrarsa içerik ve geçiş kaldığınız yerden devam edebilmeniz için saklanır. Stateful (Durumsal) işlemleri aynı kişiyle devam eden periyodik bir görüşme olarak düşünebiliriz.

Volume — Docker
Volume — Docker

Container’lar stateless (durumsuz) olarak inşaa edilmiştir. Çünkü doğası gereği taşınabilirliği ve esnekliği olmalıdır. Bu durumda Docker Volume, container içerisindeki verileri kalıcı hale getirmemize olanak sağlayan yöntemdir. Düşünsenize! container ile işimiz bittiğinde yapılan tüm işlem ve ayarları depolamasaydık aynı şeyleri tekrar tekrar yapmak durumunda kalmaz mıydık?🤔

Image’den bir container oluşturduğunuzda image içerisindeki katmanların en üstüne yazılabilen/okunabilen bir katman daha eklenir. Container içerisinde çalışan uygulamamız, veri kaydettiğinde oluşan bu katmana kaydedilir. Örneğin, Net Core MVC projemizde resim/pdf/excel vb. dosya kayıt edildiği zaman bu dosya image’den bir container ayağa kaldırdığımız zaman eklenen son yazılabilen/okunabilen katmana kaydediliyor. Haliyle de container silindiği zaman verilerde kayboluyor.

Şöyle düşünelim, bir container ayağa kaldırdık ve proje içerisinde geziniyoruz. Proje içerisine herhangi tipteki veri ya da veriler ekledik. Container’ı herhangi bir <T> ⏰ zamanında silersek eklemiş olduğumuz tüm verileri kaybederiz. Bunun haricinde bir de image’den 10 adet container ayağa kaldırdığımızda bu 10 container birbirinden bağımsız olduğu için kaydedilen verilen container özelinde olacaktır. Bu da demek oluyor ki bir container içerisindeki eklediğiniz dosyayı diğer container içerisinde görüntüleyemezsiniz. Herhangi birinde 10, herhangi bir diğerinde de 30 dosya kayıt 💾 edilebilir fakat hiçbir container diğerinin dosyalarına erişemez. İşte volume! Devreye giriyor. Volume burada verileri kalıcı kılmamıza olanak sağlıyor.

Yöntem 1: Bind Mount (İşletim Sistemi İçerisine)

İşletim sistemi üzerindeki belirlenen konuma containerlar tarafından dosyaların kaydedilme işlemidir. Tanımdan da anlaşılacağı üzere işletim sistemi üzerinde bir klasör 📂oluşturduğumuzu varsayalım. Tüm containerlara oluşturmuş olduğumuz klasör yolunu tanımlıyoruz. Bu durumda containerlar artık kendi içlerinde veri tutmayacak belirlemiş olduğum konuma depolama işlemi yapacaktır. Merkezi bir nokta oluşturduğumuz için tüm containerlar birbirlerinin verilerine erişebilecektir. Yani 1 numaralı container’ın eklemiş olduğu müzik 🎼 dosyasını 12 numaralı containerda görüntüleyebileceğiz.

Yöntem 2: Volume (Docker İçerisine)

Docker CLI tarafından yönetilen ve verileri işletim sistemi üzerinde değil de kalıcı kılmak için docker’ın kendi içerisinde bir alan oluşturma işlemine denir. Örneğin docker cli ile “dosyalar” isminde bir volume docker volume create dosyalar oluşturuyorsunuz. Sonrasında container ayağa kaldırırken oluşturduğumuz volume tanımını entegre ediyoruz. Bu sayede veriler işletim sistemi üzerinde değil, docker içerisindeki özel bir alanda depolanıyor. Volume içerisindeki datalar container’dan bağımsızdır. Container’ı sildiğinizde volume içerisindeki veriler silinmez. Ayrıca birden fazla container aynı volume’ü kullanabilir.

  • Oluşturma: docker volume create {volumeName}
  • Listeleme: docker volume ls
  • Detay görüntüleme: docker volume inspect {volumeName}
  • Bir veya birden fazla silme: docker volume rm {volumeName} {volumeName}
  • Tümünü silme: docker volume prune

Volume İle Bind Mount Oluşturmak Arasındaki Fark Nedir?🤼‍♀️

  • Volume’ler docker içerisinde olduğundan dolayı CLI komutlarıyla yönetimi sağlayabiliriz.
  • Volume’leri sadece kendi bilgisayarımızda değil, cloud ☁️ ortamlardaki volume’lerde de depolayabiliriz ama bind mount’da böyle bir yöntem yoktur.
  • Volume’ler hem 🐧 Linux, hem de Windows containerlarda kullanılabilir.
  • Volume’lerin migrate ve yedek alınması bind mount’a göre daha basittir. Çünkü bind mount’da veriler işletim sistemi üzerinde tutulduğu için her şeyi el ile (manuel) yapmak zorundayız. Volume tarafında ise docker 🐳 içerisinde özel bir alan oluşturulduğundan dolayı yönetim tamamen docker’a aittir.

Sonuç olarak bind mount ve volume’un yapmış olduğu işlem verileri kalıcı kılmaktır ancak bunu yaparken farklı yöntemler kullanmaktadır.

Tmpfs Mount (Belleğe)

Containerlar tarafından üretilen datalar işletim sisteminin belleğinde depolanır. Bu senaryoda containerlar verileri okuyabilir veya çalışan tüm containerlar ilgili belleğe veri depolayabilir.

Gerçek Hayat Senaryoları 🎬

Öncelikle tüm image’lar aşağıdaki Dockerfile dosyasından oluşturulacaktır.

FROM mcr.microsoft.com/dotnet/sdk:5.0 as sdkbuild
WORKDIR /app
COPY *.csproj .
RUN dotnet restore
COPY . .
RUN dotnet publish NetCoreDockerizeWebApp.csproj -c Release -o out
FROM mcr.microsoft.com/dotnet/aspnet:5.0
WORKDIR /app
COPY --from=sdkbuild /app/out .
ENV ASPNETCORE_URLS="http://*:2500"
ENTRYPOINT ["dotnet", "NetCoreDockerizeWebApp.dll"]
Container Oluşturma — Docker Volume
Container Oluşturma — Docker Volume

docker build --nocache -t aspnetcoremvcdockervolume . komutu ile Dockerfile dosyasından bir image oluşturuyoruz. --no cache parametresiyle image oluşurken herhangi bir katmanın cache üzerinden alınmamasını sağlıyorum.

Daha sonra docker run -d -p 5000:2500 --name volumetestcontainer1 3d7 docker run -d -p 5000:2500 --name volumetestcontainer2 3d7 komutlarla oluşturmuş olduğum image’den 2 adet container oluşturuyorum.

Birden fazla container ile çalışmak — Docker Volume
Birden fazla container ile çalışmak — Docker Volume

5000 ve 5001 portundan 2 adet container ayağa kaldırdım ve 5000 portundaki uygulama üzerinden bir resim ekleme işlemi gerçekleştirdim. 5000 portundan eklediğim resim 5001 portundaki uygulamaya yansımadı. Çünkü containerlar için volume, bind mount gibi bir bağlantı sağlamadığımdan dolayı uygulama eklenen dosyaları kendi içerisinde depoluyor. Bu nedenledir ki 5000 portunda eklenen resim 5001 portuna yansımadı.

Container ayaktayken eklenen verilere container durdurulduktan sonra erişemeyiz. Bu gibi durumlara çözüm için volume vardır.

Örnek 1 — Bind Mount

Masaüstünde “dcroot” adında rastgele isimlendirdiğim klasör oluşturdum.

Container’a bind mount tanımlamak — Docker Volume
Container’a bind mount tanımlamak — Docker Volume

Yukarıda powershell 👨‍💻 üzerinde de görüleceği üzere, masaüstünde oluşturmuş olduğum “dcroot” klasörünün dosya yoluyla birlikte bind mount olarak 2 adet container ayağa kaldırıyorum. Mantık şu; Uygulama target kısmındaki img klasöründen veri çekerken docker araya girip source kısmındaki hedefe yönlendiriyor.

Bind mount — Docker Volume
Bind mount — Docker Volume

Containerları ayağa kaldırdıktan sonra 5000 portundaki uygulamada resim kaydetme 💾 işlemi gerçekleştirdim. Bu resim masaüstündeki belirlemiş olduğum “dcroot” klasörüne kaydedildiği için (işletim sistemi — bind mount) bu resmi 5001 portundaki uygulamada da görüntüleyebildim. 3, 4, 5…99 container’da ayağa kaldırsam hepsi bu resimlere erişebilir.

Örnek 2 — Volume

İlk olarak docker volume create img komutuyla “img” adında volume oluşturmamız gereklidir. Volume oluşturduktan sonra container ayağa kaldırırken --volume parametresiyle hedef belirlemeliyiz.

Birden fazla container’a volume tanımlamak — Docker Volume
Birden fazla container’a volume tanımlamak — Docker Volume

--volume img:/app/wwwroot/img oluşturmuş olduğumuz img adında volume’ü dosya yoluyla eşleştiriyoruz. Volumeler hedef dosya yolunun içerisindeki verileri kendisine kopyalar. Yani container ayağa kalktığı zaman belirtmiş olduğumuz “img” içerisindeki veriler ilk olarak volume’e kopyalanır sonra container ayağa kalkar.

Nasıl Yani?

Container ayağa kalkarken gidiyor wwroot içerisindeki img klasörü içerisindeki dosyaları önce volume’e kaydediyor 💾 arkasından container ayağa kalkıyor. 5000 portundaki uygulama üzerinde bir resim eklediğimde bu 5001 portundaki uygulamayı da etkileyecektir. 5001 portundan resim sildiğimde bu 5000 portunu da etkileyecektir.

Peki Volume Nasıl Silinir?

Volume silmek — Docker Volume
Volume silmek — Docker Volume

docker ps komutuyla beraber ayakta olan container listesini alabiliriz. Ardından containerları silelim. docker rm 25c 4c2 --force komutuyla beraber çalışan containerları siliyorum. Artık volume silebiliriz. docker volume rm img ile oluşturduğumuz volume’ü siliyoruz.

--

--