my space

Spring Boot with Docker

dockerspring-boot

June 17, 2020

บันทึกการสร้าง container ให้กับ spring boot microservice เริ่มต้นด้วยแนวคิดว่าเราต้องการให้ Docker จัดการทุกอย่างตั้งแต่ build jar file ไปจนถึง start spring boot ขึ้นมาเลย สุดท้ายเลยได้ dockerfile ประมาณนี้ออกมา

# Build Stage for Spring boot application image
FROM openjdk:8-alpine3.8 as build

WORKDIR /app

COPY mvnw .
COPY .mvn .mvn
COPY pom.xml .

RUN chmod +x ./mvnw
# download the dependency if needed or if the pom file is changed
RUN ./mvnw dependency:go-offline -B

COPY src src

RUN ./mvnw package -DskipTests
RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar)

# Production Stage for Spring boot application image
FROM openjdk:8-alpine3.8 as production
ARG DEPENDENCY=/app/target/dependency

# Copy the dependency application file from build stage artifact
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app

EXPOSE 8080

# Run the Spring boot application
ENTRYPOINT ["java", "-cp", "app:app/lib/*","com.bluesharp.mpayapigateway.MpayApiGatewayApplication"]

ซึ่งก็พอจะใช้งานได้ดี แต่ปัญหาที่เจออย่างแรกเลยคือการ build ครั้งแรกจะนานมาก ในขั้นตอน

# download the dependency if needed or if the pom file is changed
RUN ./mvnw dependency:go-offline -B

ซึ่งหลังจากมี cache ไว้แล้วคราวต่อๆไปก็จะใช้จาก cache ได้ แต่เมื่อไหร่ก็ตามที่แก้ pom.xml ก็ไม่วายรอ download maven dependency อีกสักพักใหญ่ๆเลย

มี cache ยังพอไหว

แต่พอมีหลาย project เข้า และการ build จาก Dockerfile ข้างบนนั้นเป็น multi stage build ซึ่งจะมีการสร้าง intermediate container ออกมา ถ้าเมื่อไหร่ไปลบ docker image prune มันเมื่อไหร่ คราวต่อไปก็ตอน build image ก็ต้องโดนความช้าของการ download maven dependency อยู่ดี แล้วถ้าทำ microservice หลายสิบ(หรือร้อย)ตัวนี้ไม่ต้องพูดถึง นานมากๆ

ก็เลยย้อนกลับมาที่ basic กว่าเดิม คือถ้าขั้นตอนที่ช้ามันช้าตอน maven download dependency แล้วถ้าเราโยน dependency ในเครื่องเข้าไปให้ docker เลยละ ก็อาจจะได้ แต่ก็นึกต่อไปอีกว่า อ่าวแล้วถ้ามัน build บน server ละ จะเอา dependency จากไหน ก็ไม่มีอีก ก็ต้องโหลดอีก ก็เลยย้อนกลับมาที่จุดก่อนหน้า งั้น build จากเครื่องเราไปเลยละกัน ให้ docker แค่ copy jar file เข้าไปใช้งาน ถ้าใช้ท่านี้ก็ต้องเตรียม build server ให้มี maven (และให้มัน cache ในตัวเองให้เรียบร้อยซะ) สุดท้ายเลยได้ dockerfile แบบนี้

FROM openjdk:8-alpine3.8

RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring

EXPOSE 8080

ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

และเขียน shell script สำหรับ build spring boot

mvn -f ../sample1/pom.xml package -DskipTests
mvn -f ../sample2/pom.xml package -DskipTests

เอาอย่างนี้ไปก่อนละกัน…


gie

Written by gie who lives and works in Bangkok. Build things by code.
my twitter | github