Docker İmajlarını tar ile Dışa ve İçe Aktarma
Bir container ortamında çalışırken er ya da geç şu soruyla yüzleşiyorsunuz: “Bu imajı internete çıkmadan başka bir sunucuya nasıl taşırım?” Hava boşluğunda çalışan (air-gapped) ortamlar, kısıtlı ağ politikaları, ya da sadece “registry kurmaya vaktim yok” durumları… Bunların hepsinde docker save, docker load ve onların yanında güvenilir dostumuz tar devreye giriyor. Bu yazıda Docker imajlarını .tar arşivleriyle taşımanın tüm inceliklerini, tuzaklarını ve gerçek hayat senaryolarını masaya yatıracağız.
Temel Kavramlar: save, export ve Aralarındaki Kritik Fark
Docker dünyasında iki farklı “dışa aktarma” komutu var ve bunları birbirine karıştırmak ciddi baş ağrısına yol açar.
docker save bir imajı tüm katmanlarıyla (layers), metadata’sıyla ve tag bilgileriyle birlikte arşivler. Yani imajı “tam anlamıyla” dondurur. Bir imajı başka bir sistemde birebir aynı şekilde çalıştırmak istiyorsanız bu sizin komutunuz.
docker export ise çalışan ya da durdurulmuş bir container’ın dosya sistemini düz bir tar arşivi olarak çıkarır. Katman bilgisi yoktur, history yoktur, metadata minimaldır. Genellikle container’ın anlık dosya sistemi durumunu almak için kullanılır.
Kısaca: imaj taşıyorsanız save, container’ın dosya sistemini snapshot’lıyorsanız export.
docker save ile İmaj Arşivleme
En temel kullanım şöyle:
docker save nginx:latest > nginx_latest.tar
ya da daha açık sözdizimi ile:
docker save -o nginx_latest.tar nginx:latest
İkisi işlevsel olarak aynı şeyi yapar ama -o parametresini tercih etmenizi öneririm. Neden? Çünkü > yönlendirmesi bazı ortamlarda (özellikle terminal encoding sorunlarında) dosyayı bozabilir. -o her zaman güvenli.
Birden Fazla İmajı Tek Arşive Kaydetmek
Bu özelliği çok az kişi biliyor ama çok işe yarıyor. Birden fazla imajı tek bir tar dosyasına paketleyebilirsiniz:
docker save -o production_images.tar
nginx:1.24
redis:7-alpine
postgres:15
myapp:v2.1.0
Bu arşivi load ettiğinizde tüm imajlar tek seferde yüklenir. Özellikle compose stack’larını taşırken bu hayat kurtarıcı. Sunucuya tek dosya kopyalarsınız, tek komutla yüklersiniz, işiniz biter.
Sıkıştırma ile Boyutu Küçültmek
Ham tar dosyaları büyük olabilir. Docker imaj katmanları zaten sıkıştırılmış veriler içerdiğinden gzip çok dramatik bir küçülme sağlamayabilir ama yine de fark yaratır. İşte burada tar devreye giriyor:
# Kaydet ve gzip ile sıkıştır
docker save nginx:latest | gzip > nginx_latest.tar.gz
# Daha hızlı ama daha az sıkıştıran bzip2
docker save nginx:latest | bzip2 > nginx_latest.tar.bz2
# Modern ve hızlı: xz (en iyi sıkıştırma oranı ama yavaş)
docker save nginx:latest | xz > nginx_latest.tar.xz
# Çok çekirdekli sistemlerde paralel gzip için pigz
docker save nginx:latest | pigz > nginx_latest.tar.gz
Büyük imajlar (1 GB+) için pigz kullanmayı kesinlikle tavsiye ederim. Standart gzip tek çekirdek kullanır ve çok yavaş olabilir. pigz tüm CPU çekirdeklerini kullanarak aynı işi çok daha hızlı yapar.
Gerçek bir örnekten bahsedeyim: 3.2 GB büyüklüğündeki bir ML model imajını taşıması gerekiyordu. gzip ile 12 dakika, pigz ile 3 dakika 20 saniye. Fark büyük.
İmajın Boyutunu Önceden Kontrol Etmek
Arşivlemeden önce ne kadar yer kaplayacağını bilmek istersiniz:
# İmajın disk kullanımı
docker images --format "table {{.Repository}}t{{.Tag}}t{{.Size}}" nginx
# Tüm imajların toplam disk kullanımı
docker system df
# Daha detaylı
docker system df -v
docker load ile İçe Aktarma
Arşivlenen bir imajı yüklemek oldukça basit:
# Sıkıştırılmamış
docker load -i nginx_latest.tar
# ya da
docker load < nginx_latest.tar
Sıkıştırılmış dosyalar için docker load zaten akıllıca davranır, doğrudan gzip, bzip2 dosyalarını okuyabilir:
docker load -i nginx_latest.tar.gz
Ama pipe kullanırsanız decompress işlemini kendiniz yapmanız gerekir:
# gzip için
gunzip -c nginx_latest.tar.gz | docker load
# xz için
xz -d -c nginx_latest.tar.xz | docker load
# bzip2 için
bunzip2 -c nginx_latest.tar.bz2 | docker load
Load işlemi başarılı olduğunda şuna benzer bir çıktı görürsünüz:
Loaded image: nginx:latest
Birden fazla imaj içeren arşivleri yüklerken her imaj için ayrı satır çıkar:
Loaded image: nginx:1.24
Loaded image: redis:7-alpine
Loaded image: postgres:15
Loaded image: myapp:v2.1.0
Gerçek Hayat Senaryosu 1: Air-Gapped Ortama İmaj Taşıma
Finans, savunma ve sağlık sektöründe çok sık karşılaşılan senaryo: İnternete çıkışı olmayan bir sunucu grubuna Docker imajı kurmak. Registry kurmak için ne zaman ne de yetki var. Klasik çözüm:
# İnternet erişimi olan geliştirme makinasında
docker pull myapp:v3.0.0
docker pull postgres:15-alpine
docker pull redis:7-alpine
# Hepsini tek arşive topla, sıkıştır
docker save myapp:v3.0.0 postgres:15-alpine redis:7-alpine |
pigz > deployment_bundle_$(date +%Y%m%d).tar.gz
# Dosya bütünlüğü için checksum
sha256sum deployment_bundle_$(date +%Y%m%d).tar.gz > deployment_bundle_$(date +%Y%m%d).tar.gz.sha256
# USB ya da güvenli transfer ile hedef sunucuya kopyalayın
# Sonra hedef sunucuda:
sha256sum -c deployment_bundle_20240115.tar.gz.sha256
docker load -i deployment_bundle_20240115.tar.gz
Checksum adımını atlamamak önemli. 2 GB’lık bir dosyayı taşıyorsunuz ve yarım kalmış bir kopyalama işlemi imajı bozar. sha256sum kontrolü bu riskleri ortadan kaldırır.
Gerçek Hayat Senaryosu 2: CI/CD Pipeline’da İmaj Önbellekleme
Bazı ekipler, registry’e push yapmak yerine imajları arşivleyip artifact store’a koyar. Bu yaklaşım özellikle build sürecini hızlandırmak için kullanılır:
#!/bin/bash
# build_and_cache.sh
IMAGE_NAME="myapp"
IMAGE_TAG="${CI_COMMIT_SHA:-latest}"
CACHE_DIR="/opt/docker-cache"
CACHE_FILE="${CACHE_DIR}/${IMAGE_NAME}_${IMAGE_TAG}.tar.gz"
# Önce cache'te var mı kontrol et
if [ -f "$CACHE_FILE" ]; then
echo "Cache hit: $CACHE_FILE"
docker load -i "$CACHE_FILE"
else
echo "Cache miss, building image..."
docker build -t "${IMAGE_NAME}:${IMAGE_TAG}" .
# Cache'e kaydet
mkdir -p "$CACHE_DIR"
docker save "${IMAGE_NAME}:${IMAGE_TAG}" | pigz > "$CACHE_FILE"
echo "Cached to: $CACHE_FILE"
fi
tar Komutu ile İleri Düzey Operasyonlar
docker save çıktısı aslında içinde birden fazla dosya barındıran standart bir tar arşividir. Bunu bilmek bazı güçlü operasyonlar yapmanızı sağlar.
Arşiv İçeriğini İncelemek
# Arşiv içeriğini listelemek (extract etmeden)
tar -tvf nginx_latest.tar
# Sıkıştırılmışsa
tar -tzvf nginx_latest.tar.gz
# Sadece manifest.json'u görmek
tar -xOf nginx_latest.tar manifest.json | python3 -m json.tool
manifest.json dosyası imajın hangi katmanlardan oluştuğunu, tag bilgisini ve config dosyasını gösterir. Bu dosyayı okuyabilmek, imajın bozuk olup olmadığını anlamak için kullanılabilir.
Belirli Bir Katmanı Extract Etmek
Bazen bir imajın içindeki belirli bir dosyaya erişmek istersiniz, container çalıştırmadan:
# Arşivi geçici dizine aç
mkdir -p /tmp/nginx_inspect
tar -xf nginx_latest.tar -C /tmp/nginx_inspect
# manifest.json'dan layer listesini al
cat /tmp/nginx_inspect/manifest.json | python3 -m json.tool
# Belirli bir layer'ı aç
cd /tmp/nginx_inspect
tar -xf <layer_id>/layer.tar -C /tmp/nginx_layer_content
# nginx.conf dosyasını bul
find /tmp/nginx_layer_content -name "nginx.conf"
Bu teknik özellikle güvenlik taraması yaparken veya imaj içindeki bir konfigürasyon dosyasını debug ederken işe yarar.
docker export ve import: Ne Zaman Kullanılır?
Daha önce bahsettiğimiz export/import ikilisine daha detaylı bakalım. Bu yaklaşım bazen imaj boyutunu küçültmek için kullanılır, çünkü katman geçmişini siler:
# Mevcut container'dan "düzleştirilmiş" imaj oluşturma
docker run -d --name temp_container nginx:latest
docker export temp_container | gzip > nginx_flat.tar.gz
docker stop temp_container && docker rm temp_container
# Düz arşivden imaj oluşturma
docker import nginx_flat.tar.gz mynginx:flat
# Ya da tag vererek
gunzip -c nginx_flat.tar.gz | docker import - mynginx:flat-v1
Uyarı: import ile oluşturulan imajlarda CMD, ENTRYPOINT, ENV gibi metadata bilgileri kaybolur. İmajı çalıştırabilmek için bunları elle belirtmeniz gerekebilir:
docker import --change "CMD nginx -g 'daemon off;'"
--change "EXPOSE 80"
nginx_flat.tar.gz mynginx:flat
Bu yüzden production imaj taşıma işlemlerinde export/import yerine her zaman save/load kullanmanızı öneririm.
Uzak Sunucuya Direkt Aktarım
Ara dosya oluşturmadan, pipe aracılığıyla imajı direkt uzak sunucuya göndermek mümkün:
# SSH üzerinden direkt transfer
docker save myapp:latest | gzip | ssh user@remote-server "gunzip | docker load"
# Daha hızlı transfer için lz4 sıkıştırma (kurulu olması gerekir)
docker save myapp:latest | lz4 | ssh user@remote-server "lz4 -d | docker load"
# Bant genişliği kısıtlaması ile (rsync benzeri throttling için)
docker save myapp:latest | gzip |
ssh user@remote-server "cat | docker load"
Bu yöntem çok şık görünse de dikkatli kullanılmalı. SSH bağlantısı kesilirse transfer yarıda kalır ve hedefteki docker load hata verir. Önemli transferler için önce scp ile dosyayı kopyalayıp sonra load etmek daha güvenli.
Otomasyon: İmaj Yedekleme Scripti
Gerçek bir production ortamında kullandığım imaj yedekleme scriptinin sadeleştirilmiş versiyonu:
#!/bin/bash
# docker_image_backup.sh
set -euo pipefail
BACKUP_DIR="/var/backups/docker-images"
RETENTION_DAYS=7
LOG_FILE="/var/log/docker-backup.log"
DATE=$(date +%Y%m%d_%H%M%S)
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# Yedekleme dizinini oluştur
mkdir -p "$BACKUP_DIR"
log "Docker imaj yedekleme başladı"
# Çalışan container'larda kullanılan imajları yedekle
IMAGES=$(docker ps --format '{{.Image}}' | sort -u)
if [ -z "$IMAGES" ]; then
log "Çalışan container bulunamadı, çıkılıyor"
exit 0
fi
for IMAGE in $IMAGES; do
# İmaj adındaki / ve : karakterlerini _ ile değiştir
SAFE_NAME=$(echo "$IMAGE" | tr '/:' '__')
BACKUP_FILE="${BACKUP_DIR}/${SAFE_NAME}_${DATE}.tar.gz"
log "Yedekleniyor: $IMAGE -> $BACKUP_FILE"
if docker save "$IMAGE" | pigz > "$BACKUP_FILE"; then
sha256sum "$BACKUP_FILE" > "${BACKUP_FILE}.sha256"
SIZE=$(du -sh "$BACKUP_FILE" | cut -f1)
log "Başarılı: $IMAGE ($SIZE)"
else
log "HATA: $IMAGE yedeklenemedi"
fi
done
# Eski yedekleri temizle
log "Eski yedekler temizleniyor (${RETENTION_DAYS} günden eski)"
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +"$RETENTION_DAYS" -delete
find "$BACKUP_DIR" -name "*.sha256" -mtime +"$RETENTION_DAYS" -delete
log "Yedekleme tamamlandı"
Bu scripti cron’a ekleyerek düzenli yedekleme yapabilirsiniz:
# Her gece 02:00'de çalıştır
0 2 * * * /opt/scripts/docker_image_backup.sh
Sık Karşılaşılan Sorunlar ve Çözümleri
“No space left on device” hatası: docker save geçici olarak yer kullanır. /tmp veya /var/lib/docker altında yeterli alan olmalı. Büyük imajlarda pipe kullanmak bu sorunu çözer:
# Direkt pipe ile tmp kullanmadan aktar
docker save büyük_imaj:latest | pigz > /mnt/external/imaj.tar.gz
Bozuk arşiv:
# Arşiv bütünlüğünü test et
tar -tzf nginx_latest.tar.gz > /dev/null && echo "Arşiv sağlıklı" || echo "Arşiv bozuk!"
İmaj yüklendi ama tag yok: Bazen docker load sonrası imaj : olarak görünür. Bu genellikle export/import karışıklığından kaynaklanır. Kontrol edin:
# Tagsiz imajları listele
docker images | grep "<none>"
# Tag ver
docker tag <IMAGE_ID> benim_imajim:latest
Farklı mimariler arasında transfer: ARM’den AMD64’e veya tersine imaj taşırken dikkatli olun. docker save/load imajı olduğu gibi taşır, mimari dönüşümü yapmaz. Multi-arch imajlar için buildx kullanmayı değerlendirin.
Boyut Optimizasyonu Karşılaştırması
Farklı sıkıştırma yöntemlerinin davranışlarını bilmek karar vermenizi kolaylaştırır:
- Sıkıştırmasız (tar): En hızlı yazma/okuma, en büyük dosya boyutu, CPU kullanımı minimal
- gzip (tar.gz): İyi denge, her yerde varsayılan olarak kurulu, orta hız
- bzip2 (tar.bz2): gzip’ten daha iyi sıkıştırma, belirgin biçimde daha yavaş, nadiren tercih edilir
- xz (tar.xz): En iyi sıkıştırma oranı, en yavaş, disk alanı kritikse kullanılır
- pigz: gzip uyumlu çıktı, çok çekirdekli paralel işleme, hız/sıkıştırma dengesi için ideal
- lz4: Çok hızlı, sıkıştırma oranı düşük, hız öncelikli transferlerde tercih edilir
Bant genişliği bol ama CPU kısıtlıysa sıkıştırmasız kullanın. Bant genişliği kısıtlı ama CPU bolsa xz veya bzip2 tercih edin. Çoğu durumda pigz en iyi dengeyi sunar.
Sonuç
docker save ve docker load kombinasyonu, Docker ekosisteminin en sağlam ve taşınabilir imaj transfer mekanizmasıdır. Registry bağımlılığı olmadan çalışması, tar ve standart Unix araçlarıyla mükemmel uyum sağlaması bu ikilinin değerini artırıyor.
Özetlemek gerekirse, imaj taşımak için her zaman save/load kullanın, export/import yalnızca container dosya sistemi snapshot’ı almak için tercih edin. Büyük dosyalar için pigz ile zaman kazanın, checksum kontrolünü asla atlamamın. Birden fazla imaj taşıyorsanız tek arşivde birleştirin. Pipe kullanarak disk alanı tasarrufu yapın.
Air-gapped ortamlar, CI/CD optimizasyonu ya da sadece “şu imajı hızlıca şu sunucuya taşı” senaryolarında bu araçlar her seferinde işe yarar. Araç seti basit, ama doğru kullanıldığında son derece güçlü.
