Dockerfile Verimliliği Nasıl Artırılır?
0

Sağladığı esneklik ve ölçeklenebilirlik ile konteynerleştirme teknolojilerinin önemi gün geçtikçe artmaktadır. Konteynerleri çalıştırmak için ihtiyacımız olan Image’ları genellikle popüler Image Repository’si Docker Hub’dan sağlamaktayız. Peki, kendi docker Image’ımızı oluşturmak için ne yapmalıyız? Docker, bir Image’ı oluşturmak için gerekli tüm komutları içeren Dockerfile adı verilen text dosyasını okumaktadır. Dockerfile’da yer alan bu talimatlar ile Image’lar otomatik olarak oluşturulmaktadır. Docker Image’ları, her biri bir Dockerfile talimatını temsil eden Read-Only Layer’lardan oluşur. Layer’ların her biri bir önceki Layer’daki değişikliğin deltasıdır. Aşağıdaki Dockerfile’ı örnek alacak olursak:

dockerfile_1

Resim-1

Her talimat bir Layer oluşturmaktadır.

FROM talimatı ile ubuntu:18.04 Image’ı temel alınmaktadır.

COPY talimatı, Docker istemcinizin geçerli dizininden dosyaları kopyalamaktadır.

RUN talimatı, uygulamamızı ‘make’ ile yapılandırmaktadır.

CMD talimatı, konteyner içerisinde ‘python /app/app.py’ komutunu çalıştırmaktadır.

dockerfile_layers

Resim-2

Image’ımız çalıştırılıp bir konteyner oluşturulduğunda artık elimizde Read Only olmayan bir konteyner Layer’ı olacaktır. Yeni dosyalar ekleyip çıkarma, mevcut dosyaları düzenleme, komut çalıştırma vb. işlemlerimiz bu çalışan konteyner Layer’ında yapılabilmektedir.

Github üzerinden yaklaşık bir milyon Dockerfile’a ulaşabilmekteyken bu Dockerfile’ları kullanırken yorumlayabilmek, uygulamamızın güvenliği ve CI/CD süreçlerinin verimliliği açısından önemlidir. Mevcut Dockerfile’ları nasıl iyileştirebiliriz, Dockerfile yazarken Image boyutunu ve Build süresini azaltarak, güvenliği ve sürdürülebilirliği ise artırarak verimliliği artırmak için nelere dikkat etmeliyiz, hep beraber maddeler halinde öğrenelim.

Dockerfile’da Verimliliği Artırmak İçin Nelere Dikkat Edilmelidir?

  • Build süresini azaltmak için Cache kullanılmalıdır.

Geliştirme döngüsünde Dockerfile bir kez yapılandırıldıktan sonra kod değişiklikleri yapılıp yeniden yapılandırılırken Cache kullanmak Build süresi açısından önem taşımaktadır. Caching, gerekli olmayan derleme adımlarının tekrar tekrar çalıştırılmamasını sağlar.

  • Caching için talimatların sıralamasına dikkat edilmelidir.

Dockerfile’da kullanılan talimatların sıralaması Caching açısından önemlidir. Dosyalar değiştiğinde veya Dockerfile dosyanızda talimatların sıralaması değiştiğinde Cache, değişiklik olan adımdan sonrası için kırılacaktır. Bu yüzden sıralama, dosya içeriği ve kendisi en az değişenden en sık değişen adıma doğru olmalıdır. Aşağıdaki Dockerfile örneğinde de gördüğümüz gibi COPY talimatı aracılığıyla Image içerisine kopyalanan dosyaların içeriğinin değişme durumu diğer talimatların değişme durumundan daha sık olacağı için bu talimatın diğerlerinin altına alınması Caching’i optimize ederek Build süremizi azaltacaktır.

dockerfile_2

Resim-3

  • Sadece gerekli dosyalar kopyalanmalıdır.

Mümkün olduğunca ‘COPY .’ talimatından kaçınmalıyız. Gereksiz olarak kopyaladığımız dosyalardan herhangi birinde yaptığımız değişiklik yine Caching’i kıracaktır ve sonraki adımlar için de Caching’den yararlanmamıza engel olacaktır. Build süremizi azaltmak için Image’ımızın içerisine dosya kopyalarken mümkün olduğunca cimri olmalıyız. Aşağıdaki Dockerfile örneğinde gördüğümüz gibi tüm dizini kopyalamaktansa bir sonraki adım için gerekli olan .jar dosyasını kopyalamamız yeterli olacaktır.

dockerfile_3

Resim-4

  • Layer sayısı minimize edilmelidir.

Docker’ın eski versiyonlarında Layer sayısını minimize etmek performans açısından çok daha fazla önem taşımaktaydı. Ancak artık sadece FROM, RUN, COPY ve ADD talimatları Layer oluşturmaktayken diğer talimatlar geçici ara Image’lar oluşturmaktadır ve Build boyutunu artırmamaktadır. Layer oluşturan bu talimatların kullanımını mümkün olduğunca aza indirmek Build süremizi azaltacaktır.

  • apt-get update & install komutları tek bir RUN talimatında kullanılmalıdır.

Her bir RUN talimatı ayrı Cache birimi olarak değerlendirilir. Paket yöneticilerini kullanarak paketlerimizi yükleyeceğimiz zaman Update ve Install işlemlerimizi tek RUN talimatında yapmak iki işlemi de tek bir Cache’lenebilir Layer üzerinde gerçekleştireceğinden, eski paketlerin yüklenmesi riskini ortadan kaldıracaktır.

dockerfile_4

Resim-5

  • Gereksiz bağımlılıklar kaldırılmalıdır.

Debug için gerektiğinde zaten çalışan konteyner üzerinde kurulabilmekte olan vim, curl vb. araçları mümkün olduğunca kurmamalıyız. Apt gibi paket yöneticileri önerilen paketleri otomatik olarak yüklemektedir. İhtiyaç olunmayan paketlerin yüklenmemesi için –no-install-recommends Flag’ini kullanmalıyız.

dockerfile_5

Resim-6

  • Paket yöneticisi Cache’i kaldırılmalıdır.

Paket yöneticileri kendi Cache’lerini Image içerisinde tutmaktadırlar. Image boyutunu azaltmak için paketleri yükleyen RUN talimatına bu Cache’i temizletebiliriz.

dockerfile_6

Resim-7

  • .Dockerignore dosyası kullanılmalıdır.

Docker CLI, içeriği Docker Daemon’a göndermeden önce yapılandırmayla ilgili olmayan dosyalarımızı dahil etmemek için ana dizinde .dockerignore dosyası aramaktadır. .dockerignore dosyası ADD ve COPY talimatlarını kullanırken, gereksiz dosyaları da Image’ımıza ekleyip Image boyutunun büyümesini önlemektedir.

  • Mümkün olduğunca Official Image’lar kullanılmalıdır.

Best Practice’ler uygulanarak kurulum adımlarının birçoğu tamamlandığından Official Image kullanmak sürdürülebilirlik açısından zaman tasarrufu sağlamaktadır.

dockerfile_7

Resim-8

  • Latest Tag’i yerine spesifik Tag’ler kullanılmalıdır.

Docker Hub’daki Image’larda zaman içerisinde değişiklikler olmaktadır ve Latest Tag’i otomatik olarak değişiklik yapılan son Image’ı kapsamaktadır. Bu değişikliğin uygulamamızı nasıl etkileyeceğini öngöremediğimizden Latest Tag’i yerine spesifik Tag’ler kullanmalıyız.

dockerfile_8

Resim-9

  • Tutarlı bir ortamda kaynak koddan Build işlemi yapılmalıdır.

Makalemizde buraya kadar verdiğimiz Dockerfile örnekleri, Jar Artfact’ini kendi host’unuzda yapılandırdığınızı varsayarak hazırlanmıştı. Bu şekilde konteyner tarafından sağlanan tutarlı ortamın avantajlarından yararlanamamaktayız. Örneğin, eğer Java uygulamanız belirli kütüphanelere bağlıysa uygulamanızın hangi bilgisayarda kurulduğuna bağlı olarak istenmeyen tutarsızlıklar ortaya çıkabilir.

Öncelikle uygulamamızı yapılandırmak için gereklilikleri belirlemeliyiz. Örneğimizdeki Java uygulamasında Maven ve JDK kullanılmaktadır. Bu durumda openjdk yerine Docker Hub’da yer alan ve JDK içeren bir Maven Image’ı kullanabiliriz. Daha fazla bağımlılık yüklememiz gerekiyorsa bunları RUN talimatıyla gerçekleştirebiliriz.

  • Build bağımlılıklarını ortadan kaldırmak için Multi-Stage Build kullanılmalıdır.

Multi-Stage Build’lerde Dockerfile dosyasında birden fazla FROM talimatı kullanmaktayız. Her FROM talimatı farklı bir Base Image kullanırken yeni bir Build Stage’i başlamış olur. İstediğimiz artifactleri bir Stage’den diğerine kopyalayabiliyorken, istemediklerimizi geride bırakıp son Image’a dahil etmeyebiliyoruz.

Multi-Stage build’ler Layer ve dosya sayımızı düşürmeden son Image boyutumuzu önemli ölçüde azaltmaktadır.

dockerfile_9

Resim-10

Daha hızlı deployment ve verimli bir CI/CD süreci için nasıl daha iyi Dockerfile yazabileceğimizi ve elimizdeki Dockerfile’ları nasıl iyileştirebileceğimizi hep beraber incelemiş olduk.

Bu konuyla ilgili sorularınızı  alt kısımda bulunan yorumlar alanını kullanarak sorabilirsiniz.

Referanslar

www.mshowto.org

DockerCon Talk Recording: Dockerfile Best Practices

DockerCon Talk Slides: Dockerfile Best Practices

Docker Docs: Dockerfile References

Intro Guide to Dockerfile Best Practices

TAGs: Dockerfile nedir, Dockerfile, Docker Image, Dockerfile Best Practices, Nasıl daha verimli Dockerfile yazılır, Dockerfile yazılırken dikkat edilmesi gerekenler, dockerignore, multi-stage build, Dockerfile Caching, Build Cache, Containers

Bu İçeriğe Tepkin Ne Oldu?
  • 25
    harika_
    Harika!!
  • 0
    be_enmedim
    Beğenmedim
  • 2
    _ok_iyi
    Çok iyi
  • 0
    sevdim_
    Sevdim!
  • 0
    bilemedim_
    Bilemedim!
  • 0
    olmad_
    Olmadı!
  • 0
    k_zd_m_
    Kızdım!

İTÜ Matematik Mühendisliği ana dalından mezun olmadan önce Bilgi İşlem Daire Başkanlığı’nda 1 sene asistan öğrencilik yaparak bilgi teknolojileri sektörüne altyapımı daha iyi hazırlama fırsatım oldu. Mezun olduktan sonra Mercedes Benz Finansal Hizmetler şirketinde Database Administrator olarak çalışmaya başladım. Paralelde İTÜ’de ikinci ana dalım olan İşletme Mühendisliği’ne devam etmekteyim. Aynı zamanda DevOps trendlerini de takip ederek kendimi DevOps Engineer olarak geliştirmekteyim.

Yazarın Profili
İlginizi Çekebilir

Bültenimize Katılın

Tıklayın, üyemiz olun ve yeni güncellemelerden haberdar olan ilk kişi siz olun.

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir