วิธีการเทียบเคียงโครงการ maven? และมีกี่วิธีที่จะทำให้สำเร็จ?


90

ฉันยังใหม่กับ Docker และไม่รู้วิธีรันโปรเจ็กต์ java ด้วย maven แม้ว่าฉันจะอ่านเอกสารมากมายและลองหลายวิธีแล้วก็ตาม

  1. ฉันควรสร้างภาพโดยใช้Dockerfile?
  2. คำสั่งเช่นเมื่อเรียกใช้โครงการ maven ในโฮสต์ด้วยDockerfileอะไร?

คำตอบ:


125

ตัวอย่างการทำงาน

นี่ไม่ใช่การสอนสปริงบูต เป็นคำตอบที่อัปเดตสำหรับคำถามเกี่ยวกับวิธีเรียกใช้ Maven build ภายในคอนเทนเนอร์ Docker

คำถามเดิมโพสต์เมื่อ 4 ปีที่แล้ว

1. สร้างแอปพลิเคชัน

ใช้ Spring initializer เพื่อสร้างแอพสาธิต

https://start.spring.io/

ป้อนคำอธิบายภาพที่นี่

แตกไฟล์ zip ในเครื่อง

2. สร้าง 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"]

บันทึก

  • ตัวอย่างนี้ใช้แบบหลายขั้นตอนการสร้าง ขั้นตอนแรกใช้ในการสร้างโค้ด ขั้นตอนที่สองมีเฉพาะ jar ที่สร้างขึ้นและ JRE เพื่อเรียกใช้ (โปรดสังเกตว่า jar ถูกคัดลอกระหว่างขั้นตอนอย่างไร)

3. สร้างภาพ

docker build -t demo .

4. เรียกใช้รูปภาพ

$ 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)

อื่น ๆ

อ่านเอกสารประกอบ Docker hub เกี่ยวกับวิธีที่ Maven build สามารถปรับให้เหมาะสมเพื่อใช้ที่เก็บในเครื่องเพื่อแคช jars

ปรับปรุง (2019-02-07)

คำถามนี้มีอายุ 4 ปีและในเวลานั้นเป็นเรื่องยุติธรรมที่จะบอกว่าการสร้างแอปพลิเคชันโดยใช้ Docker ได้รับการเปลี่ยนแปลงอย่างมีนัยสำคัญ

ตัวเลือกที่ 1: การสร้างหลายขั้นตอน

รูปแบบใหม่นี้ช่วยให้คุณสามารถสร้างภาพที่มีน้ำหนักเบาได้มากขึ้นโดยไม่ต้องห่อหุ้มเครื่องมือสร้างและซอร์สโค้ดของคุณ

ตัวอย่างที่นี่ใช้อิมเมจฐานmaven อย่างเป็นทางการอีกครั้งเพื่อรันขั้นตอนแรกของงานสร้างโดยใช้ Maven เวอร์ชันที่ต้องการ ส่วนที่สองของไฟล์กำหนดวิธีการประกอบ jar ที่สร้างขึ้นในภาพผลลัพธ์สุดท้าย

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"]  

บันทึก:

  • ฉันใช้อิมเมจพื้นฐานแบบไม่มีระยะห่างของ Google ซึ่งมุ่งมั่นที่จะให้เวลาทำงานที่เพียงพอสำหรับแอป java

ตัวเลือกที่ 2: Jib

ฉันไม่ได้ใช้วิธีนี้ แต่ดูเหมือนว่าควรค่าแก่การตรวจสอบเนื่องจากช่วยให้คุณสร้างภาพได้โดยไม่ต้องสร้างสิ่งที่น่ารังเกียจเช่น Dockerfiles :-)

https://github.com/GoogleContainerTools/jib

โปรเจ็กต์นี้มีปลั๊กอิน Mavenซึ่งรวมแพ็กเกจโค้ดของคุณไว้ในเวิร์กโฟลว์ Maven ของคุณโดยตรง


คำตอบเดิม (รวมไว้เพื่อความสมบูรณ์ แต่เขียนไว้นานแล้ว)

ลองใช้ภาพทางการใหม่มีสำหรับ Maven

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

อิมเมจสามารถใช้เพื่อเรียกใช้ Maven ในเวลาสร้างเพื่อสร้างแอปพลิเคชันที่คอมไพล์แล้วหรือดังตัวอย่างต่อไปนี้เพื่อรันบิลด์ Maven ภายในคอนเทนเนอร์

ตัวอย่างที่ 1 - Maven ทำงานภายในคอนเทนเนอร์

คำสั่งต่อไปนี้เรียกใช้ Maven build ของคุณภายในคอนเทนเนอร์:

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

หมายเหตุ:

  • สิ่งที่เรียบร้อยเกี่ยวกับแนวทางนี้คือซอฟต์แวร์ทั้งหมดได้รับการติดตั้งและทำงานภายในคอนเทนเนอร์ ต้องการนักเทียบท่าบนเครื่องโฮสต์เท่านั้น
  • โปรดดูDockerfile สำหรับเวอร์ชันนี้

ตัวอย่างที่ 2 - ใช้ Nexus เพื่อแคชไฟล์

เรียกใช้คอนเทนเนอร์ Nexus

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

สร้างไฟล์ "settings.xml":

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

ตอนนี้เรียกใช้ Maven ที่เชื่อมโยงกับคอนเทนเนอร์ nexus ดังนั้นการอ้างอิงจะถูกแคช

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

หมายเหตุ:

  • ข้อดีของการเรียกใช้ Nexus ในพื้นหลังคือที่เก็บของบุคคลที่สามอื่น ๆ สามารถจัดการได้ผ่าน URL ของผู้ดูแลระบบไปยังบิลด์ Maven ที่ทำงานในคอนเทนเนอร์ภายใน

สามารถใช้แทน maven central สำหรับ gradle build ได้หรือไม่? ตามที่ระบุไว้ในsupport.sonatype.com/entries/…ฉันแทนที่ด้วยการmavenCentral()พึ่งพาการไล่ระดับของฉันด้วยmaven {url "http://nexus:8081..."และตอนนี้เพิ่งได้รับการแก้ไขปัญหา
mohamnag

@mohamnag ถูกต้องไฟล์ "การตั้งค่า" ของ Maven ด้านบนทำเช่นนั้นโดยเปลี่ยนเส้นทางคำขอ Maven Central ทั้งหมดไปยังที่เก็บ nexus ในเครื่อง คุณต้องร่างปัญหาในการแก้ปัญหาที่คุณพบ อาจเป็นอะไรก็ได้ ... ตัวอย่างเช่นคุณได้ตั้งค่าลิงค์ Docker เพื่อให้โฮสต์ "nexus" ได้รับการแก้ไขอย่างเหมาะสมหรือไม่?
Mark O'Connor

ฉันปรากฎว่าทุกอย่างเรียบร้อยดี แต่ nexus ต้องใช้เวลาในการสร้างดัชนีหรืออย่างอื่นที่ทำให้เกิดปัญหา ฉันพยายามทริกเกอร์การอัปเดตดัชนีด้วยดังนั้นฉันจึงไม่แน่ใจว่ากรณีใดที่แก้ไขปัญหาได้ ขอบคุณอย่างไรก็ตาม
mohamnag

ตอนนี้ Nexus 3 มีวางจำหน่ายในรูปแบบ Docker container ด้วย ใช้ "sonatype / nexus3"
Thorbjørn Ravn Andersen

1
@avandeursen คุณถูกต้องที่เลิกใช้พารามิเตอร์ --link (คำตอบที่มีอายุมากกว่า 3 ปี) อย่างไรก็ตามวิธีแก้ปัญหาที่ถูกต้องกว่า (ในความคิดของฉัน) คือการสร้างเครือข่ายนักเทียบท่าและเรียกใช้ทั้งสองคอนเทนเนอร์บนนั้น ด้วยวิธีนี้คุณสามารถใช้ประโยชน์จากคุณสมบัติ DNS ดั้งเดิมใน Docker และอ้างถึงคอนเทนเนอร์ nexus ตามชื่อต่อไป จะอัปเดตตัวอย่างในภายหลัง
Mark O'Connor

47

อาจมีหลายวิธี .. แต่ผมดำเนินการโดยทำตามสองวิธี

ยกตัวอย่างมาจากโครงการ maven

1. การใช้ Dockerfile ในโครงการ maven

ใช้โครงสร้างไฟล์ต่อไปนี้:

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

และอัปเดต Dockerfile เป็น:

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

ไปที่โฟลเดอร์โครงการและพิมพ์คำสั่งต่อไปนี้คุณจะเป็น ab le เพื่อสร้างภาพและเรียกใช้ภาพนั้น:

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

รับวิดีโอที่Spring Boot with Docker

2. การใช้ปลั๊กอิน Maven

เพิ่มปลั๊กอิน maven ที่กำหนด 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>

ไปที่โฟลเดอร์โครงการและพิมพ์คำสั่งต่อไปนี้คุณจะสามารถสร้างภาพและเรียกใช้ภาพนั้นได้:

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

ในตัวอย่างแรกเรากำลังสร้าง Dockerfile และจัดเตรียมอิมเมจพื้นฐานและเพิ่ม jar หลังจากนั้นเราจะรันคำสั่ง docker เพื่อสร้างอิมเมจที่มีชื่อเฉพาะจากนั้นเรียกใช้อิมเมจนั้น ..

ในขณะที่ในตัวอย่างที่สองเราใช้ปลั๊กอิน maven ที่เราให้มาbaseImageและimageNameเราไม่จำเป็นต้องสร้าง Dockerfile ที่นี่ .. หลังจากโปรเจ็กต์ maven บรรจุภัณฑ์เราจะได้รับอิมเมจนักเทียบท่าและเราต้องเรียกใช้ภาพนั้น ..


แทนที่จะแก้ไขจุดเข้าใช้เพื่อระบุชื่อสิ่งประดิษฐ์คุณสามารถใช้วิธีการเช่นในที่นี่: alooma.com/blog/building-dockers - ใช้ maven-dependency-plugin เพื่อใช้ชื่อทั่วไป ไม่จำเป็นต้องใส่ขวดที่มีเวอร์ชันในคอนเทนเนอร์นักเทียบท่าเนื่องจากคอนเทนเนอร์นั้นเป็นเวอร์ชัน
kboom

14

ตามหลักทั่วไปคุณควรสร้างJAR อ้วนโดยใช้ Maven (JAR ที่มีทั้งรหัสของคุณและการอ้างอิงทั้งหมด)

จากนั้นคุณสามารถเขียนDockerfileที่ตรงกับความต้องการของคุณ (หากคุณสามารถสร้าง JAR แบบอ้วนได้คุณจะต้องใช้ระบบปฏิบัติการพื้นฐานเช่น CentOS และ JVM เท่านั้น)

นี่คือสิ่งที่ฉันใช้สำหรับแอป Scala (ซึ่งใช้ 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

สิ่งนี้จะสร้างอิมเมจที่ใช้ CentOS ด้วย Java7 เมื่อเริ่มต้นมันจะเรียกใช้งานโถแอพของคุณ

วิธีที่ดีที่สุดในการปรับใช้คือผ่าน Docker Registry ซึ่งเหมือนกับ Github สำหรับอิมเมจ Docker

คุณสามารถสร้างภาพดังนี้:

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

จากนั้นคุณสามารถพุชรูปภาพด้วยวิธีนี้:

docker push username/projectname # this pushes all tags

เมื่อภาพอยู่ใน Docker Registry แล้วคุณสามารถดึงภาพจากที่ใดก็ได้ในโลกและเรียกใช้

ดูคู่มือผู้ใช้ Dockerสำหรับข้อมูลเพิ่มเติม

สิ่งที่ควรทราบ :

คุณยังสามารถดึงที่เก็บของคุณภายในรูปภาพและสร้าง jar เป็นส่วนหนึ่งของการเรียกใช้งานคอนเทนเนอร์ได้ แต่ก็ไม่ใช่แนวทางที่ดีเนื่องจากโค้ดอาจเปลี่ยนแปลงได้และคุณอาจใช้แอปเวอร์ชันอื่นโดยไม่ต้องแจ้งให้ทราบ

การสร้างโถไขมันช่วยขจัดปัญหานี้


สวัสดีฉันใช้ตัวอย่างของคุณในไฟล์นักเทียบท่าเพื่อคัดลอกโถไขมันในภาพ แต่การสร้างล้มเหลวเนื่องจากไม่สามารถหาโถไขมันตามเส้นทางในพื้นที่ได้ เป็นอย่างเช่น target / app.jar หรือไม่?
user_mda

สวัสดีมีวิธีดาวน์โหลด Artifact จาก Nexus ที่รันไทม์ได้ไหม หากต้องการระบุอาร์ติแฟกต์ที่จะดาวน์โหลดโดยใช้คุณสมบัติและไม่ใช่ลิงก์จริงไปยัง jar เอง? ใน dockerfile: RUN wget -O {project.build.finalname}.jar แต่ฉันต้องการดาวน์โหลด jar ด้านบนจาก nexus
Pramod Setlur

1
การรวม FAT JAR เพื่อโค้ด repo นั้นช้าสำหรับฉัน มีวิธีใดบ้างในการใช้ maven เพื่อสร้างภาพ?
WoLfPwNeR

1
กระปุกไขมันก็มีปัญหาเช่นกันโดยเฉพาะอย่างยิ่งกับขวดโหลที่มีลายเซ็น
Thorbjørn Ravn Andersen

1
ตามกฎทั่วไปไม่เคยใช้โถไขมันแพ็กเกจที่อาศัยไฟล์ Manifest หรือไฟล์ข้อมูลอื่น ๆ ภายใน jar ของพวกเขามักจะล้มเหลวเนื่องจากไม่มีวิธีที่ปลอดภัยในการรวมข้อมูลนี้ ไฟล์ Manifest ที่มีพา ธ ที่ตรงกันภายใน jar ขัดแย้งและชนะครั้งแรกหรือครั้งสุดท้าย (จำไม่ได้ว่าอันไหน) ครั้งเดียวที่คุณควรพิจารณาใช้กระปุกไขมันคือถ้าคุณมีชุดการอ้างอิงที่ จำกัด มากและคุณรู้ดีว่าขวดโหลของพวกเขาไม่มีข้อมูลรายการที่ขัดแย้งกัน หรือใช้ขวดโหลอย่างปลอดภัยเนื่องจากได้รับการออกแบบมาให้ใช้ (เช่นแยกต่างหาก)
PiersyP

3

นี่คือผลงานของฉัน
ฉันจะไม่พยายามแสดงรายการเครื่องมือ / ไลบรารี / ปลั๊กอินทั้งหมดที่มีอยู่เพื่อใช้ประโยชน์จาก Docker กับ Maven บางคำตอบได้ทำไปแล้ว
แต่ฉันจะเน้นไปที่ประเภทของแอปพลิเคชันและวิธี Dockerfile แทน
Dockerfileเป็นแนวคิดที่เรียบง่ายและสำคัญของ Docker (ภาพที่รู้จัก / ภาพสาธารณะทั้งหมดอาศัยสิ่งนั้น) และฉันคิดว่าการพยายามหลีกเลี่ยงความเข้าใจและใช้Dockerfiles ไม่จำเป็นต้องเป็นวิธีที่ดีกว่าในการเข้าสู่โลกของ Docker

การเทียบเคียงแอปพลิเคชันขึ้นอยู่กับตัวแอปพลิเคชันและเป้าหมายที่จะไปถึง

1) สำหรับแอปพลิเคชันที่เราต้องการเปิดใช้งานบนเซิร์ฟเวอร์ Java ที่ติดตั้ง / สแตนด์อโลน (Tomcat, JBoss ฯลฯ ... )

ถนนนั้นยากกว่าและนั่นไม่ใช่เป้าหมายในอุดมคติเพราะมันเพิ่มความซับซ้อน (เราต้องจัดการ / ดูแลเซิร์ฟเวอร์) และมันปรับขนาดได้น้อยกว่าและเร็วกว่าเซิร์ฟเวอร์แบบฝังในแง่ของการสร้าง / ปรับใช้ / ยกเลิกการใช้งาน
แต่สำหรับแอปพลิเคชันเดิมนั่นอาจถือเป็นขั้นตอนแรก
โดยทั่วไปแนวคิดที่นี่คือการกำหนดอิมเมจ Docker สำหรับเซิร์ฟเวอร์และกำหนดภาพต่อแอปพลิเคชันเพื่อปรับใช้
อิมเมจนักเทียบท่าสำหรับแอ็พพลิเคชันสร้าง WAR / EAR ที่คาดไว้ แต่สิ่งเหล่านี้ไม่ได้ถูกเรียกใช้เป็นคอนเทนเนอร์และอิมเมจสำหรับแอ็พพลิเคชันเซิร์ฟเวอร์ใช้ส่วนประกอบที่สร้างโดยอิมเมจเหล่านี้เป็นแอ็พพลิเคชันที่ปรับใช้
สำหรับแอพพลิเคชั่นขนาดใหญ่ (โค้ดนับล้านบรรทัด) ที่มีของดั้งเดิมจำนวนมากและยากที่จะย้ายไปใช้โซลูชันฝังสปริงบูตแบบเต็มนั่นเป็นการปรับปรุงที่ดี
ฉันจะไม่ลงรายละเอียดเพิ่มเติมเกี่ยวกับแนวทางดังกล่าวเนื่องจากเป็นกรณีการใช้งานเล็กน้อยของ Docker แต่ฉันต้องการเปิดเผยแนวคิดโดยรวมของแนวทางนั้นเพราะฉันคิดว่าสำหรับนักพัฒนาที่ต้องเผชิญกับกรณีที่ซับซ้อนเหล่านี้เป็นเรื่องดีที่ทราบว่าประตูบางบานเปิดให้ รวม Docker

2) สำหรับแอปพลิเคชันที่ฝัง / บูตเซิร์ฟเวอร์ด้วยตัวเอง (Spring Boot พร้อมเซิร์ฟเวอร์ที่ฝัง: Tomcat, Netty, Jetty ... )

นั่นคือเป้าหมายที่เหมาะกับนักเทียบท่า ฉันระบุ Spring Boot เพราะนั่นเป็นเฟรมเวิร์กที่ดีมากในการทำเช่นนั้นและนั่นยังมีความสามารถในการบำรุงรักษาในระดับสูงมาก แต่ในทางทฤษฎีเราสามารถใช้วิธีอื่น ๆ ของ Java เพื่อให้บรรลุสิ่งนั้นได้
โดยทั่วไปแนวคิดในที่นี้คือการกำหนดอิมเมจ Docker ต่อแอปพลิเคชันเพื่อปรับใช้
อิมเมจนักเทียบท่าสำหรับแอ็พพลิเคชันสร้าง JAR หรือชุดของไฟล์ JAR / คลาส / คอนฟิกูเรชันและสิ่งเหล่านี้เริ่มต้น JVM ด้วยแอ็พพลิเคชัน (คำสั่ง java) เมื่อเราสร้างและเริ่มต้นคอนเทนเนอร์จากอิมเมจเหล่านี้
สำหรับแอปพลิเคชันหรือแอปพลิเคชันใหม่ที่ไม่ซับซ้อนเกินไปในการโยกย้ายวิธีนั้นจะต้องได้รับการสนับสนุนบนเซิร์ฟเวอร์แบบสแตนด์อโลนเนื่องจากเป็นวิธีมาตรฐานและเป็นวิธีที่มีประสิทธิภาพสูงสุดในการใช้คอนเทนเนอร์
ฉันจะให้รายละเอียดแนวทางนั้น

การเทียบเคียงแอปพลิเคชัน maven

1) ไม่มี Spring Boot

แนวคิดคือการสร้างโถไขมันด้วย Maven (ปลั๊กอินการประกอบ maven และปลั๊กอิน maven shade ช่วยในเรื่องนั้น) ซึ่งมีทั้งคลาสที่คอมไพล์แล้วของแอปพลิเคชันและการพึ่งพา maven ที่จำเป็น
จากนั้นเราสามารถระบุได้สองกรณี:

  • หากแอปพลิเคชันเป็นเดสก์ท็อปหรือแอปพลิเคชันอิสระ (ที่ไม่จำเป็นต้องปรับใช้บนเซิร์ฟเวอร์) เราสามารถระบุได้เช่นเดียวกับCMD/ENTRYPOINTในการDockerfileเรียกใช้งาน java ของแอปพลิเคชัน:java -cp .:/fooPath/* -jar myJar

  • หากแอปพลิเคชันเป็นแอปพลิเคชันเซิร์ฟเวอร์ตัวอย่างเช่น Tomcat แนวคิดก็เหมือนกัน: เพื่อรับโถไขมันของแอปพลิเคชันและเรียกใช้ JVM ในไฟล์CMD/ENTRYPOINT. แต่ที่นี่มีข้อแตกต่างที่สำคัญ: เราจำเป็นต้องรวมตรรกะและไลบรารีเฉพาะorg.apache.tomcat.embedบางส่วน( ไลบรารีและอื่น ๆ ) ที่เริ่มเซิร์ฟเวอร์ฝังตัวเมื่อแอปพลิเคชันหลักเริ่มทำงาน
    เรามีคำแนะนำที่ครอบคลุมบนเว็บไซต์ Heroku
    สำหรับกรณีแรก (แอปพลิเคชันอิสระ) นั่นเป็นวิธีที่ตรงและมีประสิทธิภาพในการใช้ Docker
    สำหรับกรณีที่สอง (แอปพลิเคชันเซิร์ฟเวอร์) ที่ใช้งานได้ แต่ไม่ตรงอาจเกิดข้อผิดพลาดได้ง่ายและไม่ใช่แบบจำลองที่ขยายได้มากเนื่องจากคุณไม่ได้วางแอปพลิเคชันของคุณในกรอบของเฟรมเวิร์กที่เป็นผู้ใหญ่เช่น Spring Boot ที่ทำหลาย ๆ สิ่งเหล่านี้สำหรับคุณและยังมีส่วนขยายในระดับสูง
    แต่นั่นมีข้อดีคือคุณมีอิสระในระดับสูงเพราะคุณใช้ Tomcat API ที่ฝังไว้โดยตรง

2) ด้วย Spring Boot

ในที่สุดเราไปกันเลย
ทั้งเรียบง่ายมีประสิทธิภาพและจัดทำเอกสารไว้เป็นอย่างดี
มีหลายวิธีในการสร้างแอปพลิเคชัน Maven / Spring Boot เพื่อทำงานบน Docker
การเปิดเผยข้อมูลทั้งหมดจะยาวและอาจน่าเบื่อ
ทางเลือกที่ดีที่สุดขึ้นอยู่กับความต้องการของคุณ
แต่ไม่ว่าจะด้วยวิธีใดกลยุทธ์การสร้างในแง่ของชั้นนักเทียบท่าก็ดูเหมือนกัน
เราต้องการใช้การสร้างแบบหลายขั้นตอน: อันหนึ่งอาศัย Maven สำหรับการแก้ปัญหาการพึ่งพาและสำหรับการสร้างและอีกชุดหนึ่งอาศัย JDK หรือ JRE เพื่อเริ่มแอปพลิเคชัน

สร้างเวที (ภาพ Maven):

  • pom คัดลอกไปยังรูปภาพ
  • การอ้างอิงและการดาวน์โหลดปลั๊กอิน
    เกี่ยวกับเรื่องนั้นmvn dependency:resolve-pluginsถูกล่ามโซ่ไว้mvn dependency:resolveอาจทำให้ได้งาน แต่ไม่เสมอไป
    ทำไม? เนื่องจากปลั๊กอินเหล่านี้และการpackageดำเนินการเพื่อจัดแพ็กเกจกระปุกไขมันอาจอาศัยสิ่งประดิษฐ์ / ปลั๊กอินที่แตกต่างกันและแม้กระทั่งสำหรับสิ่งประดิษฐ์ / ปลั๊กอินเดียวกันสิ่งเหล่านี้อาจดึงเวอร์ชันที่แตกต่างออกไป ดังนั้นวิธีการที่ปลอดภัยกว่าในขณะที่อาจช้ากว่าคือการแก้ไขการอ้างอิงโดยดำเนินการตามmvnคำสั่งที่ใช้ในการจัดแพคเกจแอปพลิเคชัน (ซึ่งจะดึงการอ้างอิงที่คุณต้องการ) แต่โดยการข้ามการคอมไพล์ซอร์สและโดยการลบโฟลเดอร์เป้าหมายเพื่อให้การประมวลผลเร็วขึ้นและ ป้องกันการตรวจจับการเปลี่ยนแปลงชั้นที่ไม่ต้องการสำหรับขั้นตอนนั้น
  • คัดลอกซอร์สโค้ดไปที่รูปภาพ
  • แพ็กเกจแอปพลิเคชัน

รันสเตจ (รูปภาพ JDK หรือ JRE):

  • คัดลอกโถจากขั้นตอนก่อนหน้า

นี่คือสองตัวอย่าง

a) วิธีง่ายๆโดยไม่ต้องแคชสำหรับการอ้างอิง maven ที่ดาวน์โหลด

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

ข้อเสียของการแก้ปัญหานั้น? การเปลี่ยนแปลงใด ๆ ใน pom.xml หมายถึงการสร้างเลเยอร์ใหม่ทั้งหมดที่ดาวน์โหลดและจัดเก็บการอ้างอิงของ maven โดยทั่วไปไม่เป็นที่ยอมรับสำหรับแอปพลิเคชันที่มีการอ้างอิงจำนวนมาก (และ Spring Boot ดึงการอ้างอิงจำนวนมาก) โดยรวมถ้าคุณไม่ใช้ตัวจัดการที่เก็บ maven ในระหว่างการสร้างอิมเมจ

b) วิธีที่มีประสิทธิภาพมากขึ้นด้วยแคชสำหรับการอ้างอิง maven ที่ดาวน์โหลด

วิธีการนี้เหมือนกัน แต่การดาวน์โหลดการอ้างอิง maven ที่แคชในแคชตัวสร้างนักเทียบท่า
การดำเนินการแคชอาศัย buildkit (API ทดลองของนักเทียบท่า)
ในการเปิดใช้งาน buildkit ต้องตั้งค่าตัวแปร env DOCKER_BUILDKIT = 1 (คุณสามารถทำได้ในที่ที่คุณต้องการ: .bashrc, command line, docker daemon json file ... )

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.