Merhabalar;

İlk “Docker” yazımda, “Docker” yapısından bahsetmiş, ilk “Hello world” uygulamamızı çalıştırmış, baz
aldığımız “debian” imajına “git” yükleyerek “docker commit” ile yeni bir imaj oluşturmuştuk. Bu
bölüme “Docker” imajlarının “Dockerfile” kullanılarak oluşturulmasıyla başlayacağım. Aslında bu
yöntemi “docker commit” ile yaptığımız işleme ikinci bir alternatif olarak düşünebiliriz.
Bu konuya geçmeden önce Red Hat 7 sistemine ne şekilde “Docker” yükleyeceğimizi anlatmak
istiyorum. Öncelikle işletim sistemi 64-bit olmak zorundadır ve Linux Kernel’in versiyonu 3.10 veya
3.10’dan daha yüksek olmalıdır. Aşağıda kendi sistemimizin kernel seviyesine bakalım.

Sistemin güncel olduğundan emin olmalıyız.

“Docker” için repo ekliyoruz.

“Docker” paketini yüklüyoruz.

“Docker” servisini kullanılabilir hale getiriyoruz.

“Docker” daemon başlatıyoruz.

“Container” de test imajı çalıştırarak “Docker” ın düzgün şekilde kurulup kurulmadığını
sorgulayabiliriz.

Yukardaki komut çıktısı bize kurulumun başarılı olduğunu göstermektedir.
İlk bölümde öğrendiğimiz komutlarımızı bu yapıda çalıştırıp sonuçları görelim. Gördüğünüz gibi
“hello-world” imajımız var. Henüz bir “container” mevcut değil.

Kısa bir tekrar olması açısından Red Hat ortamına “debian:jessie” imajını “download” edelim.

“docker run -it debian:jessie” komutu sonrasında yukarda gördüğünüz gibi, debian shell’e geçiş
yaptık. Bu işlemden sonra “exit” komutuyla debian “container” dan çıkış yapabiliriz. Çıkış yaptıktan
sonra yine en sevdiğimiz komutlar “docker images” ve “docker ps -a” ile yeni imaj ve “container”
bilgilerine bakalım.

“debain” imajını ve “container” olarak yapılandığını komut çıktılarından görebiliriz.
Tekrar debian ortamına geçelim.

Görüldüğü gibi sistem üzerinde “git” komutu mevcut değil.

“git” paketini sistem üzerine yüklüyoruz.

İşlem sonrasında debian Linux üzerine “git” paketinin geldiğini görüyoruz.

Yukardaki komutlar sonrası yeni bir imajın oluştuğunu görüyoruz. Beklentimiz bu imaj ile açtığımız
“container” ın “git” komutunu içermesi. Çünkü baz imaja git eklenmiş imajdan, bu imajı elde ettik.
Durumu aşağıda görelim.

Buraya kadar ilk bölümde windows üzerinde Docker Quick Start Terminal üzerinde yaptığımız şeyleri
Red Hat 7 üzerinde yaparak genel bir tekrar yapmış olduk.
Şimdi “Dockerfile” ile “Docker” imajları nasıl inşa ettiğimize bakalım. “Dockerfile”, bir tekst dosyadır.
İçinde talimatları barındırır. Bu talimatlara göre imaj oluşturulur. Her talimat, imaja yeni imaj
katmanları oluşturacaktır. Talimatlar, imajı inşa ederken neler yapılacağını belirler.
Aşağıdaki şekilde “Dockerfile” ı oluşturalım.

Dosya içinde gördüğümüz “FROM” hangi imajı kullanacağımızı söyler. “RUN”, çalıştıracağımız
komutları ifade eder. “Dockerfile” dan yeni bir imaj oluşturmak için yeni bir komut öğreneceğiz:
“docker build”. Dikkat ederseniz aşağıda olan komutta path olarak “.” uı kullandım. Çünkü
“Dockerfile” ı bulunduğum dizin içinde oluşturmuştum.

Komut çıktısını incelediğinizde “Step 1”, “Step 2” şeklinde giden açıklamalar göreceksiniz. Burda
toplam 4 “step” olacak. Neden? Çünkü bir tansei “FROM” talimatından gelecek, diğer üç tanesi ise
“RUN” talimatından gelecek. İşlem sonrasında yeni imajın oluştuğunu görüyoruz.

Baz imajı, baz imajın üzerine eklemeler yaparak oluşturduğumuz imajları büyüklükleri ile birlikte
yukarda görüyoruz.
Yeni imaj ile “container” oluşturalım. Aşağıda komut çıktılarıyla süreç net olarak anlaşılmaktadır.

Bilmemiz gereken önemli bir nokta, dosya sistemi değişikliklerinin “container” içinde yapıldığıdır.
“Docker daemon” talimatları “container” içinde çalıştırır. “Container”, “writable process” dir ve
dosya sistemi değişikliklerini imaja yazar. Bu örnekte imaja, uygulamanın yüklenmesi işlemini yapar.
Talimatı icra etmek için bir “Container” oluşturulur, imaja değişiklikler yapılır (yeni imaj katmanı
oluşturulur) ve “Container” silinir. Oluşan imajlar “read-only” dir. “Container” sayesinde imajlara
değişiklik yapılarak yeni imajlar (imaj katmanları) oluşturulur.
“Dockerfile” içindeki her “RUN” komutu, “container” ın en tepesinde yazılabilir katman üzerinde
yürütülür. Yeni imaj, “Dockerfile” içinde belirtilen bir sonraki aksiyon için kullanılır. Yani, her “RUN”
talimatı yeni bir imaj katmanı oluşturur. Önerilen yöntem, oluşturulan imaj katmanlarının sayısının
azaltılması olacaktır elbette. Bu durumda yukarda yazdığımız “Dockerfile” ı aşağıdaki formata
dönüştürebiliriz.

Bu durumda imajı tekrar oluşturduğumuzda sadece iki “step” göreceksiniz. Neden? Çünkü bir tanesi
“FROM” talimatından geliyor. Diğeri ise “RUN” talimatından geliyor. Yani bu durumda sadece bir tane
imaj katmanı oluşacak. Ama önceki örnekte üç tane “RUN” talimatı olduğu için 3 imaj katmanı
oluşacaktır.

Bu komut sonrasında imajın “latest” tag ile oluştuğunu görüyoruz. Çünkü yukardaki komutta bir “tag”
kullanmadığım için “latest” “tag” i eklendi.

“Container” başlayacağı zaman hangi komutun çalışacağını “CMD” talimatıyla belirleyebilirsiniz. Eğer
“Dockerfile” içinde “CMD” talimatı belirlemezseniz, baz imajda tanımlanmış olan “default” komut
kullanılacaktır. Örneğin bizim örneğimizde bu “bash” dır. Şimdi biz kendimiz “CMD” talimatıyla yeni
bir tanımlama yapalım.

Oluşturduğumuz bu yeni imajı çalıştıralım. Gördüğünüz gibi dünyaya merhaba dedik.

“Container” ı çalıştırırken “CMD” talimatını ezerek farklı bir şeyde çalıştırabilirsiniz.

“Docker Cache” den bahsedelim. “Docker” ın bir talimat çalıştırdığında yeni bir imaj katmanı
oluşturduğunu biliyoruz. Eğer daha sonraki çalışmada talimat değişmezse, “Docker”, mevcut katmanı
kullanacaktır. Yukarda “docker build” komutu çıktısında “using cache” ifadesini göreceksiniz. Bu
sayede “build” zamanı kısalacaktır. “docker build -t asiyeyigit/debian:4.0 .” komutunun ürettiği
çıktıda “using cache” ifadesini göreceksiniz. Buna rağmen, “docker cache” in kullanımını dikkatli
yapmanızı öneririz. “Aggressive Caching” den kaçınmanız önemli olacaktır. Aşağıda olan örneği
dikkate alalım.

İlk siyah kutucukta belirtilen “Docker file” a sahip olduğumuzu düşünelim. İmajı inşa ettikten sonra,
tüm katmanlar “Docker cache” de olacaktır. İkinci siyah kutucukla “apt-get install” ı ekleyeceğimiz
ikinci “curl” paketiyle değiştireceğimizi varsayalım. Docker, ilk ve ikinci talimatın değişmemiş
olduğunu görecektir. Dolayısıyla ilk siyah kutucuk sonrası oluşan “Cache” i kullanacaktır. Bu durumda
git ve “curl” ün eski sürümlerini kullanma durumunuz ortaya çıkabilir çünkü ilk kutucukta ikinci işlem
sonrası “RUN apt-get update” çalıştırılmamıştı. Bu durumun çözümü olarak aşağıdaki komut
kullanılabilir.

Ek olarak “Docker” a “cache” i kullanma da diyebilirsiniz.

“COPY” talimatından da bahsetmek istiyorum. “COPY” talimatı, “Container” ın dosya sistemine yeni
dosya veya dizinleri eklemek için kullanılır. Aşağıda bulunduğumuz dizinde bir doya oluşturalım.

Daha sonra “Dockerfile” ı değiştirelim. Dosyanın mevcut hali aşağıdaki gibidir.

CMD talimatı yerine “COPY” talimatını ekleyelim ve “docker build” komutunu çalıştıralım.

“Container” ın içerisinde src dizinin içinde oluşturduğumuz abc.txt dosyasını göreceğiz.

“ADD” talimatı ise dosya kopyalama işlemini yapacağı gibi internet üzerinden dosya indirilmesini de
sağlar. Yani internet üzerinden indirdiği dosyayı “container” a kopyalayabilir. “ADD” talimatı
sıkıştırılmış dosyaları otomatik olarak açma işlemini de yapar. Genel kural eğer ADD talimatına
gerçekten ihtiyacınız varsa kullanmanızdır. Aksi halde “COPY” talimatının kullanılması önerilir.
“Docker” la ilgili yazdığım bu ikinci bölümü burda tamamlıyorum. Yazacağım üçüncü bölüm “Docker
Hub” a “Docker” imajların “push” edilmesini, basit bir web uygulamasının “Dockerize” edilmesini,
“Container” içinde “unit test” lerin yazılmasını ve çalıştırılmasını, “Docker” ın “production” ortamına
“deploy” edilmesini içerecek. Üçünü bölümde görüşmek üzere.
Bu yazıyı hazırlamamda büyük katkısı olan sayın James Lee Silikon vadisi yazılım mühendisine
teşekkür ederim.

Asiye Yiğit – 25 Kasım 2016