[tips] Phân lớp (layered) khi đóng gói ứng dụng bằng Dockerfile

[tips] Phân lớp (layered) khi đóng gói ứng dụng bằng Dockerfile

Khi ứng dụng của chúng ta được yêu cầu đóng gói và triển khai trên môi trường containers, chúng ta cần xây tạo một file Dockerfile, vậy tạo như thế nào để được tối ưu hơn.

containers mình dùng thuật ngữ này cũng chưa hoàn toàn chính xác, nhưng muốn miêu tả ứng dụng đó có thể chạy trên các môi trường hỗ trợ có hỗ trợ container như Docker hoặc Kubernetes.

Giới thiệu qua về quy trình build và chạy ứng dụng thông qua Dockerfile

Khi thực hiện lệnh docker build container engine (CE) sẽ tìm đến file cấu hình, thường đặt là Dockerfile, dựa trên các thông tin được khai báo CE sẽ tiến hành tạo image, image này đực quản lý bởi CE và có thể chạy luôn tại container bên trong CE. Nếu ta muốn đẩy lên một nơi lưu trữ trung tâm registry/hub ta sẽ đánh tag và dùng docker push (với các registry khác ta dùng cách riêng của mỗi registry). Sau khi image được đẩy lên registry/hub nó sẽ được dùng tại các CE khác

Cách tạo Dockerfile

Ta xem nội dung của 2 file Dockerfile mà mình copy từ một số dự án (được chia sẻ)

# Dockerfile 1

FROM openjdk:17

ARG JAR_FILE=build/libs/*.jar

COPY ${JAR_FILE} spettrum_backend.jar

#COPY build/libs/*.jar app.jar

COPY /src/main/resources/*.json /src/main/resources/

COPY /src/main/resources/application.yml /src/main/resources/

ENTRYPOINT ["java", "-jar", "spettrum_backend.jar"]

Dockerfile 2 có phân lớp

# Dockerfile 2
FROM eclipse-temurin:21-jre AS builder
WORKDIR /extracted
ADD ./build/libs/*.jar app.jar
RUN java -Djarmode=layertools -jar app.jar extract

FROM eclipse-temurin:21-jre
WORKDIR /application
COPY --from=builder /extracted/dependencies/ ./
COPY --from=builder /extracted/spring-boot-loader/ ./
COPY --from=builder /extracted/snapshot-dependencies/ ./
COPY --from=builder /extracted/application/ ./

EXPOSE 8080

ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]

Ta thấy trong Dockerfile 1 đơn giản là copy file .jar đã được build cho vào và tạo thành một Image, nhưng với Dockerfile 2 thực hiện có thay đổi, và điều này làm cho việc sử dụng Dockerfile hiệu quả hơn. Nó đã làm những gì?

  • giải nén jar file (file được đóng gói từ việc thực hiện build app)
  • đóng gói thành các phần
    • dependencies chứa thư viện của bên thứ 3 mà ta dùng trong dự án
    • spring-boot-loader chứa thư viện cần thiết khởi chạy Spring Boot
    • snapshot-dependencies chứa các thư viện mang hậu tố SNAPSHOT
    • application chứa các code của ứng dụng

Các CE hỗ trợ cached tại mỗi lớp (layered) do vậy khi ta thay đổi code và cập nhật, CE chỉ cập nhật những phần được thay đổi, so với cập nhật toàn bộ jar file, lượng dữ liệu trao đổi khi pull/push image đã giảm đi đáng kể.

Đây là cách khuyến nghị trong các dự án triển khai Dockerfile

Một lưu ý khi sử dụng thư viện JDK nếu không có gì đặc biệt caafnn sử dụng toàn bộ JDK như Dockerfile 1 ta có thể lưu ý đến việc sử dụng thư viện eclipse-temurin đây là thư viện được tối ưu với các ứng dụng Spring Boot, giúp cho việc chạy ứng dụng dễ dàng hơn.

Về vấn đề load thư viện, như mọi người biết đến Graalvm là thư viện cho Java, trong Spring Boot 3.0 nó hỗ trợ việc tạo ra các navive image, với thư viện được tối ưu rất nhiều, dẫn tới khởi chạy ứng dụng Spring rất nhanh, mình sẽ trình bày trong một bài khác về GraalVM

[tips] là tag cho những bài viết ngắn, phần này mình chia sẻ nhưng tip hay trong lập trình, nội dung của những bài này thường ngắn và thiên về thực hành

Written by :

user

Java Developer, System Architect, Learner and becoming Youtuber

View All Posts

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *