Docker Image Nasıl Hazırlanır?

Arif KIZILTEPE
7 min readJun 3, 2020

--

Öncelikle bu yazıya başlamadan önce eğer docker ,container mimarisi ve kubernetes konsunda bilginiz yok ise aşağıdaki yazıları okumanızı tavsiye ederim.

Dockerfile’ın Yapısı

Dockerfile oluşturulacak image özellikleri, içereceği uygulamaları ve konfigürasyonlarının belli bir paterne uygun yazılan bir dosyadır. En basit anlatımla talimatlar dizesidir ve bu dosyanın adı kesinlikle Dockerfile şeklinde olmalıdır.

Dockerfile Instructions(Argümanlar)

Ufaktan Dockerfile konusunda ön bilgi verdikten sonra Dockerfile oluştururken kullanılan instructions(Argümanları) kullanım amaçlarını ve ufak örnekler vereceğim.

FROM

Baz Image belirtmek için kullanılır. Bu aşamadan sonra yapılan tüm işlemler referans alınan image üzerinde yapılır. Burada ubuntu’nun en son sürümü alınmış.

# Base image
FROM ubuntu:latest

Eğer farklı bir sürüm kullanmak isteseydik. Bu şekilde yazacaktık.

# Base image
FROM ubuntu:18.04

MAINTAINER

Dockerfile’ı oluşturan kişi bilgilerinin vermek için kullanılır. Eğer bir image oluşturup ve bunu Docker Hub üzerinde paylaşacaksınız kullanmanızda fayda olabilir.

MAINTAINER   Arif KIZILTEPE <kzltpsgm@gmail.com>

RUN

Build işlemi sırasında çalıştırılmasını istediğiniz komutları belirtmek için kullanılır. Örneğin baz ubuntu Image’ına vim editör kurmak istiyorsanız RUNkullanmamız gerekecektir.

RUN apt-get install vim

Bir Dockefile içerisinde birden fazla RUNişlemi yapabiliriz. Örneğin vim editör ile birlikte http server kuracağız ve http server servisini start edeceğiz.

RUN apt-get install vim apache2
RUN systemctl start apache2.service
RUN systemctl enable apache2.service

Ve bir RUNişlemi içerisinde birden fazla işlemi de yapabiliriz. Aslında RUNişlemi sonrasında ubuntu cli ile ne yapabiliyorsanız buraya uyarlayabilirsiniz. Aşağıdaki gördüğünüz örnekte &&ile farklı amaçlar için kullanılan komutları tek bir komut gibi çalışmasını sağladım.

RUN apt-get install vim apache2 && \
systemctl start apache2.service && \
systemctl enable apache2.service

ADD ve COPY

Dockerfile instructions(Argümanları) içinde karıştırılan ikililerden biri. Bu yüzden bu ikiliyi tek başlık altında anlatmak daha sağlıklı olacaktır. ADDhost dosya sisteminde veya internetten image içerisine dosya eklemek için kullanılır. ADD argümanının 2 farklı kullanım şekli vardır.

ADD <src>... <dest>
ADD ["<src>",... "<dest>"]

Host dosya sisteminden image içerisine dosya kopyalamak için.

ADD [ "./BuildDir/", "/app/bin"]

İnternetten Image’a dosya kopyalanması için.

ADD [ "https://curl.haxx.se/download/curl-7.50.1.tar.gz", "/tmp/curl.tar.gz" ]

COPYargümanıADD argümanı ile aynı şekilde kullanılır fakat internetten dosya indiremez sadece Host dosya sisteminden kopyalama işlemi yapabilir.

COPY ./BuildDir/    /app/bin

Şöyle ekstra bir bilgi daha ekleyeyim. Sizin bir klasörünüz var ve siz bu klasördeki *.log dosyalarını image içerisine kopyalamak istemiyorsunuz bunun için Dockerfile’ın bulundugu dizinde .dockerignore adında bir dosya açıp içerisinde belirtebilirsiniz.

EXPOSE

EXPOSEişlemi yapılmadığı durumda docker networking container’ların birbirlerinin portlarına bağlanması izin vermez. Container içerisinde çalışan uygulamanın erişilmesi gereken portu EXPOSEişlemi ile erişilebilir duruma getirmek gerekir.

EXPOSE 8080

Belirtilen port aynı docker daemon üzerindeki container’lar tarafından erişilebilir durumdadır. Bu portu host işletim sisteminden açmak için -p 8080kullanılır.

WORKDIR

Herhangi bir işlem öncesinde veya image’ın tümünün çalışma dizinini değiştirmek için kullanılır. Daha basit bir anlatım ile normal koşullarda ubuntu bir bilgisayara ssh yaptığınızda o kullanıcının wORKDIRdizini kullanıcı home dizini olarak belirlenir ve çalıştırılan komutlar bu dizinde çalıştırılır. Aynı şekilde Dockerfile içinde belirtilen RUN, CMD, ADD, COPY veya ENTRYPOINT komutları bu dizinde çalıştırılır.

WORKDIR /java/jdk/bin

ENV ve ARG

Çokça karıştırılan ikililerden bir diğeri de ENVve ARG.

Her ikisi de değişken tanımlamak için Dockerfile içerisinde kullanılır. Fakat ENVileride çalışan konteynerler için ARG ise Docker image build işlemi sırasında kullanılır.

Örnek vermek gerekirse docker üzerinde ocr işlemi yapacak python projesi çalıştıracağız. Python işlemlerini yaparken işletim sisteminden LANG değişkeninin alıyor. İşte buradaki örnekte çalışan konteyner için atanması gereken bir işlem olduğu için ENVkullanmak doğru olacaktır.

ENV LANG C.UTF-8

ARG için bir örnek vermek gerekirse FROM işlemi sırasında baz image olarak ubuntu:latestkullanıştık. Docker image build işlemi sırasında ubuntu sürümünü değiştirmek için ARGkullanmak doğru olacaktır.

ARG version=16.10
FROM node:$NODE_VERSION
  • ARG değişkenlerini Dockerfile kullanır.
  • ENVdeğişkenlerini Konteyner kullanır.
  • ARG değişkenleri build işlemi sırasında kullanılır. Build işlemi sırasında bu değişken değiştirilebilir.

(docker build --build-arg version=20.04).

  • ENVdeğişkenleri run işlemi sırasında kullanılır.

(docker run -e "LANG=C.UTF-8").

  • ARG değişkenlerine docker run işleminde verilen değer görülemez ve değiştirilemez.docker build sırasında farklı değer atanabilir.
  • ENVdeğişkenlerine docker run sırasında farklı değer atanabilir. docker build işleminde verilen değer görülemez ve değiştirilemez.

CMD

Docker container başladığında çalıştırılacak olan Linux komutunu başlatır. Bu komut docker container’ında çalışan ilk process’dir. Container’ların görevi bir process yönetmek olduğu için container içerisinde process ölürse container kapanır.

CMD [ "command", "param1", "param2" ]CMD [ "httpd", "-v" ]

CMD argümanı kullanım şekillerinden biri bir sonraki adımda anlatacağım ENTRYPOINT argümanının parametrelerini tutmak için kullanılır.

ENTRYPOINT [ "httpd" ]
CMD [ "-v" ]

Bir farklı kullanım ise shell from olarak kullanmaktır. Yani CMD argümanındann sonra yazılan her komut bin/sh -c‘ye parametre olarak verilir ve komut çalıştırılır.

CMD httpd -v

ENTRYPOINT

CMD argümanı gibi docker container başladığında çalıştırılacak olan Linux komutunu başlatır.

CMD‘ye benzer şekilde iki formatı vardır.

ENTRYPOINT [ "command", "param1", "param2" ]ENTRYPOINT [ "httpd", "-v" ]

ENTRYPOINT argümanı CMD ‘ye farkla alacağı parametreyi docker run işlemi sırasında da verebilir.

ENTRYPOINT [ "/bin/ping" ]
docker run test/myubuntu:latest 8.8.8.8

Yukarıdaki örnekte ENTRYPOINT argümanın çalıştıracağı komuta verilmesi gereken parametre run işlemi sırasında verildi. ENTRYPOINT dinamik bir image oluşturmaya fayda sağlar.

  • Dockerfile içinde ENTRYPOINT veya CMD argümanlarından birini kullanmamız gerekmektedir.
  • ENTRYPOINT ‘e run işlemi sırasında çalıştıracağı komuta parametre atanabilir.
  • CMD komutu, ENTRYPOINT komutu için default parametreleri tutmak içinde kullanılabilir.
ENTRYPOINT [ "httpd" ]
CMD [ "-v" ]

VOLUME

Belirtilen ada sahip host ile container arasında bağlama noktası oluşturmak için kullanılır. Dockerfile içerisindeki aşağıdaki örnekte /opt/properties dizini oluşturulur ve bu alan VOLUME olarak tanımlanır.

RUN mkdir /opt/properties
VOLUME /opt/properties

Run işlemi sırasında container içerisindeki /opt/properties dizin host üzerinde istediğimiz bir alan ile bağlanabilir. Bu bağlantıyı mount işlemi olarak da düşünebiliriz.

docker run test/myubuntu:latest -v /opt/myubuntu/properties:/opt/properties

HEALTHCHECK

Çalışan container’ın durumunu kontrol etmek için kullanılır.

HEALTHCHECK [<options>] CMD <command>
<options>
--interval=<duration> (default: 30s) #Sıklık
--timeout=<duration> (default: 30s) #Zaman Aşımı
--retries=<number> (default: 3) #Tekrar

Komutun sonucu

  • 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, kurduğumuz apache2 uygulamaısnı her 30 dakikada kontrol etmek ve 3 saniye içinde cevap vermesini sağlamak için aşağıdaki gibi bir check kullanabiliriz.

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

LABEL

Image’a bazı meta veriler eklemek için kullanılır.

Örneğin bir image oluşturduk ve bu image meta bilgilerine image hakkında bilgi yazmak istiyoruz.

LABEL "about"="Test için buraya bir şeyler yazmam gerekiyor..."

Image oluşturma işlemi tamamlandıktan sonra inspect ile bunu görüntüleyebiliriz.

docker image inspect

docker image inspect <imagename>

USER

Dockerfile içerisinde yapılan tüm işlemler root kullanıcısı ile yapılır. Bu argüman ile Dockerfile içerisinde istediğimiz bir adımda kullanıcı değiştirebiliriz. Örneğin apache2 adında bir kullanıcı oluşturup USER ile bu kullanıcıya geçiş yapabiliriz. Bu işlemden sonra gelen RUN, CMD, ADD, COPY veya ENTRYPOINT komutları bu kullanıcı ile çalıştırılır.

RUN useradd apache2
USER apache2

Buraya kadar elimden geldiğince Dockerfile içinde kullanılan argümanları anlatmaya çalıştım. Şimdi kendi işlerim için geliştirdiğim projelerin Dockerfile içeriğini anlatarak daha iyi anlaşılmasını sağlayacağım.

  1. Python OCR Projesi
#Baz imajımız buildpack-deps kullanıyorum. buildpack-deps debian tabanlı docker için geliştirilmiş image'dır. Bu aşamadan sonra yapılacak tüm işlemler bu imaj içerisinde yapılacak.FROM buildpack-deps:buster#Dockerfile oluşturan kişi olarak bilgilerini ekliyorum.MAINTAINER Arif KIZILTEPE <kzltpsgm@gmail.com>#Python projemiz için gerekli olan <key>=<value> şeklinde tanım yapıyoruz. Burada ARG kullanmamamızın nedeni ARG build aşamasında kullanılıyordu. Fakat biz run aşamasında kullanavağız.ENV LANG C.UTF-8#RUN ile baz imajı update ediyoruz ve uygulama için çalışacak paketleri kuruyoruz. Install işleminde mutlaka -y ile otomatik evet opsiyonunu ekleyin çünkü build işlemi sırasında hata alabilirsiniz.RUN apt-get update
RUN apt-get install -y build-essential libreadline-gplv2-dev libncursesw5-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev libtesseract-dev tesseract-ocr liblzma-dev unzip vim ssh net-tools
#Python3.6.10 dosyası wget ile indiriliyor ve /usr/src altına açlışıyor. Burada ADD komutunu da kullanailirdik dosya indirme işlemi için.RUN wget --quiet --no-cookies https://www.python.org/ftp/python/3.6.10/Python-3.6.10.tgz -O /usr/src/Python-3.6.10.tgz
RUN cd /usr/src/ && \
tar xzvf Python-3.6.10.tgz
#Python3.6.10 manuel konfigürasyon ve kurulum işlemleri tamamlanır.RUN cd /usr/src/Python-3.6.10 && \
./configure --enable-optimizations && \
make altinstall
RUN pip3.6 install --user --upgrade pip
#Proje dosyaları ADD argümanı ile host sunucudan container içerisindeki /opt içerisine kopyalanır ve unzip ile dosya açılır. Burada COPY argümanı da kullanabilirdik.ADD proje.zip /opt
RUN cd /opt && \
unzip /opt/proje.zip
#Python projesi için gerekli paketler kurulur.RUN pip3.6 install -r /opt/proje/Kurulum/requirements.txt
RUN pip3.6 install -r /opt/proje/Kurulum/requirements.txt
RUN cd /usr/src/Python-3.6.10 && \
make altinstall
#Root kullanıcısın şifresini değiştiriyoruz ve ssh aktif ediyoruz.RUN echo "root:Passw0rd" | chpasswd && \
sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config && \
sed -i 's/#Port 22/Port 22/' /etc/ssh/sshd_config && \
sed -i 's/#ListenAddress 0.0.0.0/ListenAddress 0.0.0.0/' /etc/ssh/sshd_config
#Hem host sunucu üzerinden hemde containerlar arasında 22 ve 8080 portları EXPOSE argümanı ile açılır.EXPOSE 8080
EXPOSE 22
#Yukarıdaki tüm komutlar root kullanıcısının WORKDIR dizini olan "/" üzerinde çalışıyordu. Bu dizini projenin dizini olarak değiştiriyorum.WORKDIR /opt/proje#Python içerisine paket eklemek içinRUN /usr/src/Python-3.6.10/python -c "import nltk;nltk.download('punkt')"#Bir container'ın en önemli parçası olan çalıştırılması gereken ilk process'i çalıştırıyorum.CMD /usr/src/Python-3.6.10/python app.py > /opt/proje/logs/logfile.log 2>&1

Ben daha sonra oluşturduğum image’ı kubernetes’e bağlı node’lara yayacağım için buildişlemini master node üzerinde yapıyorum. Bu aşamada isterseniz stand-alone docker üzerinde de yapabilirsiz. Dockerfile bulunduğu klasörde build işlemini çalıştırıyoruz.

docker image build -t 32bitbilgisayar/figo .#--tag , -t  Oluşturulacak image'e isim ve sürüm atamak için kullanılır. ‘name:tag’

Build işlem süresi, Dockerfile içerisindeki yapılacak işlemlere göre değişiklik gösterebilir. İşlem başarı ile tamamlandıktan sonra listeleyerek görüntüleyebiliriz.

docker image list

Bir sonraki yazımda Kubernetes yaml ile bu uygulamayı 3 worker sunucuya dağıtılmasını anlatacağım. Fakat uygulamayı test etmek açısında runişlemi ile container oluşturuyorum.

docker run  -d  -p 30080:8080 -p 30022:22 32bitbilgisayar/figo#--detach , -d Container'ın arkaplanda çalışmasını sağlar.
#--publish , -p Image içerisinde expose edilen portların host sunucu üzerinden yayınlanmasını sağlar.

Evet başarı ile çalışmaya başladı. Bir sonraki adıma geçmeden önce container’ı siliyorum.

docker rm -f ae8008af72c7
# --force , -f Silme işlemini zorlamak için kullanılır.
# Silme işlemi için CONTAINER ID yada CONTAINER NAME kullanabilirsiniz.

--

--

No responses yet