Docker Container Nasıl Çalışır? Image, Container ve Volume Mantığı

Image katmanları, çalışan container, izolasyon ve kalıcı veriyi birbirinden ayıralım; Node.js örneğiyle build ve işletim kararlarını inceleyelim.

February 25, 2026•3 min read•

Docker kullanan bir projede en sık karışan üç kavram image, container ve volume'dür. Image uygulamanın paketlenmiş başlangıç içeriğini, container bu içeriğe dayanan çalışan ortamı, volume ise belirli verilerin container yaşam döngüsünden bağımsız tutulmasını sağlar.

Bu ayrım yalnızca terminoloji değildir. “Container'ı yeniden oluşturdum, yüklenen dosyalar kayboldu” veya “aynı image bende çalışıyor ama sunucuda çalışmıyor” gibi sorunları anlamanın başlangıcıdır.

Image: yeniden kullanılabilir paket

Image; uygulama kodu, runtime ve gerekli dosya sistemi içeriğini katmanlar halinde taşır. Dockerfile bu paketin nasıl oluşturulacağını tarif eder. Aynı image'dan birden fazla container başlatılabilir.

Katmanlı yapı build önbelleğine yardımcı olur. Kaynak koddan daha seyrek değişen bağımlılık tanımlarını önce kopyalamak, yalnızca kod değiştiğinde bağımlılık kurulumunun tekrar edilmesini önleyebilir. Image'ın katman ve metadata yapısı Docker image açıklamasında anlatılır.

Tag, örneğin task-api:1.0, bir isimdir ve başka içeriğe yöneltilebilir. Digest ise içeriği tanımlar. Tekrarlanabilir yayın için yalnızca “latest” adına güvenmek yerine hangi digest'in test edildiğini kaydetmek gerekir.

Container: image'dan başlatılan izole süreçler

Container bir sanal makineyle aynı mekanizma değildir. Linux container'ları Linux çekirdeğinin namespace ve cgroup gibi özelliklerinden yararlanır. Namespace'ler görünürlüğü, cgroup'lar kaynak yönetimini düzenlemeye yardımcı olur. Windows veya macOS üzerinde Linux container'ları çalıştırırken arada Linux sanal makinesi bulunabilir.

Container kendi işletim sistemi çekirdeğini image içinde başlatmak zorunda olmadığı için farklı bir maliyet ve izolasyon modeli sunar. Bununla birlikte “container içinde çalışıyor” ifadesi tek başına güçlü bir güvenlik sınırı garantisi değildir. Yetkiler, mount'lar ve host erişimi sonucu belirler. Temel model Docker container belgesinde açıklanır.

Bir Node.js image'ı oluşturalım

Aşağıdaki örnekte server.js doğrudan çalışan bir Node.js uygulaması, production bağımlılıkları da lock dosyasında tanımlıdır. TypeScript build gerektiren projede ayrıca build aşaması gerekir.

FROM node:22-bookworm-slim

WORKDIR /app
ENV NODE_ENV=production

COPY package*.json ./
RUN npm ci --omit=dev

COPY --chown=node:node . .
USER node

EXPOSE 3000
CMD ["node", "server.js"]

EXPOSE portu internete açmaz; image hakkında bilgi verir. Host'a erişim için ayrıca port yayınlamanız gerekir. Uygulamanın container içinde yalnızca 127.0.0.1'e değil uygun ağ arayüzüne, çoğunlukla 0.0.0.0'a bağlanması da önemlidir.

docker build -t task-api:local .
docker run --name task-api -p 127.0.0.1:3000:3000 task-api:local

Burada host portu yalnızca yerel loopback üzerinden erişilebilir. Herkese açık bir sunucuda ağ sınırlarını bilinçli tasarlayın. Runtime sürümünü projenizin destek matrisiyle uyumlu tutun; production için taban image güncellemelerini ve digest sabitlemeyi ayrı yönetin.

Build context'e ne gönderiyorsunuz?

.dockerignore dosyası gereksiz veya hassas dosyaların build context'e taşınmasını sınırlar:

node_modules
.git
.env
.env.*
npm-debug.log
coverage

Secret'ı image'a kopyalayıp sonraki adımda silmek yeterli değildir; önceki katmanda kalabilir. Yapılandırma ve sırları runtime sırasında uygun secret mekanizmasıyla sağlayın. Image'ın dağıtılabilir olması, içine production parolalarının da konulması gerektiği anlamına gelmez.

Yazılabilir katman neden kalıcılık sağlamaz?

Container image'ın üzerinde kendine ait yazılabilir bir katman kullanır. Container durdurulup aynı nesne yeniden başlatıldığında bu katman durabilir; fakat container silinip yeniden oluşturulduğunda ona bağlı içerik kaybolur.

Dolayısıyla “restart sonrası duruyor” gözlemi kalıcı depolamanın doğru kurulduğunu kanıtlamaz. Gerçek deployment yeni container oluşturuyorsa kullanıcı dosyalarını yazılabilir katmana bırakmak risklidir.

Volume, veriyi container nesnesinden ayırır. Bind mount ise host'taki belirli bir yolu container içine yansıtır. Development sırasında kaynak kodu paylaşmak için bind mount; yönetilen kalıcı veriler için volume sık kullanılır. Volume belgesi yaşam döngüsü ve mount davranışlarını ayrıntılandırır.

Kalıcılığı küçük bir deneyle gözlemlemek

Aşağıdaki deney yalnızca yeni bir örnek volume oluşturur:

docker volume create notes-demo
docker run --rm -v notes-demo:/data alpine:3.22 sh -c 'echo merhaba > /data/note.txt'
docker run --rm -v notes-demo:/data alpine:3.22 cat /data/note.txt

İlk container silinse de ikinci container aynı volume'daki dosyayı okuyabilir. Ancak volume bir yedekleme sistemi değildir. Disk arızası, yanlış silme veya bozuk uygulama yazımı veriyi yine kaybettirebilir.

Veritabanı için backup almak, canlı veri dizinini rastgele kopyalamaktan daha fazla tutarlılık gerektirebilir. Yedek kadar geri yükleme deneyi de önemlidir.

İşletim tarafında tamamlanması gerekenler

Image'ın küçük olması tek başarı ölçütü değildir. Sürecin root olmaması, kaynak limitleri, sağlık kontrolü, SIGTERM'e doğru yanıt, logların toplanması ve kalıcı verinin yedeklenmesi birlikte değerlendirilmelidir.

Container'ın yaşam döngüsünü geçici kabul edip kalıcı veriyi açıkça ayırdığınızda deployment daha basit hale gelir: uygulama değiştirilebilir, veri ise bilinçli şekilde korunur.