Dockerfile

Dockerfile Nedir

Deniz TÜRKMEN
7 min readSep 7, 2022

Merhabalar

Bu yazımda Dockerfile ne olduğu,Dockerfile yazarken kullanıdğımız komutlar ve Dockerfile katmanlarını inceliycez.

Dockerfile

Dockerfile,belli bir image görüntüsü oluşturmak için var olan tüm katmanların açıklandığı uzantısı olmayan dosyadır. Dockerfile içerisinde hangi Image’ın kullanılacağı, hangi dosyaları içereceği ve hangi uygulamanın hangi parametrelerle çalışacağı yazılır. Docker, Dockerfile dosyasında bulunan komutları sırayla tek tek çalıştırır. Her komut yeni bir katman oluşturur. Docker build sonunda elimizde uygulaması ait Docker Image oluşur .Docker Image container oluşturarak uygulaması ayağa kaldırabiliriz. Bilinmesi gereken en önemli nokta ise dosya adının kesinlikle Dockerfile şeklinde olmasıdır. “dockerfile”, “DockerFile” gibi verilen isimlendirmeler yanlıştır.

Not: Dockerfile dosyasının herhangi bir uzantısı yoktur.

Dockerfile formatı aşağıdaki gibi çok basit bir yapıdadır.

INSTRUCTION argümanlar

Not : Dockerfile base image ile başlar. Base Image işletim sistemi, docker image veya uygulamaya ait base image olabilir.

Kabaca Dockerfile açıklarsak; içerisinde yayınlanacak olan uygulamanın nasıl bir ortamda çalışacağına dair talimatları barındırmaktadır. Örneğin; geliştirme yapılan herhangi bir Asp.NET Core uygulamasının, hangi işletim sistemi üzerinde kaçıncı versiyonla ayağa kaldırılacağını ve hangi py, jar ,.dll dosyalarının yüklü olması gerektiği gibi talimatlar belirtilebilmektedir.

Dockerfile Avantajları

  • Sunucu yapılandırmaya gerek yoktur.
  • Uygulama bağımlılıklardan izole ediliriz.

Dockerfile Komutları

  • FROM : Base image göstermek. Küçük boyutlu image dosyasını almak her zaman iyidir tabiki uygulama için yeterli ise. Image son sürümü kullanmaktansa (mcr.microsoft.com/dotnet/aspnet:latest) uygulamanın geliştirildiği sürümü kullanmak her zaman iyidir. (mcr.microsoft.com/dotnet/aspnet:3.1)
FROM image : tagFROM ubuntu :18.04 
veya
FROM ubuntu:latest
  • RUN : Uygulama içerisinde çalıştırmak istediğimiz komutlar diğer bir tabiriyle uygulamaya ait bağımlılıkların tanımlandığı yerdir. Diğer bir tabir ile Docker Image alınırken çalıştırılmasını istediğimiz komutlar yazılır. Run ile yazılan her komut bir katmandır. Birden fazla run komutu yazılabilir. Run komutları eğer alt alta yazarsak her run komutu bir katman olacağından image boyutu artacaktır. Bunun yerine and (&&) kullanılarak uygulamanın ihtiyacı olan bağımlılıklar tek satırda and(&&) kullanılarak yazılır.
RUN komutRUN apt-get update && apt-get upgrade && apt-get install -y vim

Not : Docker image alınırken çalışacak komutlar tanımlanır. Daha da doğrusu oluşan image içersinde barındırmak istediğimiz toolları yükleriz.

  • CMD : Docker container ayağa kalktığında çalıştırılacak komutlar yazılır. Container ayağa kalktığında ilk bu komut içerisindeki değer çalışır. Yazılım dünyasında main fonksiyonu gibidir. Dockerfile içerisinde tek bir CMD komutu olmalıdır. Birden fazla CMD komutu yazıldığında en son satırdaki cmd komutunu devalır ve o komut satırı çalışır.
CMD <komut> <değer>

Örnekler ile bakalım.

FROM ubuntuCMD ["/bin/echo"]

dosyasından image oluşturup container oluşturursak ve aşağıdaki komut ile bir container oluşturalım.

docker container run image_ismi 1 2 3

dersek hata alırız. Çünkü cmd komutu tek değeri çalıştırabilir.

FROM ubuntuCMD ["/bin/echo","0"]---docker container run image_ismi

çıktı 0 olur.

FROM ubuntuCMD ["/bin/echo","0"]---docker container run image 1

çıktı yine hata alırız.

  • LABEL : Image sahibi veya farklı metadata detayları eklemek için kullanılır.
LABEL <key> <value>
  • MAINTAINER : Dockerfile dosyasını oluşturan kişi hakkında bilgileri içerir. Adı,e-posta vs gibi.
  • EXPOSE : Port yapılandırmasının yapıldığı yerdir. Default olarak TCP portunu kullanır. Container dış dünya ile iletişimi verdiğimiz port üzerinden yapar. Container’ın docker içinde çalışacağı port adresi belirlenir.
EXPOSE port_number veya EXPOSE port_number/protocol (TCP | UDP)
  • ENV : Containera ortam değişkeni tanımlamak için kullanılır.
ENV <key> <value>
  • ADD : Container içerisine internetten veya local den data kopyalamak için kullanılır.
ADD <host_kaynak_dosya> <container_dosya_yolu>
  • COPY : Belirtilen dosyaları container içerisinde belirlenen hedefe kopyalar.
COPY <src-path> <destination-path>
  • ENTRYPOINT : Container çalıştığında varsayılan parametre tanımlamak için kullanılır. Daha esnek bir kullanıma sahiptir. Kısaca parametre sabitlemek için kullanılır.
ENTRYPOINT <path>
  • VOLUME : Container içerisinde kalıcı depolama alanı belirtmek için kullanılır.
VOLUME <mountpoint>
  • USER : Hangi kullanıcı üzerinden işlem yapılacağını belirlemek için kullanılır.
USER <user>
  • WORKDIR : Containerın çalışma dizini belirtmek için kullanılır.
WORKDIR <path>

ARG : Container çalışacak Argüden’leri tanımlarız. ARG en güzel örnek uygulamamıza ait birden fazla ortamımız olabilir. Ortamdan kastım test ve master şuan kabul edelim. Test sunucusunda tuttuğumuz database özellikleri ile master da tuttuğumuz database özellikleri aynı değildir. İşte biz burada hangi ortama göre image alınacaksa burada onu tanımlarız.

FROM alpine
ARG ENVIROMENT
.
.
.
docker image build --tag image_ismi --build-arg=Hangi_enviroment_ise_o_yazılırdocker image build --tag tag_name --build-arg=test .

Not : dockerignore dosyası ile container içerisine aktarmak istemediğimiz yazarız.

Dockerignore

Dockerfile Örneği

Basit bir örnek yapalım. Bu örneğimizde kendi web sitemin frontend tarafında dockerfile -> dockerimage -> docker container oluşturup çalıştırcaz. Uygulamız altta gözüktüğü gibidir.

Not : dockerfile başka klasörde ise - -file /path_yolu parametre ile dockerfile dosyasının yolu gösterilir. Eğer dockerfile dosyası bulunduğumuz dizinde ise “.” nokta ile gösterilir.

  • ilk olarak dockerfile dosyamızı yazalım.
FROM ubuntu:latestLABEL Deniz TÜRKMEN <turkmen_deniz@hotmail.com>RUN apt update && apt install -y nginxWORKDIR /var/www/htmlCOPY . /var/www/htmlEXPOSE 80/tcpCMD ["nginx","-g daemon off;"]
  • Şimdide Dockerfile dosyamızdan image oluşturalım. Bunun için
docker image build --tag denizfrontend .

Burada “.”(NOKTA) Dockerfile dosyasının aynı kök dizininde olduğu söylüyoruz. Eğer başka bir dizin altındaysa onu da ;

--file <path> ile belirtiyoruz.

Docker image’ mız oluştu. Şimdi docker image görmek için;

docker imagesve yadocker image ls

komutunu çalıştırıp bakalım. Aşağıdaki şekilde gözüktüğü üzere imagemız başarılı şekilde oluştu.

Şimdide bu image container oluşturup test edelim. Bunun için ;

docker container run --detach --publish 5000:80 image_ismi

Şimdide container listeleyelim. Bunun için ;

docker container ls

komutunu kullanıyoruz.

Containerımız status up durumunda. Tarayıcıdan localhost:5000 gittiğimizde uygulamızı docker ile çalıştırmış olduk.

Visual Studio Code Docker Extentions

Şimdi de Visual Stdio Code “Docker” extentison kullanarak kendisinin bir dockerfile dosyası oluşturup bu dockerfile dosyasından da docker image oluşturup, container ile ayağa kaldırcaz ve bütün bu işlemleri bizim için VSCode Docker extentisons yapacak.

Bu işlemi yapmak için VSCode docker extentisons kurmanız gerekir.

Dockerfile dosyamıza sağ click Build Image diyelim.

Dockerfile dosyamızdan oluşturcağımız docker image ismini yazalım.

docker images

komutu ile oluşan image mızı kontrol edebiliriz.

MultiStage Dockerfile

Oluşturduğumuz image ların boyutunu küçültmeliyiz.

  • Büyük boyutlu image’ları indirmek, oluşturmak ve docker registry göndermek zaman alıcıdır.
  • İmage içerisinde gereksiz bağımlılık oluşturmak image boyutunu büyütecektir.
  • Performs sorunları ortaya çıkar.
  • Best Practices olarak önerilmemektedir.

İmage boyutunu küçültmek için ;

  • dockerigonere dosyası oluşturabiliriz.
  • İmage katmanlarını minimum düzeyde tutulmalıdır. Örneğin;
RUN apt-get updateRUN apt-get upgrade

Yerine ;

RUN apt-get update && apt-get upgrade

şeklinde kullanılmaldır.

  • Tüm imagelar için küçük boyutlu olan alpine image kullanılmalıdır. Tabiki de uygulamanız bu base image ile çalışacak düzeyde ise.
  • En önemliside (Multi-Stage) dosyaları kullanılmalıdır.

Örneğimizi yapalım. Bunun için basit bir aspnet mvc projesini yapacaz.

ilk olarak projemizi oluşturalım. Bunun için VSCode açıyoruz.

mkdir -p Multi-Stage

adında bir klasör yaratalım. Klasörü open folder diyerek VSCode ile açalım. Terminalden dotnet new mvc komutu çalıştıralım.

dotnet new mvc

diyerek projemizi dosyalarını oluşturalım.

Projemizi oluşturduk dotnet run diyip ilgili portu tarayıcınızdan çalıştırdığınızda uygulamamızın çalıştığını görelim. Şimdi de Dockerfile dosyasını yazalım. Bunun için Projenin olduğu dizine Dockerfile oluşturalım.

Dockerfile dosyamız oluşturduk. Dockerfile dosyasından image oluşturmak için ;

docker image build --tag multi-stage-image .

komutu kullanalım.

Oluşan image kontrol etmek için

docker images

komutunu çalıştıralım.

Oluşan image dan containerımızı oluşturalım. Bunun için ;

docker container run -dp 8002:80 <image_ismi>

benim image ismim multi-stage-image olduğu için onu yazıyorum.

Tarayımızdan localhost:8002 portuna gittiğimizde aşağıda ki gibi bir görüntü alıyorsanız. Containerınız çalışıyor demektir.

Doğru Dockerfile Standardı

  • Dockerfile dosyasını yazarken sıralama önemlidir.
  • İhtiyaç duyulan dosyaları kopyalanmalıdır.
Copy . .yerineCopy /deniz/containerın_ihtiyac_duyduğu_dosyalar .
  • RUN komutu tek satırda && ile birleştirilerek yazılmalıdır. Çünkü dockerfile her satır bir katmandır ve image boyutu artırır.
  • Gereksiz bağımlılıkları yüklemek için - -no-install-recommends komutunu kullanılabilir.
  • Ön Bellekteki (cache) verileri kaldırmak için rm -rf /path_bilgisi kullanılabilir.
  • En son sürüm değilde uygulamayı çalıştırdığınız versiyonu kullanmak her zaman daha iyidir.
  • Referans alınacak dosyanın en küçük boyutlu olan image’ı seçilmelidir.
  • En önemliside multi-stage şekilde yazılmalıdır.

--

--