Image Yönetimi — pull, push, tag, inspect, history
Bir önceki derste image'ın ne olduğunu, katmanlı yapısını ve varyantlarını öğrendik. Şimdi sıra geldi bu image'larla günlük çalışmaya — indirme, etiketleme, inceleme, paylaşma ve temizleme. Bu derste öğreneceğin komutlar, Docker ile çalışırken her gün kullanacağın temel operasyonlar.
Bir fotoğrafçı düşün. Fotoğraflarını çeker (build), etiketler (tag), albümde saklar (local storage), müşteriye gönderir (push), gerektiğinde geri alır (pull). Bazılarını siler, bazılarını inceler. Docker image yönetimi de tam bu iş akışını takip ediyor.
docker pull — Image İndirme
docker pull, Docker Hub'dan (veya başka bir registry'den) image'ı bilgisayarına indiren komut. Hadi detaylıca bakalım.
Temel Kullanım
En basit hali:
docker pull nginxBu komut nginx:latest tag'ini indirir. Ama bir önceki derste öğrendiğimiz gibi, latest güvenilir değil! Her zaman belirli versiyon kullanmalıyız:
docker pull nginx:1.25.4 # Belirli versiyon
docker pull node:20-alpine # Alpine varyantı
docker pull postgres:16 # PostgreSQL 16Pull sırasında konsoldaki çıktıya dikkat edelim:
1.25.4: Pulling from library/nginx
a2abf6c4d29d: Pull complete
a9edb18cadd1: Pull complete
589b7251471a: Pull complete
186b1aaa4aa6: Pull complete
b4df32aa5a72: Pull complete
a0bcbecc962e: Pull complete
Digest: sha256:abc123def456...
Status: Downloaded newer image for nginx:1.25.4
docker.io/library/nginx:1.25.4Her "Pull complete" satırı bir katman. Altı katman indirildi ve birleştirildi. En altta Digest var — bu image'ın benzersiz SHA256 hash'i. Değişmez, güvenilir bir referans.
Katman Paylaşımı — Bant Genişliği Tasarrufu
Docker'ın en güzel özelliklerinden biri katman paylaşımı. Bunu görmek için iki farklı Node.js image'ını indirelim:
# İlk image — tüm katmanlar indirilir
docker pull node:20-alpine
# a2abf6c4d29d: Pull complete
# f19e5a72315b: Pull complete
# 7c2d5c8e3a05: Pull complete
# Tamamı indirildi
# İkinci image — paylaşılan katmanlar atlanır!
docker pull node:20-slim
# a2abf6c4d29d: Already exists ← Bu katman zaten var!
# b8c3a12e5f67: Pull complete ← Sadece farklılar indirildi"Already exists" mesajını gördün mü? Docker, daha önce indirdiği katmanları tekrar indirmiyor. Bu, özellikle CI/CD pipeline'larında çok önemli — her build'de aynı base image'ı tekrar tekrar indirmek yerine, sadece değişen katmanları çekiyorsun.
Platform Seçimi
Apple Silicon (M1/M2/M3) Mac kullanıyorsan bazen AMD64 image'a ihtiyacın olabilir — mesela bazı image'lar henüz ARM64 desteği eklememiştir:
# Belirli platformu zorla
docker pull --platform linux/amd64 nginx:1.25.4
# Raspberry Pi için ARM
docker pull --platform linux/arm64 nginx:1.25.4Normalde Docker platformunu otomatik algılar ve doğru olanı çeker. Ama bazen "no matching manifest" hatası alırsan, bu flag işe yarar.
Digest ile Pull — En Güvenli Yöntem
Tag'ler değişebilir ama digest asla değişmez:
# Image'ın digest'ini bul
docker inspect nginx:1.25 --format '{{index .RepoDigests 0}}'
# nginx@sha256:6db391d1c0cfb30588ba0bf72ea999404f2764f...
# Digest ile pull — %100 aynı image garanti
docker pull nginx@sha256:6db391d1c0cfb30588ba0bf72ea999404f2764f...Production'da maximum güvenlik istiyorsan digest kullan. Ama pratikte semantic versioning (nginx:1.25.4) çoğu senaryo için yeterli.
docker images — Image Listeleme
Bilgisayarındaki image'ları listelemek için:
docker images
# REPOSITORY TAG IMAGE ID CREATED SIZE
# nginx 1.25 a8758716bb6a 2 weeks ago 187MB
# node 20-alpine a8c5be9b1d03 3 weeks ago 130MB
# postgres 16 f1d524c76f35 1 week ago 432MBFiltreleme ve Formatlama
Çok sayıda image'ın varsa filtreleme çok işe yarar:
# Belirli bir repository
docker images node
# Sadece node image'ları
# Dangling image'lar (tag'siz)
docker images -f "dangling=true"
# Sadece ID'ler (scripting için)
docker images -q
# Boyuta göre sıralama — en büyükler en üstte
docker images --format "{{.Size}}\t{{.Repository}}:{{.Tag}}" | sort -rh
# 1.1GB node:20
# 432MB postgres:16
# 187MB nginx:1.25
# 130MB node:20-alpineBu son komut çok kullanışlı. "Disk neden doldu?" diye merak ettiğinde, en büyük image'ları hemen görebilirsin.
Gerçek Disk Kullanımı
docker images komutu her image'ın boyutunu gösterir ama paylaşılan katmanları sayar. Gerçek disk kullanımı farklı olabilir:
docker system df
# TYPE TOTAL ACTIVE SIZE RECLAIMABLE
# Images 15 3 4.2GB 3.1GB (73%)
# Containers 5 2 120MB 80MB (66%)
# Build Cache - - 2.1GB 2.1GB
# Local Volumes 8 3 1.5GB 800MB (53%)Bu komut sana Docker'ın toplamda ne kadar disk alanı kullandığını gösterir. "Reclaimable" sütunu temizlenebilecek alanı gösterir — prune komutlarıyla bu alanı geri kazanabilirsin.
docker tag — Image Etiketleme
Tag, bir image'a yeni bir isim vermek. Çok önemli bir nokta: tag bir kopya oluşturmaz. Aynı image'a sadece yeni bir referans ekler.
docker tag nginx:1.25 my-nginx:latest
docker tag nginx:1.25 my-nginx:v1.0
docker tag nginx:1.25 my-nginx:productionHepsini listeleyelim:
docker images | grep -E "nginx|my-nginx"
# nginx 1.25 a8758716bb6a 187MB
# my-nginx latest a8758716bb6a 187MB ← Aynı ID!
# my-nginx v1.0 a8758716bb6a 187MB ← Aynı ID!
# my-nginx production a8758716bb6a 187MB ← Aynı ID!Dört farklı isim, hepsi aynı IMAGE ID'ye sahip. Disk'te tek bir kopya. Bu çok verimli.
Registry İçin Tag'leme
Image'ı bir registry'ye push etmeden önce, doğru formatta tag'lemen gerekir. Her registry'nin kendi formatı var:
# Docker Hub: username/repository:tag
docker tag myapp:latest tolgahan/myapp:v1.0.0
# GitHub Container Registry: ghcr.io/username/repository:tag
docker tag myapp:latest ghcr.io/tolgahan/myapp:v1.0.0
# AWS ECR: account.dkr.ecr.region.amazonaws.com/repository:tag
docker tag myapp:latest 123456789.dkr.ecr.eu-west-1.amazonaws.com/myapp:v1.0.0
# Özel registry: registry.domain.com/repository:tag
docker tag myapp:latest registry.mycompany.com/myapp:v1.0.0Production Tag Stratejisi
Production'da her image'a birden fazla tag vermek iyi bir pratik:
VERSION="1.2.3"
COMMIT=$(git rev-parse --short HEAD)
DATE=$(date +%Y%m%d)
docker build \
-t myapp:${VERSION} \
-t myapp:${VERSION}-${COMMIT} \
-t myapp:latest \
-t myapp:${DATE} \
.Bu sayede:
myapp:1.2.3→ Versiyon numarasıyla bulabilirsinmyapp:1.2.3-abc123f→ Hangi git commit'ten build edildiğini bilirsinmyapp:latest→ Geliştirmede hızlıca erişebilirsinmyapp:20240115→ Tarih bazlı sorgulama yapabilirsin
docker inspect — Image'ı Derinlemesine İnceleme
docker inspect bir image'ın (veya container'ın) tüm metadata'sını JSON olarak verir. Bu komut bir dedektif aracı gibi — image hakkında bilmek isteyebileceğin her şey burada.
Tüm Bilgiyi Gör
docker inspect nginx:1.25 | jq .Çıktı çok uzun olacak — yüzlerce satır JSON. Her şeyi bir arada görmek için güzel ama pratikte belirli bilgilere ihtiyacın olacak.
Spesifik Bilgi Çekme — Format Kullanımı
--format flag'i ile istediğin bilgiyi çıkarabilirsin:
# Container başladığında çalışacak varsayılan komut
docker inspect nginx:1.25 --format '{{json .Config.Cmd}}' | jq .
# ["nginx", "-g", "daemon off;"]
# Entrypoint
docker inspect nginx:1.25 --format '{{json .Config.Entrypoint}}' | jq .
# ["/docker-entrypoint.sh"]
# Açık portlar
docker inspect nginx:1.25 --format '{{.Config.ExposedPorts}}'
# map[80/tcp:{}]
# Environment variable'lar
docker inspect nginx:1.25 --format '{{json .Config.Env}}' | jq .
# ["PATH=...", "NGINX_VERSION=1.25.4", ...]
# İşlemci mimarisi
docker inspect nginx:1.25 --format '{{.Architecture}}'
# amd64
# Oluşturma tarihi
docker inspect nginx:1.25 --format '{{.Created}}'
# 2024-01-15T10:30:00.000000000Z
# Katman sayısı
docker inspect nginx:1.25 --format '{{len .RootFS.Layers}}'
# 7
# Çalışma dizini
docker inspect nginx:1.25 --format '{{.Config.WorkingDir}}'
# (boş ise /)
# Container'ın hangi kullanıcıyla çalışacağı
docker inspect nginx:1.25 --format '{{.Config.User}}'
# (boş ise root)Bu bilgiler ne işe yarar? Mesela birinin oluşturduğu bir image'ı kullanacaksın ama dokümantasyonu yok. docker inspect ile hangi portu açıyor, hangi komutla başlıyor, hangi environment variable'ları kullanıyor — hepsini öğrenirsin.
İki Image'ı Karşılaştır
Pratik bir kullanım senaryosu: iki image'ı karşılaştırmak.
echo "=== node:20 vs node:20-alpine ==="
echo "Boyut:"
echo " node:20: $(docker inspect node:20 --format '{{.Size}}' | numfmt --to=iec)"
echo " node:20-alpine: $(docker inspect node:20-alpine --format '{{.Size}}' | numfmt --to=iec)"
echo "Katman sayısı:"
echo " node:20: $(docker inspect node:20 --format '{{len .RootFS.Layers}}')"
echo " node:20-alpine: $(docker inspect node:20-alpine --format '{{len .RootFS.Layers}}')"docker history — Build Geçmişi
docker history image'ın nasıl build edildiğini, hangi komutların hangi katmanları oluşturduğunu ve her katmanın boyutunu gösterir:
docker history node:20-alpineIMAGE CREATED CREATED BY SIZE
a8c5be9b1d03 3 weeks ago CMD ["node"] 0B
<missing> 3 weeks ago ENTRYPOINT ["docker-entrypoint.sh"] 0B
<missing> 3 weeks ago COPY docker-entrypoint.sh /usr/local/bin/ 388B
<missing> 3 weeks ago RUN /bin/sh -c apk add --no-cache libstdc++ 1.59MB
<missing> 3 weeks ago ENV NODE_VERSION=20.11.0 0B
<missing> 4 weeks ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 4 weeks ago ADD alpine-minirootfs-3.19... / 7.38MBSIZE sütununa bak. ADD alpine-minirootfs 7.38MB (Alpine Linux'un kendisi), RUN apk add 1.59MB. Gerçek yer kaplayan komutlar bunlar.
En Büyük Katmanları Bulmak
Image neden bu kadar büyük? Hemen bulalım:
docker history myapp:v1 --format "{{.Size}}\t{{.CreatedBy}}" | sort -rh | head -5
# 500MB COPY . /app ← node_modules dahil mi?!
# 200MB RUN apt-get... ← Cache temizlenmiş mi?Eğer COPY . /app çok büyükse, muhtemelen .dockerignore dosyası eksik ve node_modules gibi gereksiz dosyalar image'a girmiş.
Tam Komutları Görmek
# --no-trunc ile komutlar kısaltılmaz
docker history --no-trunc node:20-alpinedocker push — Image Paylaşma
Image'ını bir registry'ye göndermek için docker push kullanırsın. Bu, başkalarının senin image'ını pull edebilmesini veya CI/CD pipeline'ının production'a deploy edebilmesini sağlar.
Docker Hub'a Push
# 1. Giriş yap
docker login
# Username: tolgahan
# Password: ********
# Login Succeeded
# 2. Image'ı Docker Hub formatında tag'le
docker tag myapp:latest tolgahan/myapp:v1.0.0
# 3. Push et
docker push tolgahan/myapp:v1.0.0
# The push refers to repository [docker.io/tolgahan/myapp]
# abc123: Pushed
# def456: Pushed
# ghi789: Mounted from library/node ← Zaten Hub'da var!
# v1.0.0: digest: sha256:... size: 1234"Mounted from library/node" mesajına dikkat! Bu katman Docker Hub'da zaten var (çünkü node:20-alpine official image'ının bir parçası). Docker, var olan katmanları tekrar yüklemez — sadece yeni katmanlarını push eder.
Birden Fazla Tag Push
docker push tolgahan/myapp:v1.0.0
docker push tolgahan/myapp:v1.0
docker push tolgahan/myapp:latestİlk push yavaş olabilir ama sonrakiler çok hızlı — çünkü katmanlar zaten yüklenmiş, sadece tag ekleniyor.
Farklı Registry'lere Push
# GitHub Container Registry
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
docker push ghcr.io/tolgahan/myapp:v1
# AWS ECR
aws ecr get-login-password --region eu-west-1 | \
docker login --username AWS --password-stdin 123456789.dkr.ecr.eu-west-1.amazonaws.com
docker push 123456789.dkr.ecr.eu-west-1.amazonaws.com/myapp:v1Image Temizleme — Disk Dolmasını Önle
Docker zamanla disk'i doldurur. Eski image'lar, durmuş container'lar, build cache — hepsi birikir. Düzenli temizlik çok önemli.
Manuel Temizlik Komutları
# Belirli image'ı sil
docker rmi nginx:1.25
# Dangling image'ları sil (tag'siz, havada kalan)
docker image prune -f
# Kullanılmayan TÜM image'ları sil
docker image prune -a
# ⚠️ Dikkat: çalışan container'lar hariç her image silinir
# 24 saatten eski olanları sil
docker image prune -a --filter "until=24h"
# Toplu temizlik — her şey (image + container + network + cache)
docker system prune -a --volumes
# ⚠️ Nuclear option! Kullanılmayan her şeyi silerOtomatik Temizlik Script'i
Production sunucularında haftalık çalışacak bir temizlik script'i hazırlamak iyi bir pratik:
#!/bin/bash
# docker-cleanup.sh — Haftalık çalıştır
echo "=== Docker Temizlik Başlıyor === $(date)"
echo "Önceki disk kullanımı:"
docker system df
docker container prune -f
docker image prune -f
docker network prune -f
docker builder prune --filter "until=168h" -f
echo "Sonraki disk kullanımı:"
docker system df
echo "=== Temizlik Tamamlandı ==="# Cron'a ekle (her Pazar gece 2'de)
crontab -e
# 0 2 * * 0 /path/to/docker-cleanup.sh >> /var/log/docker-cleanup.log 2>&1Image Save ve Load — Offline Transfer
İnterneti olmayan ortamlara (güvenlik nedeniyle izole ağlar, askeri sistemler, uçak, vb.) image taşımak gerekebilir:
# Image'ı sıkıştırılmış dosyaya kaydet
docker save nginx:1.25 | gzip > nginx-1.25.tar.gz
# Birden fazla image tek dosyada
docker save nginx:1.25 postgres:16 redis:7 | gzip > all-images.tar.gz
# Dosyadan image yükle
gunzip -c nginx-1.25.tar.gz | docker load
# Loaded image: nginx:1.25USB'ye kopyala, internet olmayan sunucuya götür, docker load ile yükle. Basit ve etkili.
⚠️ save/load ile export/import'u karıştırma! save image'ı kaydet (katmanlar + metadata dahil). export container'ın dosya sistemini kaydet (metadata kayıp). Image transferi için her zaman save/load kullan.
Yaygın Hatalar ve Çözümleri
"image is referenced in multiple repositories"
docker rmi a8758716bb6a
# Error: unable to delete — image is referenced in multiple repositoriesAynı image'a birden fazla tag verilmiş. Docker, referans kaldırılmadan image'ı silmez. Çözüm:
# Tag'lerle sil
docker rmi nginx:1.25 my-nginx:latest
# veya zorla sil
docker rmi -f a8758716bb6a"denied: requested access to the resource is denied"
docker push myapp:v1
# denied: requested access to the resource is deniedİki olası neden var. Birincisi, Docker Hub'a giriş yapmamışsındır — docker login çalıştır. İkincisi, image tag'i kullanıcı adınla eşleşmiyor. myapp:v1 yerine tolgahan/myapp:v1 olmalı — Docker Hub'a push ederken namespace (kullanıcı adı) gerekli.
"manifest unknown" — Tag Bulunamadı
docker pull myapp:v2.0
# manifest for myapp:v2.0 not foundBu tag registry'de mevcut değil. Ya yanlış yazdın, ya da o versiyon henüz push edilmemiş. Docker Hub web sayfasından mevcut tag'leri kontrol et.
Bu Derste Ne Öğrendik?
docker pullimage indirir. Katmanlar paylaşımlı — zaten var olanlar tekrar indirilmez. Bu ciddi bant genişliği ve disk tasarrufu sağlar.docker tagimage'a yeni referans ekler. Kopya oluşturmaz — aynı image'a birden fazla isim takabilirsin.docker inspectile image'ın tüm metadata'sına erişirsin — CMD, ENV, PORT, katmanlar, mimari. Dokümantasyonu olmayan image'ları anlamak için vazgeçilmez.docker historybuild geçmişini ve katman boyutlarını gösterir. Image neden büyük? Bu komutla hemen anlarsın.docker pushimage'ı registry'ye gönderir. Tag formatı registry'ye göre ayarlanmalı.docker save/loadoffline image transferi sağlar. Internet olmayan ortamlar için kullan.Düzenli temizlik (
docker image prune,docker system prune) yapmazsan disk dolar. Haftalık temizlik alışkanlığı edin.
Bir sonraki derste Docker Hub ve alternatif registry'leri detaylıca inceleyeceğiz — nasıl giriş yapılır, official image nedir, kendi registry'ni nasıl kurarsın.
AI Asistan
Sorularını yanıtlamaya hazır