docker

Docker: Dockerfile Hakkında En İyi Uygulamalar ve Hatalar

Docker, geliştirme ve üretimde tutarlı ortamlar sağlayarak uygulama dağıtımını devrim niteliğinde değiştirmiştir. Docker’ın kalbinde, bir imaj oluşturmak için talimatlar içeren bir betik olan Dockerfile yer alır. Ancak, verimli Dockerfile’lar oluşturmak belirli en iyi uygulamaları anlamak ve yaygın tuzaklardan kaçınmak gerektirir. Bu eğitim, sizi Dockerfile optimizasyon tekniklerinde yönlendirecek ve yaygın hataları gidermenize yardımcı olacaktır.

 

Dockerfile Temellerini ve En İyi Uygulamaları Anlama

DOCKERFILE NEDİR?
Dockerfile, bir Docker görüntüsü oluşturmak için talimatlar içeren bir metin belgesidir. Her talimat, görüntüde bir katman oluşturur ve bu katman, oluşturma süresini, görüntü boyutunu ve güvenliği etkileyebilir. Bu talimatları optimize etmek, verimli konteynerleştirmenin anahtarıdır.

Hafif, güvenli ve hızlı bir şekilde oluşturulabilen konteynerize uygulamalar geliştirmek için verimli Dockerfile’lar oluşturmak esastır. Dockerfile’ınızı yapılandırma şekliniz, geliştirme iş akışınızı ve üretim dağıtımınızı doğrudan etkiler. Daha iyi Dockerfile’lar oluşturmayı ve yaygın hatalardan kaçınmayı keşfedelim.

Adım Adım Talimatlar

  1. Belirli temel görseller kullanın: Minimum, belirli bir temel görselle başlayın
    FROM node:18-alpine

    Yeniden üretilebilir yapıları garantilemek için her zaman en son yerine belirli sürüm etiketlerini kullanın. Alpine tabanlı görüntüler, Debian/Ubuntu muadillerinden önemli ölçüde daha küçüktür. Etiketiniz ne kadar belirli olursa tutarlılık ve güvenlik güncellemeleri için o kadar iyi olur.

  2. Talimatları değişiklik sıklığına göre sıralayın: En az değişen talimatları en üste yerleştirin
    FROM node:18-alpine
    
    # Nadiren değişen araçlar
    RUN apk add --no-cache python3 make g++
    
    # Zaman zaman değişen bağımlılıklar
    COPY package*.json ./
    RUN npm ci
    
    # Sık sık değişen uygulama kodu
    COPY . .

    Docker’ın yapı önbelleği, bir katman değiştiğinde tüm sonraki katmanları geçersiz kılar. En üste daha kararlı talimatlar yerleştirerek önbellek kullanımını en üst düzeye çıkarır ve yeniden oluşturma süresini en aza indirirsiniz. Bu, geliştirme iş akışınızı önemli ölçüde hızlandıracaktır.

  3. İlgili komutları birleştirin: Komutları zincirlemek ve katmanları azaltmak için && kullanın
    # Kötü uygulama (3 katman oluşturur)
    RUN apt-get update
    RUN apt-get install -y curl
    RUN rm -rf /var/lib/apt/lists/*
    
    # İyi uygulama (1 katman oluşturur)
    RUN apt-get update && \
        apt-get install -y curl && \
        rm -rf /var/lib/apt/lists/*

    Her RUN talimatı yeni bir katman oluşturur. İlgili komutları birleştirmek görüntü boyutunu azaltır ve yapı performansını iyileştirir. Görüntüleri küçük tutmak için paket yöneticisi önbelleklerini her zaman temizleyin.

  4. .dockerignore dosyasını kullanın: Gereksiz dosyaları yapı bağlamından hariç tutun
    $ cat .dockerignore
    node_modules
    npm-debug.log
    Dockerfile
    .git
    .gitignore
    README.md

    .dockerignore dosyası .gitignore gibi çalışır ve belirtilen dosyaların derleme sırasında Docker daemon’a gönderilmesini önler. Bu derlemeleri hızlandırır ve hassas dosyaların görüntünüze dahil edilmesini önler.

  5. Çok aşamalı yapıları uygulayın: Yapı ve çalışma zamanı ortamlarını ayırın
    FROM node:18 AS builder
    WORKDIR /app
    COPY package*.json ./
    RUN npm ci
    COPY . .
    RUN npm run build
    
    FROM node:18-alpine
    WORKDIR /app
    COPY --from=builder /app/dist ./dist
    COPY --from=builder /app/node_modules ./node_modules
    COPY package*.json ./
    CMD ["npm", "start"]

    Çok aşamalı yapılar, bir görüntüyü yapı için (tüm yapı araçlarıyla) ve bir diğerini uygulamanızı çalıştırmak için kullanmanıza olanak tanır. Bu, önemli ölçüde daha küçük üretim görüntüleri ve yapı araçlarını son görüntüye dahil etmeyerek iyileştirilmiş güvenlikle sonuçlanır.

    Yukarıdaki örnekte:

    • Oluşturucu adlı ilk aşama, tüm derleme araçlarını içeren tam bir Node.js görüntüsü kullanır
    • Bu ilk aşamada bağımlılıkları kuruyoruz ve uygulamayı oluşturuyoruz
    • İkinci aşama, minimal bir Alp tabanlı görüntüyle taze bir şekilde başlıyor
    • COPY –from=builder kullanarak yalnızca yapı eserlerini ve çalışma zamanı bağımlılıklarını seçici olarak kopyalarız
    • Geliştirme bağımlılıkları, kaynak kodu ve derleme araçları içeren node_modules dahil olmak üzere derleme aşamasındaki diğer her şey atılır

    Çok aşamalı yapılar, son ikili dosyanın minimal bir görüntüye kopyalanabildiği Go, Rust veya Java gibi derlenmiş diller için özellikle değerlidir. Örneğin, bir Go uygulaması şunları kullanabilir:

    FROM golang:1.20 AS builder
    WORKDIR /app
    COPY go.* ./
    RUN go mod download
    COPY . .
    RUN CGO_ENABLED=0 GOOS=linux go build -o /app/server
    
    FROM alpine:3.18
    RUN apk --no-cache add ca-certificates
    COPY --from=builder /app/server /usr/local/bin/
    CMD ["server"]

    Bu yaklaşım, bazı durumlarda görüntü boyutlarını %99’a kadar azaltabilir (1 GB+’dan ~10 MB’a). Test, güvenlik taraması veya farklı eserler oluşturmak için ayrı aşamalara ihtiyaç duyduğunuzda iki aşamadan fazlasını bile kullanabilirsiniz.

  6. Uygun kullanıcı izinlerini ayarlayın: Kapsayıcıları root olarak çalıştırmaktan kaçının
    RUN addgroup -S appgroup && adduser -S appuser -G appgroup
    USER appuser

    Kapsayıcıları root olarak çalıştırmak bir güvenlik riskidir. Ayrıcalıklı olmayan bir kullanıcı oluşturun ve uygulamanızı çalıştırmadan önce ona geçin. Bu, kapsayıcınız tehlikeye girerse olası hasarı sınırlar.

  7. ENTRYPOINT ve CMD’yi doğru kullanın: Aralarındaki farkları anlayın
    # Uygulamalar için
    ENTRYPOINT ["node", "app.js"]
    CMD ["--production"]
    
    # Araçlar için
    ENTRYPOINT ["aws"]
    CMD ["--help"]

    ENTRYPOINT, konteyner başladığında çalışan yürütülebilir dosyayı tanımlarken, CMD bu yürütülebilir dosyaya varsayılan argümanlar sağlar. Bunları birlikte kullanmak konteynerlarınızı daha esnek ve kullanıcı dostu hale getirir.

  8. Yaygın hataları teşhis edin: Yapı hatalarını anlayın
    $ docker build -t myapp .

    Yaygın yapı hataları şunlardır:

    • Base image not found: Temel görüntünün var olduğunu ve uygun erişime sahip olduğunuzu doğrulayın
    • COPY/ADD failures: Kaynak yollarının mevcut olduğundan ve doğru şekilde belirtildiğinden emin olun
    • RUN command failures: Hata ayıklamak için komutları yerel olarak çalıştırın veya ayrıntılı çıktı için docker build –progress=plain komutunu kullanın

DOCKER İNŞA PERFORMANSINI OPTİMİZE ETME

Büyük uygulamalarla çalışırken, bu ek iyileştirmeleri göz önünde bulundurun. Derleme komutlarınızdan önce DOCKER_BUILDKIT=1’i ayarlayarak BuildKit’i kullanın. CI/CD boru hatlarında –cache-from ile derleme önbelleğini kullanın. Node.js uygulamaları için, daha hızlı ve daha güvenilir derlemeler için npm install yerine npm ci kullanın. CI/CD boru hatları için BuildJet gibi Docker katman önbellekleme hizmetlerini göz önünde bulundurun. Bu teknikler, karmaşık uygulamalar için derleme sürelerini %80’e kadar azaltabilir.

Özetlersek

Dockerfile en iyi uygulamalarına hakim olmak, verimli, güvenli ve sürdürülebilir kapsayıcı görüntüleri oluşturmanıza yardımcı olur. Talimatları değişiklik sıklığına göre düzenleyerek, ilgili komutları birleştirerek, çok aşamalı derlemeler uygulayarak ve güvenlik uygulamalarını takip ederek Docker iş akışınızı önemli ölçüde iyileştirebilirsiniz. Dockerfiles’ı optimize etmenin devam eden bir süreç olduğunu unutmayın; görüntü boyutlarını ve derleme sürelerini sürekli olarak izleyin ve uygulamanız geliştikçe yaklaşımınızı iyileştirin. Bu uygulamalarla, yaygın tuzaklardan kaçınacak ve hem geliştirici dostu hem de üretime hazır Docker görüntüleri oluşturacaksınız.

Sıkça Sorulan Sorular (SSS)

  1. Docker imajım neden bu kadar büyük?

    Büyük Docker görüntüleri genellikle şunlardan kaynaklanır: hacimli temel görüntüler kullanmak (Alpine alternatiflerini düşünün), paket yöneticisi önbelleklerini temizlememek, son görüntüye gereksiz derleme araçları eklemek veya çok aşamalı derlemeleri kullanmayı unutmak. Hangi katmanların görüntü boyutuna en çok katkıda bulunduğunu görmek için docker history <image> kullanın ve daha derin analiz için dive gibi araçları düşünün.

  2. Docker yapılarımda hızı nasıl artırabilirim?

    Yapım hızını şu şekilde optimize edin: BuildKit kullanarak, Dockerfile talimatlarını değişiklik sıklığına göre düzenleyerek, katman önbelleğe almayı uygulayarak, yapı bağlamını azaltmak için .dockerignore dosyası kullanarak ve çok aşamalı yapılar kullanarak. CI/CD hatları için, mikro hizmet mimarileri için önbelleğe alma stratejilerini ve paralel yapıları göz önünde bulundurun.

  3. Dockerfiles’da ADD ve COPY arasındaki fark nedir?

    Her iki komut da görüntünüze dosyalar eklerken, ADD’nin ek özellikleri vardır: sıkıştırılmış dosyaları çıkarabilir ve URL’lerden dosya indirebilir. Ancak, COPY daha açık olduğu için basit dosya kopyalama için tercih edilir. ADD’yi yalnızca özellikle ekstra işlevselliğine ihtiyaç duyduğunuzda kullanın.

  4. Birden fazla RUN komutu mu yoksa zincir komutları mı kullanmalıyım?

    Genellikle, katman sayısını ve görüntü boyutunu azaltmak için && kullanarak tek bir RUN talimatı içinde zincirle ilgili komutlar. Ancak, geliştirme sırasında, ayrı RUN talimatları yapı önbelleği kullanımını iyileştirebilir. Üretim Dockerfile’ları için, mantıksal olarak ilişkili komutları (paket kurulumu ve temizleme gibi) birleştirin.

  5. Başarısız olan bir Docker derlemesini nasıl hata ayıklayabilirim?

    Başarısız derlemeleri ayıklamak için: ayrıntılı çıktı için docker build –progress=plain komutunu kullanın, çok aşamalı derlemeler için docker build –target=stage komutunu kullanarak başarısız talimata kadar derleme yapın, komutları etkileşimli olarak test etmek için docker run -it <image_id> sh komutunu kullanarak son başarılı katmandan bir konteyner çalıştırın veya dosya varlığını ve izinlerini kontrol etmek için stratejik olarak RUN ls -la komutlarını ekleyin.

  6. Üretimde en son etiketi kullanmak güvenli midir?

    Üretimde en son etiketleri kullanmak kesinlikle önerilmez. Yapıları yeniden üretilemez hale getirir ve yukarı akış görüntüleri değiştiğinde uygulamanızı bozabilir. Üretim ortamları için her zaman belirli sürüm etiketleri (node:18.12.1-alpine gibi) kullanın. Tam olarak neyin dağıtılacağı üzerinde kontrolü korurken düzenli olarak güncelleme ve daha yeni sürümlerle test etme stratejisi uygulamayı düşünün.

 

Yazının orijinalini  buradan  okuyabilirsiniz.