Dockerfile, Docker konteynerlarının yapısını belirleyen bir konfigürasyon dosyasıdır. İçerisinde uygulamanın nasıl çalıştırılacağı ve hangi bağımlılıkların yüklenmesi gerektiği gibi talimatları bulundurur. Docker, bu Dockerfile kullanarak bir konteyner oluşturur ve bu konteyneri bir “image” olarak adlandırılan bir dosyaya dönüştürür. Bu “image”, daha sonra herhangi bir sistemde çalıştırılabilir hale gelir.
Bu makalede, Dockerfile oluşturma sürecini adım adım açıklayacak, Dockerfile komutlarını detaylı bir şekilde inceleyecek ve örnek kullanımlarla pratik bilgiler sunacağım. Dockerfile, Docker konteynerlarının yapısını belirleyen ve uygulamanın nasıl çalıştırılacağı ile hangi bağımlılıkların yükleneceğini belirten bir yapılandırma dosyasıdır.
Dockerfile oluştururken izlenecek adımları basit ve anlaşılır bir şekilde açıklayacağım. Her bir Dockerfile komutunu, ne işe yaradığını ve nasıl kullanılacağını örneklerle göstereceğim. Ayrıca, yaygın senaryolara özel örneklerle Dockerfile’ların nasıl uygulandığını göstereceğim.
Bu makaleyi okuyanlar, Docker kullanımını daha iyi anlayacak ve kendi projelerinde Dockerfile’larını daha etkili bir şekilde kullanabilecekler.
Dockerfile’ın başında bulunan ve temel imajı belirten komut FROM
‘dur. Temel imaj, Docker konteynerinizin çalışacağı işletim sistemi ve çevresini sağlar. Bu imajlar Docker Hub veya başka bir Docker imaj kaynağından alınabilir.
Örneğin: linux terminalde
FROM ubuntu:20.04
Bu komut, Docker konteynerinin temel imajını Ubuntu 20.04 olarak belirler. İlgili Dockerfile, konteynerin Ubuntu 20.04 işletim sistemini kullanarak yapılandırılacağını ifade eder.
FROM
komutu, Dockerfile’ın en önemli başlangıç noktalarından biridir çünkü bu, konteynerin temelini oluşturur. Bu komut, konteynerinizin gereksinimlerine ve uygulamanızın çalışmasına uygun bir temel imajı seçmek için kritik öneme sahiptir.
FROM python:3.8
Bu komut, Dockerfile’da Python dilini kullanarak bir uygulama geliştirmek istediğinizi belirtir. python:3.8
, Docker Hub’daki resmi Python imajından Python 3.8 sürümünü temel alır. Bu, Docker konteynerinizin Python 3.8 çalışma ortamına sahip olacağı anlamına gelir. Bu temel imaj, Python uygulamalarınızı çalıştırmak ve geliştirmek için gereken çeşitli Python paketleri ve araçları içerir.
Bazı senaryolarda, birden fazla FROM
komutu gerekebilir. İlk FROM
komutu, uygulamanın derlenmesi ve bağımlılıkların yüklenmesi gibi işlemleri gerçekleştiren bir ortamı belirtirken, ikinci bir FROM
komutu, çalıştırılabilir bir üretim imajını ifade edebilir. Bu yaklaşım, Dockerfile’ın farklı aşamaları için özel olarak ayarlanmış farklı temel imajlar kullanma esnekliği sağlar. Bu, örneğin geliştirme ve dağıtım aşamaları arasında farklı gereksinimleri olan projeler için faydalı olabilir.
Örnek olarak node.JS de bir nginx uygulamasi üreteceğim
# Derleme Adımları
FROM node:14 AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# Production Adımları
FROM nginx:alpine
WORKDIR /usr/share/nginx/html
COPY --from=build /app/build .
Bu Dockerfile, iki farklı aşamada bir web uygulamasını oluşturur. İlk aşama, “Derleme aşaması” olarak adlandırılır ve Node.js 14 imajını kullanarak uygulamanın kaynak kodunu derler ve paketlerini yükler. İkinci aşama ise “Production aşaması”dır ve Nginx’in Alpine sürümünü kullanarak derlenen uygulamayı bir üretim sunucusuna yayınlamak için hazırlanır.
İşte kodun ayrıntılı açıklaması:
FROM node:14 AS build
: İlk olarak, “Derleme aşaması” için bir temel imaj belirlenir. Bu aşamada, Node.js 14 imajı kullanılır vebuild
adında bir aşama tanımlanır.WORKDIR /app
: Çalışma dizini/app
olarak ayarlanır.COPY package*.json ./
:package.json
vepackage-lock.json
dosyaları mevcut dizinden (./
)/app
dizinine kopyalanır.RUN npm install
: Node.js paketlerinin yüklenmesi içinnpm install
komutu çalıştırılır.COPY . .
: Tüm kaynak kodu mevcut dizinden/app
dizinine kopyalanır.RUN npm run build
: Uygulama derlenir ve oluşturulan ürün dosyaları/app/build
dizinine yerleştirilir.FROM nginx:alpine
: İkinci aşama için temel imaj belirlenir. Bu aşama “Production aşaması”dır ve Nginx’in Alpine sürümü kullanılır.WORKDIR /usr/share/nginx/html
: Çalışma dizini/usr/share/nginx/html
olarak ayarlanır. Nginx sunucusu, HTML dosyalarını bu dizinde bekler.COPY --from=build /app/build .
:--from=build
seçeneğiyle, önceki derleme aşamasından (build
) gelen ürün dosyaları (/app/build
) mevcut dizine (.
) kopyalanır. Bu, derlenen web uygulamasının Nginx sunucusuna yayılmasını sağlar.
Sonuç olarak, bu Dockerfile, Node.js kullanarak bir web uygulamasının derlenmesi ve Nginx sunucusuna entegre edilmesi sürecini adım adım otomatize eder.
Dockerfile WORKDIR Kullanımı
WORKDIR komutu, Dockerfile içinde çalışma dizini (working directory) olarak belirtilen dizini ayarlar. Bu komut, Docker konteynerinizin içindeki komutların ve işlemlerin çalışacağı dizini belirler. WORKDIR’den sonraki komutlar burada belirtilen dizinde çalıştırılır.
WORKDIR /app # Docker konteynerinizin içindeki tüm sonraki komutların /app dizininde çalışmasını sağlar.
WORKDIR src # Dockerfile ile aynı dizindeki "src" dizinini çalışma dizini olarak belirler.
Birden Fazla WORKDIR Kullanımı:
# Başlangıç dizinini /app olarak ayarladı
WORKDIR /app
# Daha sonra /app dizini Dockerfile içindeki src ile değiştirdi
WORKDIR src
# Tekrar başlangıç dizinine döndü
WORKDIR /app
WORKDIR komutu, Dockerfile içindeki sonraki komutların çalışma dizinini belirler.
Dockerfile COPY veya ADD Kullanımı
COPY ve RUN komutu, dosyaları ve dizinleri Docker imajınızın veya konteynerinizin belirli bir konumuna kopyalamak için kullanılır. Bu komutların kullanımı şu şekildedir:
COPY <kaynak> <hedef>
- <kaynak>: Kopyalanacak dosya veya dizinin yolunu belirtir. Genellikle Dockerfile ile aynı dizinde bulunan dosyaları kopyalamak için kullanılır
- <hedef>: Dosyanın veya dizinin kopyalanacağı hedef konumu belirtir.
COPY index.html /var/www/html/ #Dockerfile dosyasının bulunduğu dizindeki index.html dosyasını /var/www/html/ yoluna kopyaladı.
COPY . /var/www/html/ #Dockerfile dosyasının bulunduğu dizindeki tüm dosyaları /var/www/html/ yoluna kopyaladı.
ADD komutu, dosyaları ve dizinleri COPY ile benzer bir şekilde kopyalamanın yanı sıra, uzak bir URL’den dosyaları çekme ve sıkıştırılmış arşivleri otomatik olarak açma yeteneğine sahiptir. ADD komutunun kullanımı şu şekildedir:
ADD <kaynak> <hedef>
- <kaynak>: Kopyalanacak dosya, url, arşiv veya dizinin yolunu belirtir.
- <hedef>: Dosyanın veya dizinin kopyalanacağı hedef konumu belirtir.
ADD index.html /var/www/html/ #Dockerfile dosyasının bulunduğu dizindeki index.html dosyasını /var/www/html/ yoluna kopyaladı.
ADD https://example.com/myfile.txt /app/ #https://erdemaytek.com/myfile.txt URL'sinden dosyayı indirir ve /app/ dizinine kopyalar.
ADD myapp.tar.gz /opt/ #Dockerfile dosyasının bulunduğu dizindeki myapp.tar.gz adlı sıkıştırılmış bir arşivi /opt/ dizininde otomatik olarak açar.
Dockerfile RUN Kullanımı
RUN komutu, Dockerfile içinde çalışan bir komut dizisi veya komutu belirtir. Bu komut, Docker imajınızı oluştururken imajın içinde çalıştırılacak komutları tanımlamanıza olanak tanır. RUN komutu genellikle imajınıza bağımlılıkları yüklemek, paketleri güncellemek veya özel yapılandırmaları gerçekleştirmek gibi işlemler için kullanılır.
Aşağıdaki örnekte FROM
ile güncel ubuntu imajını kullanacağımızı belirttik. RUN
komutu ile de tıpkı bir ubuntu terminalindeki gibi kodlar çalıştırmayı sağladık.
FROM ubuntu:latest
#RUN komutu her satırda ayrı ayrı yazılabilir.
RUN apt-get update #Ubuntu işletim sistemini güncelledik.
RUN apt-get install -y \\ apache #Apache kurulumu yaptık.
#RUN komutu tek satırda da && kullanarak çalışacak komutlar bir birine bağlanıp kullanılabilir.
RUN apt-get update && apt-get install -y apache #Önce güncelleme yapılır sonrada apache paketi yüklenir.
Örneğin Python imajlı bir Docker dosyasında paketler aşağıdaki gibi yüklenebilir.
# Resmi Python 3 imajını kullandık
FROM python:3
# requests ve numpy paketlerini yüklüyoruz
RUN pip install requests numpy
Dockerfile CMD ve ENTRYPOINT Kullanımı
CMD ve ENTRYPOINT komutları, Docker konteynerinizin başlatıldığında çalıştırılacak komutları belirlemek için kullanılır. İki komut arasındaki temel fark, CMD ile belirtilen komutların konteynerin başlatılmasının ardından kullanıcının geçersiz kılabilmesidir, ancak ENTRYPOINT ile belirtilen komutlar değişmez fakat üzerine ek argümanlar eklemek mümkündür.
CMD
ile Örnek:
Dockerfile’da CMD kullanarak bir komut belirledik:
# Resmi Python 3 imajını temel aldık
FROM python:3
# Uygulama dosyalarını çalışma dizinine kopyaladık
COPY myscript.py /myscript.py
# CMD komutunu kullanarak varsayılanda myscript.py çalışacağını belirttik.
CMD ["python", "/myscript.py"]
Docker konteyneri başlatıldığında CMD [“python”, “/myscript.py”] komutu çalışır, ancak kullanıcı bu komutu isterse geçersiz kılabilir:
Kullanıcı, Docker konteynerini başlatırken komutu değiştirebilir ve örneğin echo komutunu çalıştırabilir.
#Varsayılan kullanımda CMD ["python", "/myscript.py"] çalıştı.
docker run myimage
#Kullanıcı CMD ["python", "/myscript.py"] komutunu ezip yerine echo "Merhaba, Docker!" komutunu çalıştırdı.
docker run myimage echo "Merhaba, Docker!"
ENTRYPOINT ile Örnek:
Aynı senaryoyu ENTRYPOINT ile ele alalım:
# Resmi Python 3 imajını temel aldık
FROM python:3
# Uygulama dosyalarını çalışma dizinine kopyaladık
COPY myscript.py /myscript.py
# ENTRYPOINT komutunu kullanarak her şartta ["python", "/myscript.py"] komutunun çalışmasını sağladık.
ENTRYPOINT ["python", "/myscript.py"]
Docker konteyneri başlatıldığında ENTRYPOINT [“python”, “/myscript.py”] komutu her zaman çalışır ve kullanıcı tarafından geçersiz kılınamaz. Kullanıcı bu komutun üzerine ekstra komut ekleyemez:
docker run myimage echo "Merhaba, Docker!"
Bu durumda, Docker komutu “python /myscript.py” olarak kalır ve echo komutu çalışmaz.
Yani, temel fark, CMD ile kullanıcının komutu geçersiz kılabilmesi ve değiştirebilmesi, ENTRYPOINT ile ise komutun sabit kalması ve kullanıcının bunu değiştirememesi şeklinde özetlenebilir.
CMD ve ENTRYPOINT’ı aynı anda kullanmak
Bu iki komut, birlikte kullanıldığında CMD komutunun ENTRYPOINT komutunu çalıştırmak için bir argüman olarak kullanıldığı bir senaryo oluşturabilir.
# Resmi Python 3 imajını kullandık
FROM python:3
# Uygulama dosyalarını çalışma dizinine kopyaladık
COPY myscript.py /myscript.py
# ENTRYPOINT komutunu kullanarak her şartta başlatılacak komutu belirledik
ENTRYPOINT ["python", "/myscript.py"]
# Argüman olarak 12 ve 13 sayıları varsayılanda script dosyasına gönderdik..
CMD ["12", "13"]
Docker konteynerini başlatırken, CMD ile belirtilen varsayılan argümanlar kullanılır, ancak kullanıcı bu argümanları geçersiz kılabilir:
#Bu şekilde çalıştırılırsa varsayılandaki 12 ve 13 değerleri parametre olarak gönderilecektir.
docker run myimage
#Bu şekilde çalıştırılırsa varsayılan değerler yok sayılır
docker run myimage 17 18
Bu durumda, Docker konteyneri “python /myscript.py 17 18” komutunu çalıştırır.
Parametre Göndermek
Her iki örnekte de kodunuza aşağıdaki gibi parametre gönderebilirsiniz. Tek fark CMD de komut da gönderip varsayılan çalışma kodunu değiştirebiliyor ilken ENTRYPOINT de böyle bir durum olmuyor.
Yukarıdaki örnekler dikkate alındığında aşağıdaki gibi imaj çalıştırıldığında “python /myscript.py” komutu çalışacak ve “arg1”, “arg2” ve “arg3” gibi ek parametreler myscript.py betiğine iletilecektir.
docker run myimage arg1 arg2 arg3
Dockerfile EXPOSE Kullanımı
EXPOSE komutu, bir Docker konteynerinin belirli bir portunu veya portlarını dış dünyaya açmak için kullanılır. Bu komut, Docker konteynerinde çalışan bir servisin veya uygulamanın, aynı host üzerinde veya başka bir yerden erişilebilir olmasını sağlar. Ancak EXPOSE komutu, portları otomatik olarak dış dünyaya açmaz, sadece Dockerfile’da belirtilen portların hangi portların dışa açılacağını bildirir.
# Resmi Python 3 imajını kullandık
FROM python:3
# Uygulama dosyalarını çalışma dizinine kopyaladık
COPY myapp.py /myapp.py
# Uygulamanın 8080 portunu kullanacağını belirttik. Diğer tabirle konteynerin port 8080'i dinlediğini belirttik.
EXPOSE 8080
# Uygulamayı başlat
CMD ["python", "/myapp.py"]
Dockerfile ENV Kullanımı
ENV, Docker konteynerlerinde ortam değişkenlerini ayarlamak için kullanılır. Ortam değişkenleri, konteyner içinde çalışan uygulamalar için konfigürasyon değerleri, veritabanı bağlantı bilgileri gibi bilgileri saklamak için aktif kullanılır.
Örnek Node.js Uygulaması (app.js):
const http = require('http');
const hostname = process.env.HOSTNAME // Ortam değişkenini kullandık
const port = process.env.PORT // Ortam değişkenini kullandık
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end(`Merhaba, Docker! Bu uygulama ${hostname}:${port} üzerinden çalışıyor.\\n`);
});
server.listen(port, hostname, () => {
console.log(`Server çalışıyor: <http://$>{hostname}:${port}/`);
});
Bu Node.js uygulaması, iki ortam değişkeni kullanarak çalışma zamanında HOSTNAME ve PORT değerlerini ayarlar.
FROM node:14
COPY app.js /app.js
# Varsayılan ortam değişkenlerini ayarlıyoruz
ENV HOSTNAME="0.0.0.0" PORT=3000
CMD ["node", "/app.js"]
Şimdi bu Dockerfile’ı kullanarak Docker imajını oluşturalım ve Docker konteynerini başlatalım:
docker build -t mynodeapp .
#Herhangi bir ek parametre ile evn değiştirmediğim için dockerfile içinde kayıtlı olan değerleri kullanacak.
docker run -p 3000:3000 mynodeapp
#-e parametresi ile HOSTNAME değişkeninin değerini konteynarı çalıştırırken değiştirik. Yani dockerfile içindeki bu değeri ezmiş olduk.
docker run -p 3000:3000 -e HOSTNAME="localhost" mynodeapp
Dockerfile Volume Kullanımı
Docker’da VOLUME komutu, bir Docker konteynerı içindeki belirli bir dizini veya verileri, ana bilgisayar (host) işletim sistemi ile paylaşmanıza ve kalıcı veri depolama sağlamanıza yardımcı olur.
VOLUME komutunun temel kullanımı şu şekildedir:
VOLUME ["/path/to/directory"]
/path/to/directory: Konteyner içinde veriyi saklamak veya paylaşmak istediğiniz dizinin yoludur.
Örneğin;
FROM python:3
COPY app.py /app.py
# Verileri saklamak veya paylaşmak için oluşan conteynır içinde bir VOLUME oluşturduk
VOLUME /data
# Uygulamayı başlattık
CMD ["python", "/app.py"]
Container içindeki veriyi host olan makineye bağlayabilmek için -v parametresi ile host üzerinde nereye bağlanacağı belirtilmesi gerekir. Aksi durumda kontainerdeki veriler kapanınca sıfırlanır
docker run -v hostdatafolder:/data imajadi
Dockerfile ARG Kullanımı
ARG, Dockerfile içinde tanımlanan değişkenleri temsil eder ve docker build komutu sırasında değerleri geçmek için kullanılır. ARG kullanarak, aynı Dockerfile’ı farklı bağlamlarda kullanabilir ve farklı değerlerle imajları oluşturabilirsiniz.
Örneğin, bir Node.js uygulamasının Docker imajını oluştururken, uygulamanın sürümünü ARG kullanarak dinamik olarak ayarlayabiliriz:
# Varsayılan ARG tanımlamadık
ARG NODE_VERSION=14
# Resmi Node.js imajını kullandık. Fakat bizim vereceğimiz argümana göre bir versiyon seçecek.
FROM node:${NODE_VERSION}
COPY . /app
CMD ["node", "/app/app.js"]
Docker build komutu ile ARG değerini geçirmek için –build-arg seçeneğini kullanıyoruz:
docker build --build-arg NODE_VERSION=12 -t my-node-app .
Yukarıdaki komut, NODE_VERSION ARG’sini 12 olarak ayarlar ve Dockerfile içindeki ARG’yi kullanarak imajı oluşturur. Eğer değer vermeydik 14 olarak oluşturacaktı.
ARG değerleri, Docker imajının oluşturulmasında kullanıldıktan sonra imajın içinde kullanılamazlar. Bu nedenle ARG’leri ortam değişkenlerine kopyalamak için ENV komutunu kullanabilirsiniz.
Dockerfile Docker İmajını Oluşturma (Build):
Dockerfile ile Docker imajınızı oluşturmak için docker build komutunu kullanıyoruz.
docker build -t <image-name>:<tag> <path-to-dockerfile-directory>
- <image-name>: Oluşturduğunuz Docker imajının adını belirtir.
- <tag>: İmajınıza bir etiket (tag) atar. Genellikle sürüm numarası veya “latest” gibi tanımlayıcılar kullanılır.
- <path-to-dockerfile-directory>: Dockerfile’ın bulunduğu dizinin yolunu belirtir. Dockerfile proje kök dizinindeyse, yolu belirtmenize gerek yoktur.
docker build -t myapp:1.0 .
Bu komut, “myapp” adında bir Docker imajı oluşturur ve sürümünü “1.0” olarak etiketler. Dockerfile proje kök dizininde bulunduğu için nokta (“.”) işareti dizin yolunu ifade eder.
Docker imajını başlatmak için docker run komutunu kullanıyoruz ve tadaa 🙂
Kaynak ve yararlanacağimiz dökümanlar bilgileri için
https://docs.docker.com/develop/develop-images/dockerfile_best-practices/