Spring Boot And Docker-5 Containerizing Spring Boot MYSQL Application
Başlangıç
Merhabalar bu yazımızda Spring Boot ve MySQL veri tabanı kullanarak geliştirdiğimiz bir uygulamayı nasıl Container içerisine alıp çalıştırabileceğimizi öğreneceğiz. Yapacağımız işlemleri kuş bakışı senarize edecek olursak ilk olarak MySQL Image'den Container oluşturuyoruz. Daha sonra Spring Boot uygulamamızı Containerize ediyoruz. Tabii ki Spring Boot Container' ımız MySQL Container'ımız ile entegre ediliyor. Şimdi gelin bu adımları hep beraber yapalım.
MySQL Container Oluşturma
İlk olarak docker run mysql:5.7
komutunu terminale yazıp çalıştırdığımızda neler oluyor bir bakalım.Bu komut lokalde MySQL Image'ini arar ve çalıştırır eğer bulamazsa Docker Hub dan önce MySQL Image'ini çeker ve çalıştırır.Bu komut şöyle bir error üretir.
2020-03-22 19:34:13+00:00 [ERROR] [Entrypoint]: Database is uninitialized and password option is not specified
You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD
Bu hata veri tabanı için Root parolası tanımlamamızı söylüyor bunu şu şekilde yapacağız.
docker run -d -e MYSQL_ROOT_PASSWORD=dummyrootpw -e MYSQL_DATABASE=students -e MYSQL_PASSWORD=dummyuserpw -e MYSQL_USER=dummyuser -p 3306:3306 --name mysql mysql:5.7
Evet bu komutu hatasız girdiğimizde oluşan Containe'ın id si ekrana basılır. Aynı zamanda container ls
komutu ile Container'ımızın çalışıp çalışmadığını kontrol edebiliriz.
Evet şu anda çalışan bir MySQL veri tabanına sahibiz bu veritabanına ister lokalde herhangi bir uygulamamızı isterse Container içerisinde herhangi bir uygulamayı bağlayabiliriz. Biz containerize edeceğimiz bir Spring Boot uygulamasını bağlayacağız.
Spring Boot Container Oluşturma
MySQL Container oluştururken environment olarak ayarladığımız MYSQL_DATABASE
, MYSQL_USER
ve MYSQL_PASSWORD
değerlerini Spring uygulamamız içerisindeki application.properties
dosyası içerisine aşağıdaki gibi yazmamız gerekiyor.
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://${RDS_HOSTNAME:localhost}:${RDS_PORT:3306}/${RDS_DB_NAME:students}
spring.datasource.username=${RDS_USERNAME:dummyuser}
spring.datasource.password=${RDS_PASSWORD:dummyuserpw}
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
Uygulamamız içerisinde veri tabanına bağlanmak için gerekli ayarlamaları yaptıktan sonra uygulamamızı Container olarak ayağa kaldırabiliriz.Bunun için daha önceki yazılarda bahsettiğimiz Spotify Dockerfile Plugin
kullanacağız.
Dockerfile içeriğimiz aşağıdaki gibidir.
FROM tomcat:8.0.51-jre8-alpine
RUN rm -rf /usr/local/tomcat/webapps/*
COPY ./target/*.war /usr/local/tomcat/webapps/ROOT.war
CMD ["catalina.sh","run"]
mvn clean package -DskipTests
komutunu çalıştırdığımızda uygulama klasörü altında ki target dizini altına .war arşivimiz oluşur ve Image içerisine kopyalanır.
Evet Spring Boot uygulamamızı içeren Image'imiz hazır aynı zamanda MySQL Container'ımızda çalışır durumda geriye ikisi arasındaki bağlantıyı sağlamak kaldı.Bunun için uygulama Image'ımızı aşağıdaki şekilde run etmemiz gerekir.
Spring Boot Container İle MySQL Container'i Bağlama
docker container run -p 8080:8080 --link=mysql -e RDS_HOSTNAME=mysql spring-mysql-app:1. 0.0-SNAPSHOT
Yukarıdaki komutta --link mysql
parametresi ile spring uygulamamızı mysql ile bağlıyoruz. --link
bağlayacağımız Container'ın adını parametre alır. Fakat --link
deprecated
bir parametredir. Bunun yerine Docker network yapılarını kullanacağız. Şimdilik --link ile yapalım.
-e RDS_HOSTNAME=mysql
komutu da ağ üzerindeki mysql veritabanına bağlanmak için gereklidir.
Docker Networking
Evet buraya kadar işin büyük bir kısmını hallettik.Uygulama Container'ı ile MySQL Container'ı bağlamak için --link=mysql
yapısını kullandık fakat --link Docker tarafından kullanımdan kaldırıldı.Bunun yerine Docker Network kavramını kullanacağız.
Container'ler birbirleri ve dış dünya ile haberleşmek için farklı türlerde ağlar kullanırlar.Docker kurduğumuzda default olarak üç network tanımlıdır bunları görmek için
docker network ls
komutunu çalıştırırız.
- host
- bridge
- none
docker inspect bridge
docker inspect host
komutları ile ilgili network üzerinde hangi Container'ler çalışıyor görebiliriz.Default olarak Container'ler bridge
networkünü kullanırlar. Bizim Spring Boot uygulamamızda MySQL ile bridge
networku üzerinden haberleşmektedir.
Not: host
networku yalnızca linux sistemlerde vardır.
Herhangi bir Image'i bir network üzerinde çalıştırmak için şu şekilde bir komut yazarız.
docker run --network=host imageNanme
Evet bu bilgiler ışığında uygulamamıza dönecek olursak eğer host networkunu kullanırsak uygulamamız herhangi bir ek tanımlamaya gerek duymadan mysql ile haberleşir şöyle ki
docker container run -p 8080:8080 --network=host spring-mysql-app:0.0.1-SNAPSHOT
Bu komuta bakacak olursak port bilgisi ve rds_host bilgisi verilmedi. Çünkü her iki Container'da host networku içerisindedir.
Özel Network Oluşturma
Eğer kendimize özel bir ağ oluşturup Container'larımızı bu ağ üzerinde haberleştirmek istiyorsak şöyle yaparız.
docker network create web-mysql-network
Bu konutu girdiğimizde web-mysql-network isminde bir network oluşur. Kontrol amacıyla docker network ls
komutunu kullanırsak web-mysql-network
isminde ve bridge
türünde bir ağın oluştuğunu görürüz.
Sonuç olarak her iki Container'ımızı bu ağ üzerinde çalıştırırsak birbirleri ile haberleşirler. Custom network olursa iki Container'ı birbirine bağlamaya gerek yoktur.
MySQL Container'ını özel ağımızda çalıştırmak için aşağıdaki komutu kullanırız.
docker run -d -e MYSQL_ROOT_PASSWORD=dummyrootpw -e MYSQL_DATABASE=students -e MYSQL_PASSWORD=dummyuserpw -e MYSQL_USER=dummyuser -p 3306:3306 --network=web-mysql-network --name mysql mysql:5.7
Spring Boot uygulama Container'ını çalıştırmak için ise
docker container run -p 8080:8080 --network=web-mysql-network -e RDS_HOSTNAME=mysql spring-mysql-app:0.0.1-SNAPSHOT
evet Container'larımız başarılı bir şekilde ayağa kalktı ve birbirleriyle iletişim halindeler.
docker inspect web-mysql-network
komutunu çalıştırısak oluşan çıktıda Containers bölümünde uygulama ve mysql Container'lerimizi görürüz.
Veri Kalıcılığını Sağlama-Docker Volumes
MySQL Container'ımız çalıştı ve uygulamamıza veri girmeye başladık diyelim eğer bu verileri Docker Volume
kullanarak kalıcı hale getirmezsek Container'lar durduktan sonra veriler silinir.
Docker Container'ları yapıları itibari ile üzerinde çalıştıkları makiden bağımsız bir şekilde çalışırlar ve herhangi bir durdurulma senaryosunda sıfırdan başlarlar fakat birçok uygulama bu duruma uygun değildir mesela bizim MySQL Container'ımız uygulama verilerini saklamakla görevlidir yani bu Container dursa bile tekrar başladığında verilerimizin kaybolmaması gerekir. Bunu sağlamak için Container içerisindeki verilerin tutulduğu dizini host makine üzerindeki bir dizinle eşleştiriyoruz bu şekilde Container fdursa bile yeni bir Container başlattığımızda host üzerindeki bu dizini volume olarak parametre alırsa veriler kaybolmadan başlamış olur.
--volume data-directory-in-host-machine:/var/lib/mysql/
Container'ımızı ilk defa başlattığımızda bu ayarlamayı yaparsak verilerimiz host üzerinde ilgili klasöre yedeklenmiş olur.