Docker Üzerine Genel Bakış — Image, Container ve Registry Kullanımı

Serkan Bingöl
AWS Certified User Group Turkey
8 min readDec 21, 2018

Merhabalar daha önceki yazımızda docker network ile ilgili genel bilgileri paylaşmıştım. Bu yazı serisinde aslında docker ile ilgili genel bilgilendirmeler ile birlikte container mimarisi kullanımında ilgi çekici konuları ele alacağım ve bir örnek üzerinden bu konuları ilişkilendirmeye çalışacağım.

Bu yazının temeli aslında Gökhan Şengün ‘ün blogundaki docker serisinin 2. yazısına dayanmakta. Docker ile ilgili tüm sorularınızın detaylarını bu yazı serisinden takip edebilirsiniz. Konuları incelerken ve docker mimarisini kendi kullanım alanlarıma indirgemeye çalışırken aslında image oluşturma ve oluşturulan imaj üzerinde yeni geliştirmeler yapılması işlemlerinde container mimarisinin etkileyici ve performanslı bir biçimde çalıştığını gördüm.

Bu yazı ile birlikte docker imajları ve bu etkileyici yapıyı açıklamaya çalışıp genel bir örnek ile yazımızı sonlandırmış olacağız.

Docker Image Nedir ?

Docker image adından da anlaşılacağı gibi çalışacak uygulamanızın ve uygulamanızın altyapısında çalışan gerekli işletim sistemi kütüphanelerinin bulunduğu bir yapıdır. İmajları, container yaratmak için gereken talimatların bulunduğu bir şablon olarak düşünebiliriz. docker image build komutu ile bir Dockerfile üzerinden oluşturduğumuz yapılardır.

Aşağıdaki resim üzerinden takip edebileceğiniz şekilde aslında Dockerfile image ile ilgili tüm işlemlerin adımlarını barındıran komutlar zincirinden oluşmaktadır. Bu komutlar ile ilgili genel bilgiyi Gökhan Şengün hocamızın yazısından detaylandırabilirsiniz. Genel bilgi olarak FROM komutu ile bir base image dosyasını referans olarak belirliyoruz. ENV komutu ile genel değişkenlerin atamasını yapıyoruz, RUN komutu ile container ile birlikte build zamanında yapılması gereken tüm işlemleri tanımlıyoruz. EXPOSE ile sanal docker networkünde kullanılacak portları tanımlayıp en son olarak CMD komutunda container çalıştırıldığında işleme alınacak komutları tanımlıyoruz.

Oluşturduğumuz Dockerfile dosyasını $ docker image build -t image_ismi komutu ile build ettiğimiz an aslında teker teker adımların gerçekleştiğini çıktılardan takip edebiliriz.

Image build işlemimiz tamamlandıktan sonra , imajlarımızı kontrol ettiğimizde bu işlemler sonunda yeni isimlendirdiğimiz imaj artık localimizde kullanıma hazır şekilde bulunuyor. Aşağıdaki resimden bu işlemi takip etmeniz mümkündür.

Yukarıda bahsettim ve aslında derinlemesine bakıldığında etkileyici olan kısım bu adımdan itibaren ortaya çıkmakta. Oluşturmuş olduğumuz docker image üzerinde bir değişiklik yapmak istediğimizde ilgili Dockerfile dosyasını açarak yapılacak işlemler için komutlarımızı yazıp build işlemimizi yapıyoruz ve çıktıları incelediğimizde artık bazı adımların tekrardan yapılmadığını bunun yerine “using cache” çıktısı ile belirtilerek işlemin başka bir biçimde gerçekleştiğini belirtiyor.

Burada “Layer” kavramını biraz açıklamak gerekiyor. Docker imagelar aslında container’ların file system üzerindeki halidir, başka bir anlatım ile container oluşturmak için sadece okuma yapabildiğiniz dosyalar olarak tanımlanmaktadır. Imajlar “layers” olarak tanımlanan katmanlı bir yapıdan oluşur. Pratikte bir container image tek bir dosyadan oluşmaz. Her katman aslında Dockerfile’ da bir yönerge veya talimattır. Dockerfile üzerinde yürütülen komutlar ile yeni eklenen komutlar build işlemi sırasında çalıştırılırken , daha önceden layer olarak oluşturulan komutlar cache üzerinden oluşturulur ve build işlemi hem daha temiz hem daha kısa süre içinde performanslı bir şekilde gerçekleşir.

Docker imagelar üzerinde yapılan işlemleri görüntülemek ve inceleme yapmak adına docker image history image_ismi ve docker image inspect image_ismi komutları kullanılmaktadır. docker history ile image üzerindeki tüm layerları inceleyebiliriz.

docker inspect komutu ile ilgili image için detaylar görüntülenebilir.

Aşağıdaki resimde birkaç layer üzerinden oluşan bir docker image dosyasından üretilmiş containerları görebiliriz. Containerlar üzerinde oluşan okuma ve yazma katmanı containerlara değindiğimiz bölümde biraz daha açıklayıcı şekilde ele alınacaktır.

Layerların bütünlüklerinin nasıl sağlandığı ile ilgili bir kaç ufak bilgi vermek gerekir ise , katmanların bütünlükleri ayrı ayrı korunur. Yani her katmanın kendine özel bir hash (Content Hash) değeri vardır. En sonunda tüm katmanları hep beraber hashlenir ve buna Distribution hash denir.

Docker Container Nedir ?

Docker Container en basit hali ile imajların çalıştırılmış veya durdurulmuş halidir. Yazılımlarımızı paketleyip runtime bağımlılıklarını yönetebildiğimiz , işletim sisteminin sanallaştırmasını kullanmadan daha az kaynak tüketimi ile process izolasyonu sağlayan bir yapı parçacığıdır.

İndirdiğiniz imajı kullanarak yeni bir container oluşturduğunuzda, yukarıda bahsettiğimiz gibi docker, bu container içinde okunabilir ve yazılabilir bir katman daha ekler. Bu katmana “intermediate image” da denilir. Bu katman aslında sadece okunabilir image layerlarının tamamının üzerinde containerin değişiklik yapmasına olanak tanıyan bir ara image layerı gibi çalışmaktadır. Container silindiğinde bu katmanda container ile yok edilmektedir.

Docker Registry Nedir ?

İmajların tutulduğu ve dağıtıldığı bir ortamdır. Aynı Github’da olduğu gibi elimizdeki imajları docker registry’sine push edebilir veya daha önceden yüklenmiş olan bir docker imajı kendi localimize çekebiliriz. Bu sayede ihtiyaçlarınızı karşılayacak bir imaja çok hızlı bir şekilde erişebilir, gerekirse üzerinde değişiklik yapabilir ve tag’leyerek farklı bir versiyon olarak yeniden gönderebiliriz. Docker registry üzerinden istenirse docker image pull image_ismi komutu ile istenilen imaj localimize çekilebilir yada bir container build etmek için docker container run image_ismi çalıştırılarak ilgili imaj üzerinden bir container türetme işlemi başlatılır. run komutu ile eğer imajlocalimizde bulunmuyor ise docker hub üzerinden gerekli docker image dosyasını indirecek ve bunun üzerinde oluşturulmak istenilen containerı ayaklandıracaktır.

Docker registry üzerinden indirilen bir imaj üzerinde bazı konfigürasyonlar yapıp istenir ise yeni oluşturulan bu docker image genel kullanıma açılmak üzere docker hub üzerinden yayınlanabilir. Burada dikkat edilmesi gereken konu öncelikle docker üzerinde repo sahibinin giriş yapmış olması gerekmektedir.

Sonrasında depolama alanına gönderilecek ve değişiklikleri barındıran imaj adına tagleme yöntemi kullanarak yeni bir repository_ismi oluşturulması gerekmektedir. Burada dikkat edilmesi gereken kısım docker hub üzerinde sadece official imajların önünde bir takı olmadan yayına alınabildiğini bilmek gerekmektedir. docker tag orjinal_Image_ismi degistirilen_Image_ismi komutunu kullanarak yeni bir repository ismi oluşturup docker image push degistirilen_Image_ismi ile docker hub üzerinde bu repositoryi yayınlayabiliyoruz.

Gerekli gönderme işlemini yaptıktan sonra artık https://hub.docker.com/ adresinden repository sekmesinden imajın docker hub üzerine gönderildiğini görüntüleyebiliriz.

Uygulama Test Senaryosu

Şu ana kadar bahsettiğimiz tüm kısımları bir uygulama üzerinde anlatalım. Test senaryomuzu Node.Js ile hazırlanmış bir web uygulamasını , Dockerfile ile konfigüre ederek bir image haline getirip , docker hub üzerinde yayınlamak olarak tanımlayabiliriz.

Öncelikle node.js uygulamamızın bulunduğu klasörde boş bir Dockerfile açarak bunu Visual Studio Code ya da Linux Vim editör gibi yardımcı bir editör ile oluşturmaya çalışalım.

Vim editör düzenlemeye başladığımız Dockerfile dosyasında FROM node:6-alpine komutu ile alpine distrosu üzerinde oluşturulmuş node.js 6 versiyonu base image olarak kullanıyoruz.Neden alpine distrosunu tercih ettiğime yukarıdaki teorik kısımda kısaca değinmiştim. EXPOSE 3000 komutu ile uygulamanın 3000 portunu dinleyeceğini RUN apk add — update tini komutu ile alpine paket yükleyicisine tini paketini kurması gerektiğini, RUN mkdir -p /usr/src/app bir app klasörü oluşturarak bu klasöre WORKDIR /usr/src/app komutu ile ulaşıp COPY package.json package.json komutu ile packeage.json dosyamızı kopyalıyoruz. Sonrasında run npminstall && npm cache clean ile gerekli paket bağımlılıklarını yükleyerek işlem bittikten sonra bu paketleri temizleyip CMD komutunu çalıştırıyoruz. run npminstall && npm cache clean komutu kimi zaman run npminstall ; npm cache clean olarak da kullanılmaktadır. “;” ile “&&” arasında “;” ilk işlemin bitişini gerçekleşip gerçekleşmediğini beklemeden ardından gelen işleme devam ederken “&&” bağlacı ilk işlemin tamamlanmasını beklemektedir.

Dockerfile dosyasını oluşturduktan sonra burada imagelarımızı kontrol edip içinde nodejs-test isimli bir image olmadığını kontrol ediyoruz.

Artık docker image build -t nodejs-test . komutunu kullanarak içinde bulunduğumuz klasördeki Dockerfile dosyasını kullanarak image oluşturma işlemini başlatabiliriz. Adımları takip ettiğimizde step 1/9 ile başlayarak tüm satırların çalıştığını görebiliriz.

Step 7/9 içinde Node.js ile gerekli tüm bağımlılıkları yüklüyoruz.

Bir kez daha imageları listeleyerek yeni oluşturduğumuz nodejs-test image dosyasına artık ulaşabiliriz. docker container run — rm — publish 8080:3000 nodejs-test komutunu kullanarak uygulama containerımızı oluşturduğumuz image aracılığı ile ayaklandırıp http://localhost:8080 üzerinden inceleyebiliriz.

asasasasasas

Artık oluşturduğumuz node.js uygulama containerımızı docker hub üzerinde bulunan depolama alanımıza gönderebiliriz. Burada daha önceden değindiğimiz üzere docker hub üzerinde sadece official imagelar on takısız olmak üzere yayınlanabiliyordu. Dolayısı ile bizde docker image tag nodejs-test srknbngl/nodejs-test komutunu kullanarak aynı image ID sine sahip yeni bir image kopyalıyoruz.

Oluşturduğumuz bu image dosyasını docker push srknbngl/nodejs-test komutunu kullanarak artık docker hub üzerindeki depolama alanımıza yollamış oluyoruz.

Kontrollemiz ile birlikte aynı anda docker hub üzerinde srknbngl/nodejs-test image dosyası olarak görebiliriz.

Oluşan yeni image dosyasını hub üzerinden indirerek bir container oluşturabilir miyiz diye test etmek adına öncelikle localimizde bulunan srknbngl/nodejs-test image dosyasını docker image rm -f 83c33 komutunu kullanarak siliyoruz.

Tekrardan docker container run — rm — publish 8080:3000 nodejs-test komutunu çalıştırarak docker hub üzerinden image dosyasını indirip bu image i kullanarak containerımızı ayağa kaldırmış olmalıyız. Aşağıdaki resimden bu işlemi inceleyebiliriz.

Bir image dosyası nasıl oluşturulur , Dockerfile dosyası nasıl konfigüre edilir ve çalıştırılır , containerlar nasıl image üzerinden ayağa kaldırılır ve docker hub kullanımı ile ilgili genel bir bilgi edinerek bir yazımızın daha sonuna geldik. Bir daha ki yazıda görüşmek dileği ile.

Test Senaryosu aşamaları :https://1drv.ms/b/s!AskWoAU3NqUug_dP5iyEv1lZ335iEQ

Uygulama Dosyaları :https://1drv.ms/u/s!AskWoAU3NqUug_dRnbK_0jtxkmYP1g

Docker Image Linki : srknbngl/nodejs-test

--

--

Serkan Bingöl
AWS Certified User Group Turkey

Muzur bir oğlan babası, hayvan sever, Harry Potter hayranı, bazen maceracı düz yazılımcı.