Làm thế nào để dockerize maven dự án? và có bao nhiêu cách để hoàn thành nó?


87

Tôi mới làm quen với Docker, và không biết làm thế nào để chạy một dự án java với maven mặc dù tôi đã đọc nhiều tài liệu và thử nhiều phương pháp.

  1. Tôi có nên xây dựng hình ảnh bằng cách sử dụng Dockerfile?
  2. Các lệnh như thế nào khi chạy dự án maven trong máy chủ lưu trữ với Dockerfile?

Câu trả lời:


123

Ví dụ làm việc.

Đây không phải là một hướng dẫn khởi động mùa xuân. Đó là câu trả lời cập nhật cho câu hỏi về cách chạy bản dựng Maven trong vùng chứa Docker.

Câu hỏi ban đầu được đăng 4 năm trước.

1. Tạo một ứng dụng

Sử dụng trình khởi tạo mùa xuân để tạo ứng dụng demo

https://start.spring.io/

nhập mô tả hình ảnh ở đây

Giải nén cục bộ lưu trữ zip

2. Tạo Dockerfile

#
# Build stage
#
FROM maven:3.6.0-jdk-11-slim AS build
COPY src /home/app/src
COPY pom.xml /home/app
RUN mvn -f /home/app/pom.xml clean package

#
# Package stage
#
FROM openjdk:11-jre-slim
COPY --from=build /home/app/target/demo-0.0.1-SNAPSHOT.jar /usr/local/lib/demo.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/usr/local/lib/demo.jar"]

Ghi chú

  • Ví dụ này sử dụng một bản dựng nhiều giai đoạn . Giai đoạn đầu tiên được sử dụng để xây dựng mã. Giai đoạn thứ hai chỉ chứa jar được xây dựng và một JRE để chạy nó (lưu ý cách jar được sao chép giữa các giai đoạn).

3. Xây dựng hình ảnh

docker build -t demo .

4. Chạy hình ảnh

$ docker run --rm -it demo:latest

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.3.RELEASE)

2019-02-22 17:18:57.835  INFO 1 --- [           main] com.example.demo.DemoApplication         : Starting DemoApplication v0.0.1-SNAPSHOT on f4e67677c9a9 with PID 1 (/usr/local/bin/demo.jar started by root in /)
2019-02-22 17:18:57.837  INFO 1 --- [           main] com.example.demo.DemoApplication         : No active profile set, falling back to default profiles: default
2019-02-22 17:18:58.294  INFO 1 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 0.711 seconds (JVM running for 1.035)

Misc

Đọc tài liệu về trung tâm Docker về cách tối ưu hóa bản dựng Maven để sử dụng kho lưu trữ cục bộ để lưu trữ các lọ trong bộ nhớ cache.

Cập nhật (2019-02-07)

Câu hỏi này hiện đã được 4 năm và trong thời gian đó, công bằng mà nói việc xây dựng ứng dụng bằng Docker đã trải qua một sự thay đổi đáng kể.

Tùy chọn 1: Xây dựng nhiều giai đoạn

Phong cách mới này cho phép bạn tạo nhiều hình ảnh nhẹ hơn mà không gói gọn các công cụ xây dựng và mã nguồn của bạn.

Ví dụ ở đây một lần nữa sử dụng hình ảnh cơ sở chính thức của maven để chạy giai đoạn đầu của quá trình xây dựng bằng cách sử dụng phiên bản Maven mong muốn. Phần thứ hai của tệp xác định cách lắp ráp jar đã xây dựng vào hình ảnh đầu ra cuối cùng.

FROM maven:3.5-jdk-8 AS build  
COPY src /usr/src/app/src  
COPY pom.xml /usr/src/app  
RUN mvn -f /usr/src/app/pom.xml clean package

FROM gcr.io/distroless/java  
COPY --from=build /usr/src/app/target/helloworld-1.0.0-SNAPSHOT.jar /usr/app/helloworld-1.0.0-SNAPSHOT.jar  
EXPOSE 8080  
ENTRYPOINT ["java","-jar","/usr/app/helloworld-1.0.0-SNAPSHOT.jar"]  

Ghi chú:

  • Tôi đang sử dụng hình ảnh cơ sở không kiểm soát của Google , cố gắng cung cấp vừa đủ thời gian chạy cho một ứng dụng java.

Tùy chọn 2: Jib

Tôi chưa sử dụng phương pháp này nhưng có vẻ đáng để điều tra vì nó cho phép bạn xây dựng hình ảnh mà không cần phải tạo ra những thứ khó chịu như Dockerfiles :-)

https://github.com/GoogleContainerTools/jib

Dự án có một plugin Maven tích hợp việc đóng gói mã của bạn trực tiếp vào quy trình làm việc Maven của bạn.


Câu trả lời gốc (Được bao gồm để hoàn thiện, nhưng được viết từ nhiều năm trước)

Hãy thử sử dụng các hình ảnh chính thức mới, có một hình ảnh dành cho Maven

https://registry.hub.docker.com/_/maven/

Hình ảnh có thể được sử dụng để chạy Maven tại thời điểm xây dựng để tạo ứng dụng đã biên dịch hoặc, như trong các ví dụ sau, để chạy bản dựng Maven trong một vùng chứa.

Ví dụ 1 - Maven chạy trong vùng chứa

Lệnh sau chạy bản dựng Maven của bạn bên trong vùng chứa:

docker run -it --rm \
       -v "$(pwd)":/opt/maven \
       -w /opt/maven \
       maven:3.2-jdk-7 \
       mvn clean install

Ghi chú:

  • Điều thú vị về cách tiếp cận này là tất cả phần mềm được cài đặt và chạy trong vùng chứa. Chỉ cần docker trên máy chủ.
  • Xem Dockerfile cho phiên bản này

Ví dụ 2 - Sử dụng Nexus để lưu tệp vào bộ nhớ cache

Chạy vùng chứa Nexus

docker run -d -p 8081:8081 --name nexus sonatype/nexus

Tạo tệp "settings.xml":

<settings>
  <mirrors>
    <mirror>
      <id>nexus</id>
      <mirrorOf>*</mirrorOf>
      <url>http://nexus:8081/content/groups/public/</url>
    </mirror>
  </mirrors>
</settings>

Bây giờ hãy chạy liên kết Maven đến vùng chứa nexus để các phần phụ thuộc sẽ được lưu vào bộ nhớ đệm

docker run -it --rm \
       -v "$(pwd)":/opt/maven \
       -w /opt/maven \
       --link nexus:nexus \
       maven:3.2-jdk-7 \
       mvn -s settings.xml clean install

Ghi chú:

  • Một lợi thế của việc chạy Nexus trong nền là các kho lưu trữ bên thứ 3 khác có thể được quản lý thông qua URL quản trị một cách rõ ràng đối với các bản dựng Maven đang chạy trong các vùng chứa cục bộ.

cái này có thể được sử dụng để thay thế maven center cho việc xây dựng gradle không? như đã nêu trong support.sonatype.com/entries/… Tôi đã thay thế mavenCentral()phần phụ thuộc vào lớp của mình bằng maven {url "http://nexus:8081..."và bây giờ chỉ nhận được các vấn đề giải quyết.
mohamnag

@mohamnag Đúng, tệp "cài đặt" của Maven ở trên thực hiện chính xác điều đó, chuyển hướng tất cả các yêu cầu của Maven Central tới kho lưu trữ nexus cục bộ. Bạn cần phác thảo loại vấn đề giải quyết mà bạn đang gặp phải. Có thể là bất cứ thứ gì ... Ví dụ: bạn đã thiết lập liên kết Docker để máy chủ lưu trữ "nexus" được giải quyết đúng cách chưa?
Mark O'Connor

Tôi hóa ra rằng mọi thứ đều ổn, nhưng nexus cần thời gian để xây dựng chỉ mục hoặc điều gì đó khác gây ra rắc rối. Tôi cũng đã cố gắng kích hoạt cập nhật chỉ mục do đó tôi không chắc trường hợp nào đã khắc phục sự cố. Tuy nhiên, cảm ơn.
mohamnag

Nexus 3 hiện cũng có sẵn dưới dạng bộ chứa docker. Sử dụng "sonatype / nexus3"
Thorbjørn Ravn Andersen

1
@avandeursen Bạn đúng là tham số --link không được dùng nữa (Câu trả lời trên 3 tuổi). Tuy nhiên, giải pháp đúng đắn hơn (theo ý kiến ​​của tôi) là tạo một mạng docker và chạy cả hai vùng chứa trên đó. Bằng cách đó, bạn có thể tận dụng tính năng DNS gốc trong Docker và tiếp tục tham chiếu đến vùng chứa nexus theo tên. Sẽ cập nhật ví dụ sau
Mark O'Connor

47

Có thể có nhiều cách .. Nhưng tôi đã triển khai theo hai cách

Ví dụ về dự án maven.

1. Sử dụng Dockerfile trong dự án maven

Sử dụng cấu trúc tệp sau:

Demo
└── src
|    ├── main
|    │   ├── java
|    │       └── org
|    │           └── demo
|    │               └── Application.java
||    └── test
|
├──── Dockerfile
├──── pom.xml

Và cập nhật Dockerfile dưới dạng:

FROM java:8
EXPOSE 8080
ADD /target/demo.jar demo.jar
ENTRYPOINT ["java","-jar","demo.jar"]

Điều hướng đến thư mục dự án và gõ lệnh sau, bạn sẽ có thể tạo hình ảnh và chạy hình ảnh đó:

$ mvn clean
$ mvn install
$ docker build -f Dockerfile -t springdemo .
$ docker run -p 8080:8080 -t springdemo

Xem video tại Spring Boot với Docker

2. Sử dụng các plugin Maven

Thêm plugin maven đã cho vào pom.xml

<plugin>
    <groupId>com.spotify</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <version>0.4.5</version>
        <configuration>
            <imageName>springdocker</imageName>
            <baseImage>java</baseImage>
            <entryPoint>["java", "-jar", "/${project.build.finalName}.jar"]</entryPoint>
            <resources>
                <resource>
                    <targetPath>/</targetPath>
                    <directory>${project.build.directory}</directory>
                    <include>${project.build.finalName}.jar</include>
                </resource>
            </resources>
        </configuration>
    </plugin>

Điều hướng đến thư mục dự án và nhập lệnh sau, bạn sẽ có thể tạo hình ảnh và chạy hình ảnh đó:

$ mvn clean package docker:build
$ docker images
$ docker run -p 8080:8080 -t <image name>

Trong ví dụ đầu tiên, chúng tôi đang tạo Dockerfile và cung cấp hình ảnh cơ sở và thêm jar, sau khi làm điều đó, chúng tôi sẽ chạy lệnh docker để xây dựng một hình ảnh với tên cụ thể và sau đó chạy hình ảnh đó ..

Trong khi ở ví dụ thứ hai, chúng tôi đang sử dụng plugin maven mà chúng tôi cung cấp baseImageimageNamevì vậy chúng tôi không cần tạo Dockerfile ở đây .. sau khi đóng gói dự án maven, chúng tôi sẽ nhận được hình ảnh docker và chúng tôi chỉ cần chạy hình ảnh đó ..


Thay vì sửa đổi điểm nhập để chỉ định tên tạo tác, bạn có thể sử dụng cách tiếp cận như ở đây: alooma.com/blog/building-dockers - sử dụng maven-dependency-plugin để sử dụng tên chung. Không cần đặt một bình đã được tạo phiên bản vào bộ chứa docker vì chính bộ chứa đã được tạo phiên bản.
kboom,

14

Theo nguyên tắc chung, bạn nên xây dựng một JAR béo bằng cách sử dụng Maven (một JAR chứa cả mã của bạn và tất cả các phụ thuộc).

Sau đó, bạn có thể viết một Dockerfile phù hợp với yêu cầu của mình (nếu bạn có thể xây dựng một JAR chất lượng cao, bạn sẽ chỉ cần một hệ điều hành cơ sở, như CentOS và JVM).

Đây là những gì tôi sử dụng cho một ứng dụng Scala (dựa trên Java).

FROM centos:centos7

# Prerequisites.

RUN yum -y update
RUN yum -y install wget tar

# Oracle Java 7

WORKDIR /opt

RUN wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/7u71-b14/server-jre-7u71-linux-x64.tar.gz
RUN tar xzf server-jre-7u71-linux-x64.tar.gz
RUN rm -rf server-jre-7u71-linux-x64.tar.gz
RUN alternatives --install /usr/bin/java java /opt/jdk1.7.0_71/bin/java 1

# App

USER daemon

# This copies to local fat jar inside the image
ADD /local/path/to/packaged/app/appname.jar /app/appname.jar

# What to run when the container starts
ENTRYPOINT [ "java", "-jar", "/app/appname.jar" ]

# Ports used by the app
EXPOSE 5000

Điều này tạo ra một hình ảnh dựa trên CentOS với Java7. Khi bắt đầu, nó sẽ thực thi jar ứng dụng của bạn.

Cách tốt nhất để triển khai nó là thông qua Docker Registry, nó giống như một Github cho hình ảnh Docker.

Bạn có thể xây dựng một hình ảnh như thế này:

# current dir must contain the Dockerfile
docker build -t username/projectname:tagname .

Sau đó, bạn có thể đẩy một hình ảnh theo cách này:

docker push username/projectname # this pushes all tags

Sau khi hình ảnh có trong Docker Registry, bạn có thể kéo hình ảnh từ bất kỳ đâu trên thế giới và chạy nó.

Xem Hướng dẫn sử dụng Docker để biết thêm thông tin.

Một điều cần ghi nhớ :

Bạn cũng có thể kéo kho lưu trữ của mình bên trong một hình ảnh và xây dựng jar như một phần của quá trình thực thi vùng chứa, nhưng đó không phải là một cách tiếp cận tốt, vì mã có thể thay đổi và bạn có thể sử dụng một phiên bản khác của ứng dụng mà không cần thông báo.

Xây dựng một bình chất béo loại bỏ vấn đề này.


Xin chào, tôi đã sử dụng ví dụ của bạn trong tệp docker của mình để sao chép fat jar trong hình ảnh nhưng bản dựng không thành công vì không thể tìm thấy fat jar được đưa ra đường dẫn cục bộ. Nó có giống target / app.jar không?
user_mda

Xin chào, có cách nào để tôi có thể tải xuống tạo tác từ nexus trong thời gian chạy không? Để chỉ định tạo tác được tải xuống bằng cách sử dụng thuộc tính chứ không phải liên kết thực sự đến chính cái jar? Trong tệp dockerfile: RUN wget -O {project.build.finalname}.jar Nhưng tôi muốn tải xuống jar ở trên từ nexus.
Pramod Setlur

1
Với tôi, bao gồm FAT JAR để mã repo là chậm. Có cách nào sử dụng maven để xây dựng hình ảnh không?
WoLfPwNeR

1
Các lọ chất béo cũng có một số vấn đề, đặc biệt là với lọ có ký.
Thorbjørn Ravn Andersen

1
Theo nguyên tắc chung, không bao giờ sử dụng một bình chứa chất béo, các gói dựa trên tệp kê khai hoặc các tệp dữ liệu khác trong bình của chúng có khả năng bị lỗi vì không có cách nào an toàn để hợp nhất dữ liệu này. Tệp kê khai có đường dẫn phù hợp bên trong xung đột jar và chiến thắng đầu tiên hoặc cuối cùng (không thể nhớ cái nào). Thời điểm duy nhất bạn nên cân nhắc sử dụng lọ béo là nếu bạn có một tập hợp phụ thuộc rất hạn chế và bạn biết rất rõ rằng các lọ của chúng không có dữ liệu kê khai mâu thuẫn. Nếu không, hãy giữ các lọ sử dụng an toàn vì chúng đã được thiết kế để sử dụng (tức là riêng biệt).
PiersyP

3

Đây là đóng góp của tôi.
Tôi sẽ không cố gắng liệt kê tất cả các công cụ / thư viện / plugin tồn tại để tận dụng Docker với Maven. Một số câu trả lời đã làm được.
thay vào đó, tôi sẽ tập trung vào phân loại ứng dụng và cách thức Dockerfile.
Dockerfilethực sự là một khái niệm đơn giản và quan trọng về Docker (tất cả các hình ảnh được biết đến / công khai đều dựa vào đó) và tôi nghĩ rằng cố gắng tránh hiểu và sử dụng Dockerfiles không nhất thiết là cách tốt hơn để tham gia vào thế giới Docker.

Tài liệu hóa một ứng dụng phụ thuộc vào chính ứng dụng đó và mục tiêu cần đạt đến

1) Đối với các ứng dụng mà chúng tôi muốn tiếp tục chạy chúng trên máy chủ Java được cài đặt / độc lập (Tomcat, JBoss, v.v.)

Con đường khó hơn và đó không phải là mục tiêu lý tưởng vì điều đó làm tăng thêm sự phức tạp (chúng tôi phải quản lý / bảo trì máy chủ) và nó kém khả năng mở rộng và kém nhanh hơn so với các máy chủ nhúng về mặt xây dựng / triển khai / hủy triển khai.
Nhưng đối với các ứng dụng kế thừa, đó có thể được coi là bước đầu tiên.
Nói chung, ý tưởng ở đây là xác định hình ảnh Docker cho máy chủ và xác định hình ảnh cho mỗi ứng dụng để triển khai.
Hình ảnh docker cho các ứng dụng tạo ra WAR / EAR dự kiến ​​nhưng chúng không được thực thi dưới dạng vùng chứa và hình ảnh cho ứng dụng máy chủ triển khai các thành phần được tạo ra bởi các hình ảnh này dưới dạng các ứng dụng được triển khai.
Đối với các ứng dụng khổng lồ (hàng triệu dòng mã) với rất nhiều nội dung cũ và quá khó để chuyển sang giải pháp nhúng khởi động mùa xuân đầy đủ, đó thực sự là một cải tiến tốt.
Tôi sẽ không trình bày chi tiết hơn về cách tiếp cận đó vì đó là dành cho các trường hợp sử dụng nhỏ của Docker nhưng tôi muốn trình bày ý tưởng tổng thể của cách tiếp cận đó bởi vì tôi nghĩ rằng đối với các nhà phát triển phải đối mặt với những trường hợp phức tạp này, thật tuyệt khi biết rằng một số cánh cửa được mở ra tích hợp Docker.

2) Đối với các ứng dụng tự nhúng / bootstrap máy chủ (Spring Boot với máy chủ nhúng: Tomcat, Netty, Jetty ...)

Đó là mục tiêu lý tưởng với Docker . Tôi đã chỉ định Spring Boot vì đó là một khuôn khổ thực sự tốt để làm điều đó và điều đó cũng có mức độ bảo trì rất cao nhưng về lý thuyết, chúng tôi có thể sử dụng bất kỳ cách Java nào khác để đạt được điều đó.
Nói chung, ý tưởng ở đây là xác định một hình ảnh Docker cho mỗi ứng dụng để triển khai.
Hình ảnh docker cho các ứng dụng tạo ra một JAR hoặc một tập hợp các tệp JAR / lớp / cấu hình và chúng bắt đầu một JVM với ứng dụng (lệnh java) khi chúng ta tạo và khởi động một vùng chứa từ các hình ảnh này.
Đối với các ứng dụng mới hoặc ứng dụng không quá phức tạp để di chuyển, cách đó phải được ưu tiên hơn các máy chủ độc lập vì đó là cách tiêu chuẩn và là cách sử dụng vùng chứa hiệu quả nhất.
Tôi sẽ trình bày chi tiết cách tiếp cận đó.

Tài liệu hóa một ứng dụng maven

1) Không có Spring Boot

Ý tưởng là tạo một lọ béo với Maven (plugin lắp ráp maven và plugin bóng maven giúp thực hiện điều đó) chứa cả các lớp đã biên dịch của ứng dụng và các phụ thuộc maven cần thiết.
Sau đó, chúng tôi có thể xác định hai trường hợp:

  • nếu ứng dụng là ứng dụng dành cho máy tính để bàn hoặc ứng dụng tự trị (không cần phải được triển khai trên máy chủ): chúng tôi có thể chỉ định như CMD/ENTRYPOINTtrong quá Dockerfiletrình thực thi java của ứng dụng:java -cp .:/fooPath/* -jar myJar

  • nếu ứng dụng là một ứng dụng máy chủ, chẳng hạn như Tomcat, thì ý tưởng là giống nhau: lấy một cái lọ béo của ứng dụng và chạy một JVM trong CMD/ENTRYPOINT. Nhưng ở đây có một sự khác biệt quan trọng: chúng ta cần bao gồm một số thư viện logic và cụ thể ( org.apache.tomcat.embedthư viện và một số thư viện khác) khởi động máy chủ nhúng khi ứng dụng chính được khởi động.
    Chúng tôi có một hướng dẫn toàn diện trên trang web heroku .
    Đối với trường hợp đầu tiên (ứng dụng tự trị), đó là một cách đơn giản và hiệu quả để sử dụng Docker.
    Đối với trường hợp thứ hai (ứng dụng máy chủ), hoạt động nhưng không thẳng, có thể dễ xảy ra lỗi và không phải là một mô hình có thể mở rộng vì bạn không đặt ứng dụng của mình trong khung của một khuôn khổ hoàn thiện như Spring Boot. những thứ này cho bạn và cũng cung cấp mức độ mở rộng cao.
    Nhưng điều đó có một lợi thế: bạn có mức độ tự do cao vì bạn sử dụng trực tiếp API Tomcat được nhúng.

2) Với Spring Boot

Cuối cùng, chúng ta bắt đầu.
Điều đó vừa đơn giản, hiệu quả và được ghi chép rất đầy đủ.
Thực sự có một số cách tiếp cận để tạo một ứng dụng Maven / Spring Boot chạy trên Docker.
Việc phơi bày tất cả chúng sẽ lâu và có thể nhàm chán.
Sự lựa chọn tốt nhất phụ thuộc vào yêu cầu của bạn.
Nhưng dù theo cách nào thì chiến lược xây dựng về các lớp docker đều giống nhau.
Chúng tôi muốn sử dụng một bản dựng nhiều giai đoạn: một bản dựa vào Maven để phân giải phụ thuộc và cho bản dựng và một bản khác dựa vào JDK hoặc JRE để khởi động ứng dụng.

Xây dựng giai đoạn (Hình ảnh Maven):

  • bản sao pom vào hình ảnh
  • phụ thuộc tải xuống plugin.
    Về điều đó, mvn dependency:resolve-pluginsxích để mvn dependency:resolvecó thể làm công việc nhưng không phải luôn luôn.
    Tại sao ? Bởi vì các plugin này và việc packagethực thi để đóng gói lọ béo có thể phụ thuộc vào các tạo tác / plugin khác nhau và thậm chí đối với cùng một tạo tác / plugin, chúng vẫn có thể tạo ra một phiên bản khác. Vì vậy, một cách tiếp cận an toàn hơn trong khi có khả năng chậm hơn là giải quyết các phụ thuộc bằng cách thực thi chính xác mvnlệnh được sử dụng để đóng gói ứng dụng (sẽ kéo chính xác các phụ thuộc mà bạn cần) nhưng bằng cách bỏ qua biên dịch nguồn và xóa thư mục đích để làm cho quá trình xử lý nhanh hơn và ngăn chặn bất kỳ phát hiện thay đổi lớp không mong muốn nào cho bước đó.
  • bản sao mã nguồn vào hình ảnh
  • đóng gói ứng dụng

Giai đoạn chạy (hình ảnh JDK hoặc JRE):

  • sao chép bình từ giai đoạn trước

Đây là hai ví dụ.

a) Một cách đơn giản mà không cần bộ nhớ cache cho các phụ thuộc maven đã tải xuống

Dockerfile:

########Maven build stage########
FROM maven:3.6-jdk-11 as maven_build
WORKDIR /app

#copy pom
COPY pom.xml .

#resolve maven dependencies
RUN mvn clean package -Dmaven.test.skip -Dmaven.main.skip -Dspring-boot.repackage.skip && rm -r target/

#copy source
COPY src ./src

# build the app (no dependency download here)
RUN mvn clean package  -Dmaven.test.skip

# split the built app into multiple layers to improve layer rebuild
RUN mkdir -p target/docker-packaging && cd target/docker-packaging && jar -xf ../my-app*.jar

########JRE run stage########
FROM openjdk:11.0-jre
WORKDIR /app

#copy built app layer by layer
ARG DOCKER_PACKAGING_DIR=/app/target/docker-packaging
COPY --from=maven_build ${DOCKER_PACKAGING_DIR}/BOOT-INF/lib /app/lib
COPY --from=maven_build ${DOCKER_PACKAGING_DIR}/BOOT-INF/classes /app/classes
COPY --from=maven_build ${DOCKER_PACKAGING_DIR}/META-INF /app/META-INF

#run the app
CMD java -cp .:classes:lib/* \
         -Djava.security.egd=file:/dev/./urandom \
         foo.bar.MySpringBootApplication

Mặt hạn chế của giải pháp đó? Bất kỳ thay đổi nào trong pom.xml có nghĩa là tạo lại toàn bộ lớp tải xuống và lưu trữ các phụ thuộc maven. Điều đó thường không được chấp nhận đối với các ứng dụng có nhiều phụ thuộc (và Spring Boot kéo nhiều phụ thuộc), về tổng thể nếu bạn không sử dụng trình quản lý kho lưu trữ maven trong quá trình xây dựng hình ảnh.

b) Một cách hiệu quả hơn với bộ nhớ cache cho các phụ thuộc maven đã tải xuống

Cách tiếp cận ở đây là tương tự nhưng các bản tải xuống phụ thuộc maven được lưu trong bộ đệm ẩn của trình tạo docker.
Hoạt động của bộ đệm dựa trên bộ xây dựng (api thử nghiệm của docker).
Để kích hoạt bộ xây dựng, biến env DOCKER_BUILDKIT = 1 phải được đặt (bạn có thể làm điều đó ở nơi bạn muốn: .bashrc, dòng lệnh, tệp json daemon docker ...).

Dockerfile:

# syntax=docker/dockerfile:experimental

########Maven build stage########
FROM maven:3.6-jdk-11 as maven_build
WORKDIR /app

#copy pom
COPY pom.xml .

#copy source
COPY src ./src

# build the app (no dependency download here)
RUN --mount=type=cache,target=/root/.m2  mvn clean package -Dmaven.test.skip

# split the built app into multiple layers to improve layer rebuild
RUN mkdir -p target/docker-packaging && cd target/docker-packaging && jar -xf ../my-app*.jar

########JRE run stage########
FROM openjdk:11.0-jre
WORKDIR /app

#copy built app layer by layer
ARG DOCKER_PACKAGING_DIR=/app/target/docker-packaging
COPY --from=maven_build ${DOCKER_PACKAGING_DIR}/BOOT-INF/lib /app/lib
COPY --from=maven_build ${DOCKER_PACKAGING_DIR}/BOOT-INF/classes /app/classes
COPY --from=maven_build ${DOCKER_PACKAGING_DIR}/META-INF /app/META-INF

#run the app
CMD java -cp .:classes:lib/* \
         -Djava.security.egd=file:/dev/./urandom \
         foo.bar.MySpringBootApplication
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.