30 Mart 2019 Cumartesi

Docker Notlarım

Docker
Bir java yazılımcı jar ve war olarak uygulamayı paylaşabilir.
Ama jvm argument (active spring profiles gibi), mysql ayarları vs gibi uygulamaının ihtiyaç duyduğu
ayarları da paylaşmak zorundadır.
Ama bunu docker içine koyarsa, ilgili jdk, ilgili işletim sisteminin tool ve utilleri, ayarlanmış program
argumentleri image olarak paylaşabilir.
Docker image bir kalıptır, container ise bunun kernel üzerinde çalışan instance’dır.
Image bir tane olurken container’lar birden fazla olabilir.
Kernel üzerinde bir proccess olarak çalışır.
Virtual machine değildir çümkü kernel’i yoktur.
İçinde ubuntu, centos, redhat gibi işletim sistemlerinin tool ve utillerini barındırabilir ama kernelini
barındırmaz.


Kullanıcılar yarattıkları image’ları hub.docker.com’da repositoryleri üzerinde paylaşabilirler.
Eğer bu public bir repositoryde paylaşımışsa kullanıcalar dünyanın herhangi bir yerinden bu imagi
indirip kullanabilirler.
Bir diğer faydalı yani ise indirilen bu image’lar modify edeemezlerse de extend edilebilirler.
Official image’lar docker ekibi tarafından tasrlanmış ve bilgisayara zarar vermiyecek şekilde test
edilmişlerdir.


İndirdiğimiz ubuntu imaginin üstüne java ekleyip yeni bir image yaratabiliriz.


Container komutları :


docker container run [image-name] -> image’i container olarak çalıştırır
docker container run -p 80:8080 [image-name] ->imagi çalıştırır ve container’ın 8080 portunu
80 portuna yönlendirir(Portlar örnektir)

docker container run -d [image-name] -> image’ın arka planda çalışmasını sağlar, bu sayede
container ekrana bir çıktı vermez (detach modu)

docker container logs [containerId] -> Çalışan bir container’ın logunu gösterir.
(Deatach modda olsa bile) -> -f parametresi geçilirse loglar dinamik olarak güncellenir

docker container exec [containerId] [command] -> Container içerisinde bir komut çalıştırmaya
yarar.

docker container exec -it [containerId] bash -> Exec komutuna bir örnektir ve ubuntu container’ın
terminalini çalıştrırmaya yarar.

docker container ls -> Çalışan containerları listeler

docker container stop [containerId] -> Çalışan container’ı durdurur

docker container ls -a -> Çalışan çalışmayan tüm container’ları listeler

docker container prune -> Çalışmayan containerları hafızadan siler (imageları değil)

Eğer bir ubuntu container’a -it ile terminalini açıp jdk yüklersek ve stop edersek. Ve daha sonra da :

docker container commit -a “turgut bozkurt turgıtbozkurt@gmail.com
[containerId] myjdkimage ->
olarak kaydedersek localimizde bu image artık var olur.
Fakat bu yöntem çok kullanışlı ve yaygın bir yöntem değildir. Onun yerine dockerfile kullanarak bu
işlemi gerçekleştiririz.








-İlk satırda hangi image’ı extend ettiğimizi yazıyoruz.Aslında bu image’i alıyoruz ve yaratacağımız
image’a ekliyoruz.
-İkinci satır opsiyoneldir. BU image’i kim yaratıyor sorusuna cevap verir.
-Üçüncü satırda extend ettiğimiz image’ın bash shellinde execute ettiğimiz komut yer alır.
-Son satırdali CMD komutu ise bu container ayağa kalktığında otomatik olarak çalıştırılacak komutu
belirileriz.


DockerFile’i kullanmak için bulunduğu dizine gidilir ve :


docker image build -t [imageName] [dockerFilePlace] komutu çalıştırılır.(t  parametresi tag ,
anlamına gelir)
Ör: docker image build -t myDockerImage .
Tabi bu işlemde pratikde çok kullanılan bir image oluşturma şekli değildir. Esas amacımız genelde
image’a bir program yükleyip onu çalıştırmak şeklinde olur.


Burada ilk 3 step aynıdır.
-4.step’de bulunan container üzerindelki path’a gidilir.
-5.step’de bulunulan dizine dosya kopyalanır. (Burada comminity genel olarak COPY’i önerir ama
ADD daha fazla özelliğe sahiptir)
-6.step’de container ayağa kalktığında çalıştırılacak komut beirlenir. (Burada CMD’de kullanabilirdik.
Ama container ayağa kalkarken, container’i kullanan kişi CMD ile belirlenen komutu ezebilir.)


Örnek bir tomcat image’ı yukardaki gibidir. Eğer bu dosyaya EXPOSE 8080 verseydik, bu container
çalıştığında 8080 portundan kendisini yayınayacaktı. Ama zaten extend ettiğimiz tomcat imagi bu
özelliğe sahip. Bunu ezebilir veya hiç yazmayabiliriz.


Örnek bir tomcat java war web uygulaması. Ama bu iyi bir pratik değil. Çünkü spring boot
uygulamasıda zaten gömülü bir tomcat var ve jar ile çalıştırılabiliyor. Şimdi daha kolay deploy
yöntemi olan bu yöntemi inceleyelim.
Oluşturduğumuz bu yeni image’i docker hub’da yayınlamak veya saklamak isteyebiliriz. Yayınlamak
(aynı zamanda saklamak) için image’ımızı açtığımız hesaptaki public repository’e push edebiliriz.
Docker hub hesabı açtığımızda bir adet private repository’e de sahip oluruz. Birden fazla private
repository’e sahip olmak için para ödemek zorundayız.


Push komutu şu şekildedir :


İlk önce login olmalıyız.


docker login
Ardından credential bilgilerini gireriz.
...


Ardından tag ekleriz
docker tag [imageId] [userName]/[imageName]


Ardından push ederiz
docker image push [newImageName]


CONTAINER TO CONTAINER NETWORK CONNECTION


Docker container’da best practise ve bize normalde izin verilen bir CMD komutu ve bir servisin
çalıştırılmasıdır. Supervisor yöntemiyle (bkz : stackoverflow) birden fazla servis çalıştırılabilir ama bu iyi
bir yöntem değildir.


Misal container’ınızda bir spring boot uygulaması var ve mysql’e bağlanması gerekiyor. Bu durumda
spring boot uygulamanız ayrı bir servis ve mysql(mongodb, cassandra etc..) ayrı bir servis olmalıdır.


Eğer bir containerın içinde birden fazla büyük servis olsaydı bunları monitor etmek ve gerektiğinde
yeniden başlatmak zor olacaktı ve iyi bir pratik olmayacaktı.


Doğru yöntem yukardaki gibi farklı containerlarda bu servisi çalıştırmaktır.
Burada main server dışından container’daki mysql server’a dışarıdan erişim açılmadıkca privae’dır ve
direkt olamaz. Fakat diğer container’la network bağlantısı çok kolaydır.


Burada dikkat edilmesi gereken nokta spring boot uygulamasındaki mysql driver ile diğer containerdaki
mysql servisinin mysql versiyonları aynı olmalıdır.


İki container arasında network bağlantısı kurmak için, bir bridge network oluşturmalıyız.


docker network ls-> ile networkleri listeleyebiliriz. Listedeki bridge network containerları dışa açan
kapıdır.


Biz de docker network create my-network diyerek bir bridge network yaratıp containerları bu network’e
dahil edebiliriz.


Containerları ayağa kadırırken network ve name parametreleri geçebiliriz.


docker container run --network my-network --name database …. mysql:5


docker container run -d -p 80:8080 --network my-network --name fleetman-webapp fleetman-webapp


Artık iki container birbirine isimleriyle ping atabilir hale geldi. Spring boot uyguamasının içindeki databe
property’si şu şekilde olmalı:


HINT : bir container’ı stop etseniz bile aynı isimde başka bir container ayağa kaldırmayıyoruz. Bunun
için önce container’ı remove etmemiz gerekiyor. Bunun için container’ı --rm ile başlatırsak stop
ettiğimizde otomatik olarak remove olacaktır.


Yukarıda ise java webapp iki networle bağlı. Ama mysql ve apachemq farklı networklerde ve
birbirlerini görmüyorlar.


Volumes and Mounts
Bu zamana kadar docker’da bir işlem yapıp, gerektiğinde data kaydedikten sonra container’ı remove
edince tüm datanın ve işlemlerin dispose olduğunu görümüştük. Bu aslında istediğinmiz bir durumdu.
Ama bazen yaptığımız işlemlerden sonra datanın kalıcı olmasını isteriz. Buna klasik bir örnek container
içerisinde bir database çalıştırırmamızdır.


Eğer docker hub’da publish edilmiş official mysql image’ına bakarsanız VOUME diye bir satır
görürsünüz.




Burada VOLUME ile belirlenmiş path’de container’ın persist etmek istediği data host bilgisaarda
/some/somePAth’de kalıcı olarak kaydedilir. Bir sonra çalıştırıan yine yeni mysql container’de yine
VOLUME ile belirlenmiş path’deki data /other/someOtherPath’de kalıcı olarak kaydedilir.




,Eğer docker container inspect [containerId] komutunu çalıştırısak, conmtainer ile ilgili uzun bir
json sonucu alırız.
Burada “Mounts” propertysine bakıcak olursak :




Burada source sizin host bilgisayarınızdaki path’i gösterirken, Destination container içerisindeki path’i
gösterir. Eğer linux sistem üzerinde docker’ı çalıştırıyorsanız bu path’e direkt gidebilirsiniz. eğer mac
veya windows gibi virtual sistem üzerinde docker’ı çalıştırıyorsanız bu virtual sistemin kullandığı
path’dir.


Ayrıca:
docker volume ls yaparak’da bu volume’leri görebilirsiniz.


Eğer;
docker volume prune yaparsak durdurulmuş conatiner’ların volumelerini silebilirz.


Volume açısından bu anlattıklarımız çok iyi bir yaklaşım değildir. Bu yaklaşım yerine volume’e bir isim
vermek çok daha etkili bir yaklaşımdır.


Eğer container’ımızı -v parametresi ile bir isimlendirme yaparsak






Bu şekilde containerımızı durdurup çalıştırdıktan sonra yanı parametrey da bu pathe’e yönlendirebiliriz.


Inspect yaparsak:




Volume’e isim vermek yerine mount edilecek path’in yolunu da verebiliriz.
Aşağıdaki Windows için bir örnektir:


Sağ taraf mount edilen container’daki path’ken sol taraf host bilgisayırımızdaki mountpointdir.


Maven


Fabric8 plugin ile image oluşturma işimizi otomatikleştirebiliriz. İlk önce pom’a plugini ekliyoruz.




Burada pom.xml’de username ve password’u external alıyor olacağız.
dockerfileDir’ı da main klasörünün altında bir docker klasörü oluşturup Dockerfile’ı buraya koyacağız.
Base dır’a koyarsak herşeyi zipleyip network yoluyla docker’a göndermeye çalışıyoruz bunu engelleyip
sadece bir klasörü göndermesin


Image’ı build etmek için

şeklinde değiştirip (target altında maven klasörü açıyor) aşagıdaki maven komutunu


çalıştırıyoruz


Her defasında docker:build çalıştırmak yerine


yapıp package phase’ine build goalını eklemiş oluyoruz.


Docker Hub username vapassword’u clean olsun diye maven’ın settings.xml dosyasına koyarız.




build ederken tag ile versiyonlama yapabiliyoruz




Daha sonra mvn ile push ediyoruz



DOCKER COMPOSE


Geliştirme yaparken containerları ayağa kaldırırken birçok ayarlama yapıp parametre geçiyoruz.
Bunu her defasında yaptığımızda sıkıcı bir işlem olmaya başlıyor. Docker compose ile bu ayarları bir
dosyaya yazıp otomatikleşitirebiliriz.


Bilgisayarınızda docker compose olup olmadığını docker-compose -v yazarak anlayabiliriz.




fleetman-webapp ve database --name ile geçtiğimiz name’leri simgeler.
herbir servis için çalıştırılacak imagelar, bağlı olduğu networ listesi ve bağlandığı port belirlenir.
Eğer bir enviornment listesi geçilecekse geçilir.
networks: kısmında ise network ismi yazılır ve eğer o network yoksa otomatik olarak yaratılır.
Burada depends_on servisin diğer servisin önce çalışmasına bağlı olduğunu gösterir. Diğer servis
çalışması garanti altına alınır ama sağlıklı çalışıp çalışmadığı garanti altına alınamaz. Bu yüzeden
production ortamında kubernates kullanılır. Docker compose bu konuda yetersizdir ve dev ve test için
daha yaygın olarak kullanılır.
Burada docker-compose.yaml dosyasını projenin kök dizinine verdik.(Opsiyoneldir)
Bu dizine gelip docker-compose up dediğimizde, -d parametresi eklersek detach modda çalışır ve
ctrl+c dediğimizde containerlrımız durmamış olurlar.
docker-compose logs -f [serviceName] deyip anlık logları takip edebilirz.
docker-compose down dersek servisler stop ve aynı zamanda remove olurlar.

0 yorum: