Docker Serisi — Dockerfile Oluşturma

Ahmet Cokgungordu
5 min readJan 6, 2019

Önceki yazımda DockerHub üzerinden bir Docker Image çekmeyi ve çalıştırmayı gördük. Development ortamınızda veritabanı gibi şeylerle çalışıyorsanız ve ortamınızı Docker Container’ı içinde kişiselleştirilmiş olarak çalıştırmak istiyorsanız, kendi Docker Image’ınızı yaratmanız oldukça yararlı olacaktır.

Kendi Docker Image’ınızı oluşturmadan önce yapmanız gereken ilk adım bir Dockerfile yazmaktır. Dockerfile, Docker Image’ı oluşturmak için kullanılan içeriğinde tanımlar bulunan bir dosyadır.

Dosya adı kesinlikle “Dockerfile” şeklinde olmalıdır. “dockerfile”, “DockerFile” gibi verilen isimlendirmeler yanlıştır. Dockerfile dosyasının herhangi bir uzantısı bulunmamaktadır. Bu yazı sonunda Kendi Dockerfile’ınızı oluşturmak için yeterli bilgiye sahip olacaksınız.

Dockerfile, Docker’a temel bir image belirtmek için kullanılan metin belgesidir. Dockerfile içerisinde hangi Image’ın kullanılacağı, hangi dosyaları içereceği ve hangi uygulamanın hangi parametrelerle çalışacağı yazılır.

Yeni bir Docker Image’ı çalışırken, sıfırdan oluşturulan Docker Engine aşağıdaki gibi boş bir Image ile başlar. Docker, Dockerfile dosyasında bulunan komutları sırayla tek tek çalıştırır. Her komut yeni bir katman oluşturur ve Docker build sonunda katmanlardan oluşan yeni bir Docker Image oluşur.

Yeni bir Docker Image oluşturmak için, mevcutta bulunan Docker Image’i başlangıç noktası olarak kullanabiliriz. Buna Base Image denilmektedir. Bu Base Image’den Docker motoru sayesinde Dockerfile’daki komutlar okunarak yeni katmanlar oluşturulur.

Yukarıda da göründüğü gibi son Docker Image’ının, Base Image üzerine eklenmiş Application Framework ve Web Application katmanından oluştuğunu düşünebiliriz.

Bir Dockerfile formatı aşağıdaki gibi çok basit bir yapıdadır. # ile başlayan satırlar yorum satırı olarak kabul edilir.

# Comment
INSTRUCTION argümanlar

Aşağıda bir Dockerfile örneği bulunmaktadır. Şimdi bu Dockerfile dosyasındaki satırları tek tek inceleyelim.

FROM node:9.3.0-alpineRUN npm install -g @angular/cli@1.5.5 \
&& mkdir -p /usr/src/test-project
WORKDIR /usr/src/test-projectADD . /usr/src/test-projectRUN npm install && ng buildEXPOSE 80CMD node server.js $HOSTNAME

Dockerfile oluşturmaya başlamadan önce ilk yapılacak şey Base Image göstermektir. Base Image’ınız mevcut bir Docker Image’ı veya bir İşletim Sistemi Image’ı olabilir. Örneğin bir İşletim Sistemi Image’ı aşağıdaki gibi tanımlanır.

FROM

FROM node:latest

Base Image belirtmek için kullanılan bir Dockerfile komutudur. DockerHub’da resmi olarak yayınlanan node.js Image’ını kullanarak başlıyoruz.

FROM node:9.3.0-alpine

Dockerfile oluştururken versiyon kullanmanız yararlı olacaktır. Çünkü “latest” versiyonun ne zaman değişeceğini bilemezsiniz. Bu sürüm adından anlaşılacağı üzere Linux Alp İşletim Sistemi üstünde çalışan node.js 9.3.0'ı kullanacağımızı belirtmektedir.

RUN

RUN npm install -g @angular/cli@1.5.5 \
&& mkdir -p /usr/src/test-project

Docker Image’ı yaratılırken normal Linux komutlarının çalışması gerektiğini bildirir. Yukarıdaki komut Angular CLI yükler ve “test-project” adında dizin oluşturur.

RUN npm install && ng build

Bu komut ise “npm install” ile bütün proje bağımlılıklarını yükleyecek ve “ng build” ile Angular Projesini build edecektir. Komut “/home/node/pintail-whoami” pathi altında çalışacaktır.

WORKDIR

WORKDIR /home/node/test-project

Container üzerinde çalıştırılacak olan komutların nerede çalışacağını belirtir. RUN, CMD, ENTRYPOINT, COPY ve ADD komutları çalışacağı zaman bu path üzerinde çalışacaktır.

ADD

ADD . /usr/src/test-project

Mevcut dosya sisteminizdeki hangi dosyaları Docker Image’ında nereye eklemek istediğinizi belirtebilirsiniz. Format olarak <src> … <dest> şeklinde kullanılır. Yukarıdaki örnekte “.” parametresi ile mevcut dosya sisteminizdeki bulunduğunuz path içerisindeki bütün dosyaları eklemesini söylemiş olduk. Docker Image’inde host sisteminde yer alan tüm dosyalar “/usr/src/test-project” altına koyulacaktır.

ADD komutu internetten Image’a dosya kopyalanmasını da sağlamaktadır. Bu komutun kopyalamasını istemediğimiz dosyalarını belirtmek için .gitignore benzeri bir .dockerignore dosyası oluşturabiliriz.

ADD [ "http://central.maven.org/maven2/org/springframework/security/spring-security-rsa/1.0.8.RELEASE/spring-security-rsa-1.0.8.RELEASE.jar", "/tmp/spring-security-rsa-1.0.8.RELEASE.jar" ]

Yukarıda internetten dosya yüklemeye bir örnek verilmiştir. Maven deposundan çekilen jar tmp dosyasına indirilecektir.

EXPOSE

EXPOSE 80

Expose komutu ile bağlantı noktasını İşletim Sistemine gösterir. Docker Container’ındaki hangi bağlantı noktasının İşletim Sistemine bağlanacağını görmeyi kolaylaştırır.

CMD

CMD node server.js $HOSTNAME

Şimdi ise işin güzel kısmına geliyoruz!! CMD komutu, Docker Container’ı başladığında çalıştırılacak olan Linux komutunu uyarır. Bu komut Docker Container’ında 0 process olur ve Docker Container çalıştığı sürece çalışmaya devam edecektir. İşlem bittiğinde, Container duracaktır. Kısaca özetlemek gerekirse Image hazırlandıktan sonra, Container’ın belirlediği bir komutu çalıştırarak Container’a devretmektedir.

CMD komutu aşağıdaki şekillerde kullanılabilir;

CMD [ "/bin/ping", "8.8.8.8" ]

Bu komut ile Google DNS sunucusuna ping atan Image oluşturmuş olduk.

CMD bash /scripts/runnerEntry.sh

Bu komut ile bir sh dosyasını tetiklemiş olduk.

CMD komutu, yukarıda verilen her iki formatta da kullanılmaktadır.

Diğer Komutlar

Örnekteki komutların yanında diğer komutlar da bulunmaktadır. Bunlara da kısaca değinelim.

COPY

ADD komutu ile aynı olmasına rağmen arasında çok ufak bir fark vardır. Add komutu ile internet üzerinden yükleme yapılmasına olanak sağlanırken, copy ile sadece İşletim Sistemi Host’undaki dosya veya klasörleri Container içine kopyalabilirsiniz.

ENTRYPOINT

Container çalıştığında ilk önce yürütülecek komutu ve parametreleri ayarlar.

“docker run <image>” çalıştırılırken verilen her komut bu komut ile birlikte işletilir ve CMD kullanılarak belirtilen tüm öğeleri geçersiz kılar. Örneğin, “docker run <image> bash” komutunda “bash” argümanı “entrypoint” sonuna eklenir.

ENTRYPOINT ve CMD Kullanımı

Bu iki komutu kullanmanın farklı yolları vardır. Docker kullanımı hakkında bazı best practices’ler bulunmaktadır.

Best Practices

Docker, Image için ana komut ayarlamak için ENTRYPOINT kullanılmasını öneriyor. Varsayılan için ise CMD kullanılmasını öneriyor. Her ikisininde birlikte kullanılmasına örnek aşağıdaki gibidir.

FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]

Özetle hem CMD hem de ENTRYPOINT, bir Container çalıştırılırken hangi komutun uygulanacağını tanımlar. Nasıl etkileşimde bulunduklarını açıklayan birkaç kural vardır.

  • Dockerfile içinde CMD veya ENTRYPOINT komutlarından en az birini belirtmek gereklidir.
  • ENTRYPOINT, Container çalıştırılabilir olarak kullanılırken tanımlanmalıdır.
  • CMD komutu, ENTRYPOINT komutu için default parametreleri tanımlama yöntemi olarak veya bir Container’da özel bir komut çalıştırmak için kullanılmalıdır.
  • Alternatif argümanlarla çalıştırılırken CMD geçersiz kılınır.

HEALTHCHECK

Bu komut ile oluşturulan Docker Image’ının durumu kontrol edilebilir. Bu komut ile Docker’a bu işlemin nasıl yapılacağı anlatılır. Bu, sonsuz döngüde sıkışmış olan ve sunucu işlemi devam etse bile yeni bağlantıları kaldıramayan bir web sunucusu durumları algılar.

Komutun sonucu, Container’ın sağlık durumunu belirtir. Değerler;

  • 0: success — Container sağlıklı ve kullanıma hazır
  • 1: unhealthy — Container düzgün çalışmıyor.
  • 2: reserved — Bu çıkış kodunu kullanmamak gereklidir.

Örneğin, bir uygulamayı her 5 dakikada kontrol etmek ve 3 saniye içinde cevap vermesini sağlamak için aşağıdaki gibi bir check kullanabiliriz.

HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1

Böylece uygulama 3 saniye içinde cevap vermezse healthcheck işleminden geçemeyeceği anlamına gelmektedir.

--

--