Docker Nedir? Nasıl Kullanılır?

Uygulamalar zamanında fiziksel sunucular üzerinde yapılandırılarak barındırılmaktaydı. İzole uygulamalar ilave sunuculara ihtiyaç duymaktadır. Bu süreç hem maliyeti arttırıyor hem de deployment işlemlerini yavaşlatarak yönetimi zorlaştırıyordu. Sanallaştırmanın hayatımıza girmesiyle sunucularda birden fazla işletim sistemi ayağa kaldırılarak kaynaklar daha verimli kullanılmaya başlandı. Ölçeklendirme ve deployment işlemleri hızlansada her sanal makinanın işletim sistemi gerektirmesi, taşınabilirlik gibi sorunlar devam etmekteydi. Bu gibi sorunlar container-based virtualization ile çözüme kavuşmuştur. Go diliyle yazılan Docker bu noktada karşımıza çıkmaktadır.

Docker, işletim sistemi üzerine eklediği Container Engine ile uygulamaları ihtiyaç duyduğu paketlerle çalıştırmaktadır. Bu yapıyla birlikte dağıtım ve taşınabilirlik sorunları çözülürken uygulamalar arasında izolasyon da sağlanmaktadır.

Docker client-server mimarisini kullanır. Kullanıcı client aracılığıyla daemon ile iletişim kurar. Client (kinematic, command-line) aldığı komutları Daemon’a ileten kullanıcı arabirimidir. Daemon (docker server, docker engine) host üzerinde sürekli çalışarak container run, build ve distribution işlemlerini üstlenmektedir.

Image ve container olmak üzere iki ana bölümden oluşmaktadır. Aralarındaki ayrıma class ve instance ilişkisi örnek gösterilmektedir. Image bir sınıf şeklinde düşünülürse sınıfın örneklenmesiyle container oluşmaktadır.

Kurulum versiyondan versiyona farklılık gösterebileceğinden resmi sitesindeki adımlara göre kurulum sağlanmalıdır.

Images

İmajlar, oluşturulacak her container için read-only şablon görevindedir. Uygulama ve gerekli ortam bilgilerini (işletim sistemi, runtime, v.b.) içermektedir. Container oluşturulmaksızın kendi kendilerine çalıştırılamazlar. Dockerfile kullanılarak oluşturulmaktadırlar.

İmajlar özel bir Registry üzerinde depolanacağı gibi Docker Registry üzerinde depolanabilmektedirler. Registry içerisinde yer alan her repository çeşitli tag’lara göre derlenmiş sürümlerden oluşmaktadır. Imaj oluşturulurken bir tag belirtilmemesi durumunda varsayılan tag latest olacaktır.

Containers

Imajların çalışan örnekleridir. Bir container oluşturulduğunda imajın üstüne ince bir read-write katmanı eklenmektedir. Aynı imaja bağlı birden fazla container birbirinden izole şekilde ayağa kaldırılabilir. Uygulamalar arası herhangi bir state veya data paylaşımı olmaz.

Volumes

Imajlar bir kez oluşturulduğunda read-only olduklarından değiştirilemezler. Bir değişiklik için yeniden build edilmelidirler. Container’lar imajların üstüne ince bir read-write katmanı eklediklerinden okuma ve yazma yapabilirler. Bu imajı değiştirmeden imaj içerisinde dosya işlemleri yapılabileceği anlamına gelir. Okuma yazma işlemi yapılabilmesine rağmen bir kaç sorun mevcuttur. Container’ın silinmesi durumunda yazılmış veriler de kaybolacaktır, bu sorun volume kullanılarak çözülmektedir. Container, host dosya sistemiyle etkileşime giremez. Proje dizininde yapılacak değişiklikler çalışan container içerisine yansımayacaktır. Yeni bir imaj build işlemiyle yeni bir container oluşturulup başlatılması yerine bind mount kullanılabilir.

Volume, bir container içerisindeki klasör ve dosyalara bağlı, host tarafından yönetilen klasör ve dosyalardır. İki tür volume vardır.

  • Anonymous volume container silindiğinde otomatik olarak içerisindeki veriyle birlikte volume da silinir. -v /PATH parametresiyle oluşturulmaktadır. Bind mount tarafından container içi verilerin override edilmemesi adına yararlı olabilir.
  • Named volume container’dan bağımsız olarak var olmakta ve komut aracılığıyla silinebilmektedirler. -v NAME:/PATH parametresiyle oluşturulurlar. Upload edilen dosyalar, veritabanı dosyaları gibi container verilerinin tutulması amacıyla kullanılırlar.

Volume kullanılarak container içerisine veri taşınabilir ve container tarafından yazılan veriler korunabilir; ancak bu değişiklikler host’a yansımaz. Volume, Docker tarafından oluşturulur ve yönetilir.

Bind Mounts

Volume ile benzerlik göstermektedir. Aralarındaki fark host’a container içerisindeki bir yola bağlanması gereken yolun ayarlanmasıdır. -v /ABS_HOST_PATH:CONTAINER_PATH parametresiyle oluşturulmaktadır.

Development ortamında Container çalışırken paylaşılan verinin (source code) değişeceği durumlarda yararlıdırlar. Production ortamında kullanılmaması tavsiye edilmektedir.

Networks

Gerçek hayat senaryolarında birden fazla container’a ihtiyaç duyulacaktır. Birden fazla ana işleve sahip bir container’ın yönetimi zorlaşacağından her ana işlevin (web server, database) kendi container’ına sahip olması best-practice olarak kabul edilmektedir. Bu durum container’lerın kendi aralarında, host ile ve www ile iletişime geçme ihtiyacını doğurmaktadır.

www ile iletişim kurmak (Http, gRPC istekleri gibi) oldukça kolaydır. Hangi programlama dili kullanılırsa kullanılsın Container içerisinde ekstra bir yapılandırma gerekmeksizin normalde olduğu gibi istek gönderilebilmektedir.

Host ile iletişim kurmak (Host üzerinde çalışan bir veritabanı) için ufak bir değişiklik yapılması yeterli olacaktır. Host üzerinde localhost:3000 adresinde çalışan bir web server’a container dışından istek atıldığını düşünelim. Container içerisinde localhost container’ın kendisi olacağından istek başarısız olacaktır. Bu sorunu çözmek adına host.docker.internal özel adresi kullanılmalıdır. Bu adres Docker tarafından Host IP adresine dönüştürülmektedir. Böylece host.docker.internal:3000 adresine yapılan istekler Docker tarafından çözümlenerek başarıyla sonuçlanacaktır.

Container’ler arasında iletişim kurmak için iki seçecek mevcuttur. İletişim kurulacak Container IP adresi elde edilerek istek gönderilebilir, ancak bu adres zamanla değişebileceğinden kalıcı çözüm sunmaz. Bir diğer yöntemde Docker Network kullanmaktır. Bir network oluşturulup mevcut container’lar bu ağa eklenerek container’ların birbirleriyle haberleşmesi sağlanabilir.

Böylece iki container aynı network altında olacaktır. Birbirleriyle haberleşirken kullanacağı adreslere de container ismi yazılması (container1/api/products gibi) yeterli olacaktır. Docker IP adreslerini bizim için çözümleyecektir.

Docker komutuyla ilgili tüm komut listesi, konsola ilgili komuttan sonra --help flagı eklenerek docker --help docker run --help görülebilmektedir. Detaylı bilgi için dokümantasyon taranabilir.

docker build .Dockerfile adımlarına göre bir imaj oluşturur. -t NAME:TAG parametresiyle oluşturulacak imaja bir isim ve tag verilmektedir.
docker run IMAGEIMAGE ile belirtilen imajdan bir container oluşturarak başlatır. Mevcut imaj çalışma ortamında bulunmuyorsa registry üzerinden indirilir. --name NAME parametresiyle oluşturulacak container’a bir isim verilir. -d parametresi kullanılırsa container detached mod ile başlatılırsa konsol container’ın durmasını beklemez. -it parametresiyle container interactive mod ile başlatılarak container’a konsol üzerinden komut gönderilebilir. --rm parametresiyle container durduğunda otomatik silinmesi sağlanır.
docker imagesÇalışma ortamındaki imajları listeler.
docker psÇalışan tüm container’ları listeler. -a parametresi kullanılırsa durmuş container’lar da listeye dahil edilir.
docker rmi IMAGEIMAGE ile belirtilen (name, id) imajı siler.
docker rm CONTAINERCONTAINER ile belirtilen (name, id) container’ı siler.
docker image pruneBir taga sahip olmayan (untagged) tüm imajları siler. -a parametresi kullanılırsa tüm imajlar silinir.
docker container pruneÇalışmayan tüm container’ları siler.
docker push IMAGERegistry’e belirtilen imajı gönderir.
docker pull IMAGERegistry’den belirtilen imajı çeker.
docker volume lsTüm volume’ları listeler.
docker volume create NAMENAME ile belirtilen isimde bir named volume oluşturur. Container çalıştırılırken mevcut değilse otomatik olarak oluşturulacağından genellikle buna gerek kalmaz.
docker volume rm NAMENAME ile belirtilen (name, id) volume’u siler.
docker volume pruneKullanılmayan tüm volume’ları siler.
docker network create NAMENAME ile belirtilen isimde bir network oluşturur.

Dockerfile

Dockerfile instruction adındaki adımlardan oluşmaktadır. Bu adımlar İmajın nasıl oluşturulacağını belirtmektedir. Imaj oluşturulduğunda bu adımlar birer katmana dönüşmektedir. Oluşturulan katmanlar sonrasında imajları verimli şekilde yeniden oluşturmak ve imajlar arasında paylaşmak için kullanılmaktadır. Docker Cache sayesinde eğer adımlar değiştirilmemişse bir sonraki imaj oluşturma işleminde önceden oluşturulmuş mevcut katman kullanılacaktır. Bu sayede build süresi kısalacaktır. Bu adımlarda kullanılabilecek komutlarla birlikte örnek bir Dockerfile’a göz atalım.

Yorum satırlarının # işaretiyle başladığına dikkat edelim.

FROM

FROM komutu kendisinden sonra gelen adımlar için base image ayarlar. Dockerfile bir FROM komutuyla başlamalıdır. Birden fazla base image belirtilebilir.

WORKDIR

WORKDIR komutu, RUN CMD ENTRYPOINT COPY ve ADD komutlarının hangi dizinde çalıştırılacağını belirtir. WORKDIR belirtilmemişse sonraki adımlar tarafından kullanılmayacak olsa dahi oluşturulacaktır. Birden çok kez kullanılabilirler. Belirtilen dizinlerin relative olması durumunda bir önceki dizin baz alınacaktır.

ADD

ADD komutu kaynak olarak belirtilen dosya, klasör ve internet üzerindeki verileri imaj içerisinde belirtilen hedef dizine kopyalar. Birden çok kaynak belirtilebilir. Bu komuta gerçekten ihtiyaç varsa kullanılması önerilmektedir. Aksi durumda COPY komutu tercih edilmelidir.

COPY

COPY komutu kaynak olarak belirtilen dizinden hedef dizine mevcut dosya ve klasörleri kopyalayarak taşır. ADD komutuna göre farkı internet üzerinden değil yalnızca host içerisinden kopyalama yapabilmesidir. Birden fazla kaynak belirtilebilir.

EXPOSE

EXPOSE komutu container’ın çalışma zamanında hangi portu kullanacağını bildirir. Bir protokol belirtilmediğinde varsayılan TCP protokolü kullanılır. Bu komut dokümantasyon amacıyla hangi portların kullanılacağını bildirir, belirtilen portlar yayınlanmaz. Bir container çalıştırılacağında port yayınlamak için -p parametresi kullanılmalıdır.

ENV

ENV komutu girilen değerleri environment variable olarak ayarlar. Bu değerler build aşamasında kendisinden sonra gelen komutlar tarafından kullanılabilir ve sonrasında değiştirilebilir.

VOLUME

VOLUME komutu container içerisinde belirtilen dizinle host üzerinde oluşturduğu dizini birbirlerine bağlayarak anonymous volume oluşturur. Alacağı değer array ya da string tipinde olabilir. Volume komutunun kullanılması yerine container başlatılırken -v parametresiyle ayarlanması önerilmektedir.

RUN

RUN komutu imaj oluşturulurken çalıştırılması istenen komutları yürütmektedir. Yeni bir imaj katmanı oluşturduklarından sayılarının az tutulması önerilmektedir.

CMD

CMD komutu container başlatıldığında çalıştırılması istenen komutlardır. Dockerfile içerisinde CMD komutu belirtilmediğinde FROM komutuyla belirlenmiş base image default komutu çalıştırılacaktır.

Container çalıştırılırken imaj isminden sonra bir command belirtilmişse Dockerfile içerisindeki CMD komutu override edilecektir.

ENTRYPOINT

ENTRYPOINT komutu yine container başlatıldığında çalıştırılması istenen komutlardır. CMD komutundan farkıysa imaj isminden sonra belirtilen command override edilmek yerine belirtilen komutun sonuna eklenmesidir.

Dockerignore

Docker Client, Daemon ile iletişime geçmeden önce root dizinde .dockerignore isminde bir dosya arar, mevcut olması durumunda içerisinde belirtilen dosya veya klasörlerin ADD veya COPY komutlarıyla imaja taşınması engellenmektedir. Böylece istenmeyen büyük ve hassas dosya veya dizinlerin imaja taşınmasının önüne geçilebilmektedir.

Docker Compose

Docker Compose multi-container Docker uygulamarını çalıştırmaya yarayan bir araçtır. Bu araçla birlikte container tanımları tek bir YAML dosyasından yapılarak uygulamalar bir komutla çalıştırılabilir ve durdurulabilir.

Birden fazla container’a sahip olduğumuzu düşünelim, Docker Compose kullanılmadığı taktirde network oluşturma, imaj build işlemleri, container oluşturma ve oluşturulan network’e dahil etmek gibi bir çok komut yazmamız ve bu komutları hatırlamamız gerekmektedir. Üstelik yapılacak en ufak değişikliklerde bu sürecin tekrarlanması gerekecektir. Docker Compose kullanıldığındaysa container konfigürasyonlarının docker-compose.yml dosyasına belirtilmesi yeterli olacaktır.

Bu dosya istenildiğinde tek bir yerden düzenlenerek docker-compose up komutuyla ayağa kaldırılabilir. Tüm konfigürasyonlara buradan ulaşabilirsiniz.

Docker Compose ile çalışırken adımıza bir network oluşturulmakta ve tüm container’lar bu network’e dahil edilmektedir. Birden fazla network’e ihtiyacımız yoksa ekstradan bir network oluşturmamıza gerek kalmamaktadır.

docker compose upYAML dosyasında belirtilen container’ları başlatır.
docker compose downİlgili container’ları durdurur.
docker compose psYAML dosyasında belirtilen container’ları listeler.
docker compose logsCompose tarafından yönetilen container log bilgilerini gösterir. -f parametresi kullanılırsa yeni gelenler de eklenir. Bir container ismi eklenirse yalnızca ilgili container’a ait log bilgileri sunulur.
docker compose rmİlgili container’ları siler.
docker compose buildCompose tarafından yönetilen imajları build eder.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.