Dockerize Spring Boot Microservice Project

Eren Cihan
4 min readMar 12, 2024

--

Herkese selam bu yazıda docker ve docker-compose kullanarak birden fazla mikroservice uygulamamızı tek bir docker-compose dosyası içerisinde nasıl ayağa kaldıracağımız hakkında konuşacağız.

Öncelikle bunları yapmadan önce docker nedir sorusu ile başlayalım;
Docker hızla popülerlik kazanan bir container platformudur. Docker bizlere uygulamaları bağımsız olarak çalıştırabilme ve dağıtma özelliği sunar. Bu sayede kendi local’imizden bağımsız bir uygulamayı çalıştırabilme şansı tanır. Bu da bize yazılımı geliştirme kısmında daha büyük bir kolaylık sağlar. Sonuç olarak bu da bize geliştiricilerin, uygulamalarını hızla geliştirip dağıtmalarını ve işletmelerin rekabet avantajını artırmalarını sağlar.

Uygulamaları Dockerize Etme

docker-compose dosyamızı oluşturmadan önce yazdığımız uygulamaları dockerize etmemiz gerekiyor bu sayede oluşturduğumuz dokcer-compose dosyası içerisine birer service olarak eklememizi sağlayacak ve compose dosyasını çalıştırdığımız zaman hepsi birden ayağa kalkmış olacak. Bunun için ise ilk yapmamız gereken projenin içerisinde bir “Dockerfile” dosyası oluşturmak olacak.

“Dockerfile” Dosyamızın Oluşturulması

FROM maven:3.8.4-openjdk-17-slim AS build
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN mvn clean install -DskjavaipTests

FROM openjdk:17 AS runtime
WORKDIR /app
COPY --from=build /app/target/productQueryService-0.0.1-SNAPSHOT.jar .
CMD ["java", "-jar", "productQueryService-0.0.1-SNAPSHOT.jar"]

burada ilk aşamada kullandığımız “build” kısmında bir meaven imajı kullanılır.
sonraki aşamada ise uygulamanın çalışma dizini /app olarak ayarlanır.
“copy” aşamalarında ise pom.xml dosyası ve src dizini docker container’ına kopyalanır.
sonrasında ise “mvn clean install -DskipTests” kullanılarak uygulamanın derlenmesi ve paketlenmesi gerçekleştirilir. Bir sonraki kısımda ise runtime kısmı için jdk’nın sürümü belirlenir ve “runtime” adındaki aşama tanımlanır.
“build” kısmında olduğu gibi çalışma dizini /app olarak belirlenir
— from=build kısmında “build” aşamasında oluşturulan .jar dosyası runtime aşamasına kopyalanır.
son adımda ise bir cmd komutu ile JAR dosyası çalıştırılır.
şimdi ise en önemli kısımlardan birine geldik hazırladığımız bu Dockerfile dosyasının bir image’inin oluşturulması.
bunu ise terminalde “docker build -t productqueryservice . “ komutunu çalıştırarak yapıyoruz. burada -t’den sonraki kısım bizim kendi image’imize verdiğimiz isim, kendi projenize göre düzenleyebilirsiniz. bu çalıştırdığımız komut bizim uygulamamızın bir image’ini oluşturmamızı sağlıyor ve bu sayede ise hazırlayacağımız docker-compose dosyasının içerisine bu image’i ekleyebileceğiz, burada yapılan Dockerfile dosyası meaven tabanlı spring projeleri için oldukça kullanışlıdır. Sizde bu Dockerfile dosyasını kendi projenize göre düzenleyerek kullanabilirsiniz.

şimdi ise oluşturduğumuz uygyulamaların image’leri ve uygulamalarımızın içerisinde kullandığımız diğer image’leri ekleyeceğimiz docker-compose dosyasını oluşturalım

“docker-compose” Nedir ?

Birden fazla docker container’ını yönetmek ve bunların hepsini bir araya getirerek bir uygulamayı oluşturmak bazen zor olabiliyor bu noktada bizim işimizi kolaylaştıracak şey ise docker compose oluyor. Docker compose bizim container’larımızı yönetmek ve dağıtmak için kullandığımız bir araçtır. bunu ise YAML dosyaları aracılığı ile yapmamızı sağlar. Peki neden Docker compose? çünkü YAML dosyası aracılığıyla Docker konteynerlerini tanımlamak oldukça kolaydır. İhtiyacımız olan her bir service’in özelliklerini bağımlılıklarını ve geri kalan bir çok özelliğini kolayca ayarlayabiliriz ve ayarladığımız bu bütün dosyayı tek bir “docker compose up” komutu ile çalıştırabilir ve bütün container’larımızı başlatabiliriz. En önemli özelliklerinden biri ise oluşturduğumuz service’lerin birbiri arasındaki bağımlılıklarını ve iletişimini kolay bir şekilde yönetebiliriz.

“docker-compose” Oluşturma

şimdi bir docker compose nasıl oluşturulur onu öğrenelim. İlk yapmamız gereken projemizde bir “docker-compose.yml” dosyası oluşturmak bu dosyanın bir YAML dosyası olmasına dikkat edelim. oluşturduğumuz bu dosyanın içerisine önce uygulamalarımız da kullandığımız diğer container’ları ekleyelim. Bunlar message brokerlar olabilir veritabanları olabilir veya uygulamalarınıza hizmet eden farklı container olabilir. Ben kendi service’lerimin dışında service’lerim için POSTGRES, MİNİO, ZOOKEEPER, KAFKA, ELASTİCSEARCH container’larını ekleyeceğim bu şekilde;

version: '3.8'
services:
db:
image: postgres
container_name: postgress
environment:
POSTGRES_DB: productservice
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
ports:
- "5432:5432"
volumes:
- ./postgres-data:/var/lib/postgresql/data


minio:
image: minio/minio
container_name: minioZ
restart: always
command: server --console-address ":9001" /data
ports:
- "9000:9000"
- "9001:9001"
environment:
MINIO_ACCESS_KEY: your_access_key
MINIO_SECRET_KEY: your_secret_key
volumes:
- ./minio-data:/data


zookeeper:
image: confluentinc/cp-zookeeper:latest
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
ports:
- 22181:2181


kafka:
image: confluentinc/cp-kafka:latest
depends_on:
- zookeeper
ports:
- 29092:29092
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1


elasticsearch:
image: elasticsearch:8.8.0
environment:
- discovery.type=single-node
- validate_after_inactivity=0
- max_open_files=65536
- max_content_length_in_bytes=100000000
- transport.host=elasticsearch
- xpack.security.enabled=false
volumes:
- $HOME/app:/var/app
ports:
- "9200:9200"
- "9300:9300"

sonrasında ise yukarıda bahsettiğim gibi image’lerini oluşturduğum ve dockerize ettiğim service’lerimi ekleyeceğim. Onlar ise compose dosyama bu şekilde dahil olacak;

productservice:
container_name: productservice
image: productservice
ports:
- "8084:8084"
depends_on:
- db
- minio
- zookeeper
- kafka
environment:
- spring.datasource.url=jdbc:postgresql://db/productservice?useSSL=false&createDatabaseIfNotExist=true
- minio.url=http://minio:9000
- kafka.url=http://kafka:29092


cartapi:
container_name: cartapi
image: cartapi
ports:
- "8086:8086"
depends_on:
- db
- kafka
environment:
- spring.datasource.url=jdbc:postgresql://db/cartapi?useSSL=false&createDatabaseIfNotExist=true



productqueryservice:
container_name: productqueryservice
image: productqueryservice
ports:
- "8085:8085"
depends_on:
- elasticsearch
- kafka
environment:
- elasticsearch.host=elasticsearch
- elasticsearch.port=9200
- kafka.url=http://kafka:29092
restart: always



authservice:
container_name: authservice
image: authservice
ports:
- "8083:8083"
depends_on:
- db
environment:
- spring.datasource.url=jdbc:postgresql://db/authservice?useSSL=false&createDatabaseIfNotExist=true

networks:
my-network:

artık compose dosyamız hazır. öncelikle compose dosyasının formatını daha detaylı inceleyebilmeniz için yazımın sonuna ulaşabileceğiniz reponun linkini bırakacağım. çünkü compose dosyasını hazırlarken doğru formatta yazmaya dikkat etmemiz gerekiyor aksi taktirde dosyamızı build edemeyeceğiz. şimdi gelin burada ki bazı bir kaç önemli yerlere bakalım

“version” = gördüğünüz gibi ilk başta version kelimesi ile başlıyoruz. Bu kelime bize Docker Compose dosyamızın versiyonunu belirtir.

“service” = sonrasında ise tanımladığımız bütün container’lar service kelimesinin altında tanımlanır. çünkü her servis, Docker konteynerini oluşturmak için gerekli parametrelerle birlikte burada tanımlanır.

“image” = belirttiğimiz service’lerin içerisindeki image kısmında ise image’lerin ismi belirtilir.

“container_name” = bu kısımda ise oluşturulan docker container’larının adını belirtiriz.

“ports” = ports kısmında ise tahmin edeceğiniz üzere kullanılacak portlar belirtilir. Burada ilk yazılan port Docker main bilgisayarında kullanılabilirken ikinci yazılan port ise docker container’ında kullanılır.

“depends_on” = Servisin başlaması için bağımlı olduğu diğer servisleri belirtir. Bu, bir servisin başlamadan önce belirli bir sıraya göre diğer servislerin başlamasını sağlar.

“environment” = Bu ise docker conteiner’ında kullanılacak ortam değişkenlerini belirler. örneğin kullanıclacak veri tabanına bir bağlantı oluşturabilmek için gerekli kullanıcı adı ve şifrenin verilmesi gibi.

“networks” = Container’ların oluşturulacağı ağları belirlemek için kullanılır. container’lar arasındaki iletişimi sağlamak için kullanılır. Burada yazılan compose dosyasında ise oluşturulan container’larda bir network belirtilmediği için default network olan Bridge Network’ de oluşturacaktır.

ilgili projenin reposunu incelemek için;

https://github.com/AErencihan/compose

Buraya kadar gelip yazımı okuduğunuz için teşekkürler.

--

--