Docker'da Ollama: Volume & Resource Limit Rehberi
Merhaba! Bu yazıda Docker içinde Ollama'yı ayağa kaldıracağız, bir modeli çalıştırıp kalıcı hale getireceğiz ve konteynerin kullandığı sistem kaynaklarını nasıl sınırlandırabileceğimizi öğreneceğiz. İşin mutfağına ineceğiz fakat gereksiz yerlere pek temas etmeyeceğiz; amacımız her adımın mantığını kavramak diyebilirim. Hadi başlayalım!

Ayrıca evet, yine tüm görsel içerikler elle hazırlandı. Blog yazısını destekleyen unsurlar olduklarını düşünüyorum...
Adım 1.1: Neden?
Ollama'yı bilgisayarına doğrudan kurabilirsiniz, bu en basit yol. ¯\_(ツ)_/¯
Neden bu Ollama'yı konteyner içine koyalım ki?
Çünkü Docker sana izolasyon verir. Ollama'nın kendisi, ayarları ve indirdiğin modeller hep konteynerin içinde yaşar; ana sistemine karışmaz. Docker sana parametrelerle, modellerle ve araçlarla serbestçe takılma imkanı verir. Bir gün "bu kurulumla işim bitti" dediğinde tek yapman gereken konteyneri silmek.
E, ne oldu? Sistemin tertemiz kaldı. ദ്ദി(ᵔᗜᵔ)
Adım 2.1: Proje Yapısı
Uzatmadan başlayalım. Önce projemiz için bir çalışma alanı açalım:
mkdir ollama-docker
cd ollama-docker
Bu yazıda ekstra bir config dosyasına (docker compose) ihtiyacımız yok, çünkü Ollama'nın kendisi zaten konteyner içinde çalışacak şekilde hazır bir image olarak geliyor. Asıl önemli olan kısım, birazdan konuşacağımız volume (kalıcı depolama alanı) olacak.
Adım 3.1: Image'ı Çekmek
Ollama'nın resmi Docker image'ını indirelim:
docker pull ollama/ollama
Bir Hata ve Çözümü
Ben aşağıdaki hatayı almıştım, çözmek için Docker Desktop uygulamasın başlatıp, arka planda Docker'ın çalışmasını sağlamam yetmişti: ufuk@192 ollama-docker % docker pull ollama/ollama Using default tag: latest failed to connect to the docker API at unix:///Users/ufuk/.docker/run/docker.sock; check if the path is correct and if the daemon is running: dial unix /Users/ufuk/.docker/run/docker.sock: connect: no such file or directoryBu imaj dosyası biraz büyük (yaklaşık 3 GB), çünkü içinde Ollama'nın çalışma zamanı (runtime) barınıyor. Merak etmeyin, bir kere indirdikten sonra tekrar indirmene gerek kalmayacak.
Adım 4.1: Konteyneri Çalıştırmak
Şimdi asıl kısma geldik. Aşağıdaki komutu terminaline yapıştır:
docker run -d \
--name ollama \
-p 11434:11434 \
-v ollama-data:/root/.ollama \
--memory="6g" \
--cpus="4" \
ollama/ollama
Aşağıdaki docker ps komutunu kullanarak Ollama'nın arkada doğru bir şekilde çalışıp-çalışmadığını teyit edebilirsiniz.
ufuk@192 ollama-docker % docker ps
IMAGE COMMAND CREATED STATUS NAMES
ollama/ollama "/bin/ollama serve" 4 seconds ago Up 3 seconds ollama
Yukarıdakine benzer bir geri dönüş aldıysanız meraklanmayın, Ollama arkada düzgün bir şekilde çalışıyor demektir.
Ollama'yı çalıştırırken yazdığımız parametreler biraz karmaşık görünüyor olabilir, hemen parça parça açalım. Parametrelerin detaylarını anlatmak bayağı eğlenceli...
Adım 4.2: Komutu Anlamak
-d: Konteyneri arka planda (detached) çalıştırır, aktif terminal sessionunuzu kilitlemez.--name ollama: Konteynere sabit bir isim veriyoruz, ileride komut yazarken kolaylık sağlayacak.-p 11434:11434: Ollama, kendi sabit API'sini 11434 portundan sunuyor. Bu satırla, bilgisayarınızdaki 11434 portunu konteynerin içindeki 11434 portuna bağlıyoruz. Böylecelocalhost:11434üzerinden Ollama'ya ulaşabiliyoruz.-v ollama-data:/root/.ollama: Bu, birazdan detaylı konuşacağımız kalıcılık (persistence) ayarı. Asıl olay buralarda.--memory="6g"ve--cpus="4": Kaynak sınırlaması, bu da ayrı bir başlık altında ele alacağımız ve üstüne düşülmesi gereken bir konu.

Adım 5.1: Neden Volume Şart?
Burada duralım ve biraz düşünelim. Ollama, çektiğimiz (pull ettiğimiz) modelleri konteyner içinde /root/.ollama klasörüne kaydediyor. Sorun şu ki: Docker konteynerleri geçicidir (ephemeral). Konteyneri silerseniz, içindeki her şey - indirdiğiniz model de dahil - yok olur.
Volume, bu klasörü konteynerin dışına, Docker'ın kendi yönettiği bir depolama alanına bağlamanın en sağlıklı yolu. Yukarıdaki komutta kullandığımız ollama-data bir named volume (isimli birim). Docker bunu sizin için diskte bir yerde tutuyor, siz bunun nerede olduğuyla uğraşmıyorsunuz bile.
Mantığı şu: Konteyner gelip geçici bir kabuk, evet. Model dosyaları ise kalıcı veri. -v ollama-data:/root/.ollama parametresi ile, "konteyner içindeki /root/.ollama klasörüne her ne yazılırsa, aslında ollama-data adlı kalıcı alana yazılsın" demiş oluyorsun. Model dosyalarını Matrix'ten kaçırıyorsun anlayacağın. ( ╹ -╹)
Bunu test edebiliriz: Konteyneri sil, tekrar aynı -v ollama-data:... parametresiyle çalıştır. İndirdiğimiz model hâlâ orada duruyor olacak, çünkü onu tutan aslında konteyner değil, volume'du.
docker volume ls
Bu komutla oluşturulan volume'u görebiliriz. ollama-data listede karşınıza çıkmalı.
Adım 5.2: Neler Oluyor?
"Named volume" dediğimiz şey aslında sihirli bir şey değil, Docker'ın sizin için yönettiği sıradan bir dizin. Docker Desktop kullandığınızı tahmin ettiğim için bu dizin, sisteminizin kendisinde değil, Docker'ın içinde çalıştığı Linux sanal makinesinin (VM) diskinde duruyor. Volume'un gerçek konumunu görmek için VM'in içine girmeye gerek yok, Docker size bunu zaten söylüyor:
docker volume inspect ollama-data
Oluşturma tarihi, ayarlar ve sürücüler gibi detayların olduğu bir çıktı almış olmanız gerekiyor. Çıktıda Mountpoint adında bir alan göreceksiniz. Aşağıdakine benzeyecektir:
"Mountpoint": "/var/lib/docker/volumes/ollama-data/_data"
İşte indirdiğiniz model dosyaları tam olarak bu yolda duruyor. Docker, konteyner ayağa kalkarken bu klasörü, konteynerin içindeki /root/.ollama yoluna bir bind mount gibi bağlıyor. Yani konteyner içindeki süreç (bu blog yazısı için Ollama yani) o klasöre bir dosya yazdığında, aslında doğrudan _data klasörüne yazmış oluyor; ortada bir kopyalama, senkronizasyon falan yok, aynı verinin iki farklı yoldan görünen hali bu.
Burada bir şeyleri netleştirmek lazım: Bu bağlama işlemine teknik olarak "bind mount" dememizin sebebi, işletim sisteminin bir dizini başka bir yola bağlama (mount) mekanizmasını kullanması. Ama "named volume" ile "bind mount" seçeneğini birbirine karıştırmayın: named volume kullandığınızda (bizim ollama-data örneğimizde olduğu gibi) Docker, _data klasörünün tam olarak nerede durduğunu kendi yönetir ve siz bununla hiç uğraşmazsınız; bind mount'ta ise siz host üzerinde -v /kendi/klasorum:/root/.ollama gibi keyfi bir yolu doğrudan gösterirsiniz. İkisi de aynı alttaki mekanizmayı (kernel'in bir dizini başka bir yola bağlaması) kullanır, fark sadece kimin o klasörün konumunu yönettiğidir.
Bunu bilmek şunun için önemli: Volume'u silmeden konteyneri silip yeniden oluşturduğunuzda, Docker aynı _data klasörünü yeni konteynerin /root/.ollama yoluna tekrar bağlıyor. Model dosyaları hiç bir şekilde yer değiştirmiyor, sadece hangi konteynerin ona baktığı değişiyor.

Adım 6.1: Model Çekmek ve Çalıştırmak
Konteyner ayakta, şimdi içine girip bir model indirelim. Sisteminizde rahat çalışacağını düşündüğüm, hafif bir model seçelim:
docker exec -it ollama ollama pull llama3.2:3b
docker exec: Zaten çalışan bir konteynerin içinde komut çalıştırmanızı sağlar.-it: Terminali interaktif moda alır, indirme ilerlemesini canlı olarak görebilmenizi sağlar.ollama pull llama3.2:3b: Konteyner içindeki Ollama'ya "şu modeli indir" diyorsunuz.3bkısmı modelin parametre sayısını (3 milyar) belirtiyor. Bu, donanımınız için makul olmayan bir boyutsa değiştirmekten çekinmeyin.
İndirme bitince modeli çalıştırın:
docker exec -it ollama ollama run llama3.2:3b
Karşınıza bir sohbet ekranı gelecek, doğrudan yazabilirsiniz. Çıkmak için /bye yazmanız yeterli.

Bir proje geliştiriyorsanız API üzerinden de aynı modele istek atabilmeniz, soru sorabilmeniz mümkün:
curl http://localhost:11434/api/generate -d '{
"model": "llama3.2:3b",
"prompt": "Docker nedir, tek cümleyle anlat.",
"stream": false
}'
Bir dakika... Model, prompt falan nedir biliyoruz da, stream nedir? Demiş olabilirsiniz...
stream parametresi, Ollama'nın cevabı size nasıl göndereceğini belirliyor. false dediğimiz zaman, model tüm cevabı üretene kadar bekliyoruz ve sonunda tek bir JSON içinde komple cevap geliyor; true yapsaydık, gündelik kullandığınız chatbotların arayüzlerinde gördüğümüz gibi kelime kelime, parça parça (token token) akan bir cevap alırdık, her parça ayrı bir JSON satırı olarak gelirdi. Burada false kullanmamızın sebebi basit: curl ile test ederken tek seferde okunabilir, düzgün bir çıktı görmek istiyoruz; bir arayüz veya chatbot inşa ediyor olsaydık, kullanıcıya "yazıyormuş" hissi vermek için true tercih edilirdi. Psikolojik yani!
Adım 7.1: Neden Sınır Koymalısınız?
Sisteminiz güçlü olabilir, bunu bilemem. Ama sınırsız olmadığına eminim. Eğer konteynere hiç kaynak sınırı koymazsanız, Ollama gerektiğinde makinenin tüm RAM'ini ve CPU'sunu tüketmeye çalışabilir. Bu da diğer uygulamaların (tarayıcı, müzik, IDE) yavaşlamasına, hatta sistemin bir yerden sonra kilitlenmesine dahi yol açabilir.
--memory ve --cpus parametreleri tam olarak da bunu önlemek için var. Mantığı basit: Docker'a "bu konteyner en fazla şu kadar RAM ve şu kadar CPU çekirdeği kullanabilirsin" diyorsunuz. Konteyner bu sınırı aşmaya çalışırsa, Docker onu durdurur (memory limit için) ya da bilerek yavaşlatır (CPU limit için).
--memory="6g" \
--cpus="4"
--memory="6g": Konteynere en fazla 6GB RAM kullanma izni veriyorsunuz.llama3.2:3bgibi bir model çalışırken genelde 3-4GB RAM yeter, 6GB biraz nefes payı bırakıyor diyelim.--cpus="4": Konteynerin en fazla 4 CPU çekirdeği kullanabileceğini söylüyorsunuz.
Bu parametreleri zaten yukarıda, Ollama'yı ilk defa çalıştırırken yazmıştık. Hatırlamış olduk.
Bu sayıları modelin boyutuna göre ayarlamanız gerekir. Daha büyük bir model çalıştıracaksanız (örneğin 8b bir model), --memory değerini de daha yukarılara çekmeniz gerekir; yoksa Ollama, konteyner sınırına takılıp modeli dahi yükleyemeyebilir.

Adım 7.2: --memory Aşılırsa Ne Olur?
Burada bilinmesi gereken önemli bir ayrım var: --memory ve --cpus aslında birbirinden çok farklı iki şekilde uygulanıyor.
--cpus="4" "yumuşak" bir sınır denebilir. Docker, arka planda Linux'un cgroups (control groups) mekanizmasını kullanarak konteynerin CPU zamanını kısıtlıyor, yani konteyner 4 çekirdekten fazlasını asla göremiyor ama bu sınıra çarptığında konteyner çökmüyor, sadece yavaşlıyor. Model, cevabı biraz daha geç üretiyor, hepsi bu. Hayati bir parametre değil anlayacağınız.
--memory="6g" ise "sert" bir sınır. Konteyner bu sınırı aşmaya çalıştığı anda, Linux çekirdeği devreye giriyor ve OOM Killer (Out-Of-Memory Killer) denen bir mekanizmayla konteynerin içindeki süreci (bizim durumumuzda Ollama'yı) doğrudan sonlandırıyor. Yani RAM sınırını aştığında konteyner yavaşlamıyor, komple vefat.
Bunu görmek isterseniz, konteyneri bilerek çok düşük bir bellekle çalıştırıp büyük bir model yüklemeyi deneyebilirsiniz: (Bence denemeyin de... Pek gereği yok. :P)
docker run -d --name ollama-test --memory="1g" ollama/ollama
docker exec -it ollama-test ollama run llama3.2:3b
Model belleğe sığmaya çalışırken konteyner aniden duracak. Kontrol ederseniz:
docker inspect ollama-test --format='{{.State.OOMKilled}}'
Bu komut true döndürüyorsa, tam olarak yukarıda anlattığım şey gerçekleşmiş demektir: OOM Killer devreye girmiş ve süreci sonlandırmış.
Bir de swap konusuna değinelim. Biz kendimiz özellikle bir ayar yapmadık, çünkü Docker'da varsayılan olarak --memory-swap, --memory ile aynı değere ayarlanır. Yani ekstra bir şey belirtmezseniz konteynerin swap alanı kullanma hakkı yok diyebiliriz. İsterseniz bunu ayrıca açabilirsiniz:
--memory="6g" --memory-swap="8g"
Bu, konteynerin 6GB RAM'in üstüne çıkabileceği, ama sadece 2GB'lık ekstra bir swap alanına kadar (8GB - 6GB) nefes alabileceği anlamına gelir. Ancak şunu bilmek gerekir: swap, disk üzerinde çalıştığı için RAM'den çok ama çok daha yavaştır. Bir LLM için swap'a düşmek genelde "çalışıyor ama sürünüyor" anlamına gelir, bu yüzden bu ayarı orta güçlü sistemlerde çoğu zaman varsayılan (swap kapalı) bırakmak daha sağlıklı bir tercihtir.
Sınırların gerçekten uygulandığını görmek isterseniz:
docker stats ollama
Bu komut size konteynerin o an ne kadar RAM ve CPU kullandığını canlı olarak gösterir. --memory="6g" demiştik, MEM USAGE / LIMIT sütununda bu dediğimi doğrulayabilirsiniz.
Adım 8.1: Kontroller
Sona yaklaşıyoruz. Her şeyin yolunda gittiğinden emin olalım.
Konteyner durumunuzu kontrol etmek için:
docker ps
Loglara bakmak isterseniz:
docker logs ollama
İndirdiğiniz modellerin listesini görmek için:
docker exec -it ollama ollama list
Docker bir derya deniz. Daha birçok farklı şeyi kontrol edip konteynerinizin ne durumda olduğunu öğrenebilirsiniz Ama yazıyı çok uzatmamak adına kısa keseceğim.
Adım 9.1: Kapanış ve Temizlik
Adım 9.1.1: Konteyneri Durdurmak
docker stop ollama
docker start ollama ile tekrar uyandırabilirsiniz, volume sayesinde modelleriniz hâlâ yerinde duruyor olacaktır!
Adım 9.1.2: Konteyneri Silmek
docker rm -f ollama
Unutmayın, bu komut sadece konteyneri siler. ollama-data volume'u ve içindeki modeller hala yerlerinde duruyor, çünkü onlar konteynerden bağımsız olarak yaşıyor. Bahsetmiştik.
Adım 9.1.3: Volume'u Silmek
docker volume rm ollama-data
Eğer modelleri de tamamen silmek istiyorsanız volume'u silme yoluna başvurabilirsiniz.
Bunu yaptıktan sonra tekrar aynı modeli kullanmak isterseniz, baştan indirmeniz gerekecektir.
Sonuç
Artık Ollama'yı Docker içinde çalıştırabiliyor, modellerinizi konteyner silinse bile kaybetmeyecek şekilde kalıcı hale getirebiliyor ve sisteminizin kaynaklarını Ollama'nın sömürmesine izin vermeden sınırlandırabiliyorsunuz. Parametreleri anlamlandırabilmeniz ise cabası.
Bir sonraki yazımda tüm bu yaptıklarımızı docker-compose ile daha derli toplu bir hale getireceğiz. O yazı da muhtemelen 2026 yılı içerisinde gelir. Gelmeyebilir de... Keyfime bağlı.
( -_•)

Sonraki yazılarımda görüşmek üzere.