如何将maven项目停靠?以及实现它的方法有多少?

时间:2015-01-04 15:48:52

标签: java maven docker

我是Docker的新手,并且不知道如何使用maven运行java项目,即使我已经阅读了很多文档并尝试了很多方法。

  1. 我应该使用Dockerfile构建图片吗?
  2. 使用Dockerfile在主机中运行maven项目时的命令是什么?

6 个答案:

答案 0 :(得分:43)

可能有很多方法..但我通过以下两种方式实施

给出的例子是maven项目。

<强> 1。在maven项目中使用Dockerfile

使用以下文件结构:

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插件

pom.xml

中添加给定的maven插件
<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插件,我们提供baseImageimageName,所以我们不需要在这里创建Dockerfile ..在打包maven项目后,我们将得到docker图像和我们只需要运行该图像..

答案 1 :(得分:39)

工作示例。

这不是春季启动教程。它是关于如何在Docker容器中运行Maven构建的问题的更新答案。

问题最初发布于4年前。

1。生成应用程序

使用spring初始化程序生成演示应用程序

https://start.spring.io/

enter image description here

在本地提取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"]

请注意

  • 此示例使用multi-stage build。第一阶段用于构建代码。第二阶段只包含构建的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构建以使用本地存储库缓存jar。

更新(2019-02-07)

这个问题现在已经有4年了,在那个时候,使用Docker构建应用程序已经发生了重大变化。

选项1:多阶段构建

这种新风格使您可以创建更轻量级的图像,而这些图像不会封装您的构建工具和源代码。

此处的示例再次使用official 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的distroless基础映像,该映像旨在为Java应用程序提供足够的运行时间。

选项2:Jib

我还没有使用过这种方法,但似乎值得研究,因为它可以让你构建图像而不必像Dockerfiles那样创建讨厌的东西: - )

https://github.com/GoogleContainerTools/jib

该项目有Maven plugin,可将代码的打包直接集成到Maven工作流程中。


原始答案(包括完整性,但很久以前写过)

尝试使用新的官方图片,其中一张为Maven

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

该映像可用于在构建时运行Maven以创建已编译的应用程序,或者如以下示例中所示,在容器中运行Maven构建。

示例1 - 在容器内运行的Maven

以下命令在容器中运行Maven构建:

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

注意:

  • 这种方法的巧妙之处在于所有软件都在容器内安装并运行。只需在主机上使用docker。
  • 请参阅Dockerfile for this version

示例2 - 使用Nexus缓存文件

运行Nexus容器

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

创建&#34; settings.xml&#34;文件:

<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构建。

答案 2 :(得分:11)

根据经验,您应该使用Maven(一个包含代码和所有依赖项的JAR)构建 fat 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

这将使用Java7创建基于CentOS的图像。 启动时,它将执行您的app jar。

部署它的最佳方式是通过Docker Registry,它就像是Docker镜像的Github。

你可以建立这样的图像:

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

然后您可以这样推送图像:

docker push username/projectname # this pushes all tags

一旦图像在Docker Registry上,您就可以从世界上任何地方提取它并运行它。

有关更多信息,请参阅Docker User Guide

要记住的事情

您还可以将您的存储库拉入图像并在容器执行过程中构建jar,但这不是一个好方法,因为代码可能会更改,您最终可能会使用不同版本的应用程序,恕不另行通知。

构建胖罐会消除此问题。

答案 3 :(得分:3)

这是我的贡献。
我不会尝试列出所有可利用Maven充分利用Docker的工具/库/插件。已经有一些答案了。
相反,我将专注于应用程序类型和Dockerfile方式。
Dockerfile实际上是Docker的一个简单而重要的概念(所有已知/公共映像都依赖于此),我认为尝试避免理解和使用Dockerfile并不一定是进入Docker的更好方法。 Docker世界。

对应用程序进行Docker化取决于应用程序本身和达到的目标

1)对于我们要继续在已安装/独立的Java服务器(Tomcat,JBoss等)上运行它们的应用程序

道路更加艰辛,也不是理想的目标,因为这会增加复杂性(我们必须管理/维护服务器),并且在构建方面比嵌入式服务器具有较低的可扩展性和速度。 / deploy / undeploy。
但是对于旧版应用程序,这可能是第一步。
通常,这里的想法是为服务器定义Docker映像,并为每个要部署的应用程序定义一个映像。
应用程序的docker映像会产生预期的WAR / EAR,但不会作为容器执行,服务器应用程序的映像会将这些映像生成的组件部署为已部署的应用程序。
对于具有大量遗留内容的大型应用程序(数百万行代码),因此很难迁移到完整的Spring Boot嵌入式解决方案中,这确实是一个不错的改进。
我将不详细介绍该方法,因为这是针对Docker的少量用例,但我想展示该方法的整体思想,因为我认为对于面对这些复杂情况的开发人员来说,很高兴知道有些门可以打开集成Docker

2)对于本身嵌入/引导服务器的应用程序(带有嵌入式服务器的Spring Boot:Tomcat,Netty,Jetty ...)

这是使用Docker的理想目标。 我之所以指定Spring Boot是因为这样做确实是一个非常不错的框架,并且具有很高的可维护性,但是从理论上讲,我们可以使用任何其他Java方法来实现这一目标。
通常,这里的想法是为每个要部署的应用程序定义一个Docker映像。
应用程序的docker映像会生成一个JAR或一组JAR / classs / configuration文件,当我们从这些映像创建并启动容器时,它们会使用应用程序(java命令)启动JVM。
对于新应用程序或迁移不太复杂的应用程序,与独立服务器相比,必须优先采用这种方式,因为这是使用容器的标准方式和最有效的方式。
我将详细介绍该方法。

Docker打包Maven应用程序

1)没有Spring Boot

这个想法是用Maven创建一个胖子(maven程序集插件和maven阴影插件帮助),其中既包含应用程序的已编译类,又包含所需的maven依赖项。
然后,我们可以确定两种情况:

  • 如果该应用程序是桌面或自主应用程序(不需要部署在服务器上):我们可以在CMD/ENTRYPOINT中将Java执行的Dockerfile指定为应用程序:java -cp .:/fooPath/* -jar myJar

  • 如果应用程序是服务器应用程序,例如Tomcat,则想法是相同的:获取该应用程序的胖子并在CMD/ENTRYPOINT中运行JVM。但是这里有一个重要的区别:我们需要包括一些逻辑和特定的库(org.apache.tomcat.embed库以及其他一些库),这些逻辑库和特定的库在启动主应用程序时启动嵌入式服务器。
    我们有全面的指南on the heroku website
    对于第一种情况(自治应用程序),这是使用Docker的直接有效的方法。
    对于第二种情况(服务器应用程序),这种方法行之有效,但并非直截了当,可能易于出错,并且不是非常可扩展的模型,因为您没有将应用程序放置在诸如Spring Boot这样的成熟框架中,因为框架做很多事情这些东西对您来说还可以提供较高的扩展性。
    但这有一个优点:您具有高度的自由度,因为您直接使用嵌入式Tomcat API。

2)使用Spring Boot

最后,我们开始。
这既简单,高效又有据可查。
实际上,有几种方法可以使Maven / Spring Boot应用程序在Docker上运行。
暴露所有这些可能会很长,甚至很无聊。
最佳选择取决于您的要求。
但是无论如何,关于docker层的构建策略看起来都是一样的。
我们想要使用一个多阶段构建:一个依赖Maven进行依赖关系解析和构建,另一个依赖JDK或JRE启动应用程序。

构建阶段(Maven图片):

  • pom复制到图像
  • 依赖项插件下载。
    与此相关的是,链接到mvn dependency:resolve-plugins的{​​{1}}可以胜任,但并非总是如此。
    为什么呢因为这些插件和用于打包胖子的mvn dependency:resolve执行程序可能依赖于不同的工件/插件,甚至对于相同的工件/插件,它们仍可能使用不同的版本。 因此,一种安全的方法(可能会更慢)可以通过完全执行用于打包应用程序的package命令来解决依赖关系(这将完全拉出您需要的依赖关系),但是可以跳过源代码编译并删除要创建的目标文件夹更快地处理,并防止对该步骤进行任何不希望的层变化检测。
  • 将源代码复制到图像
  • 打包应用程序

运行阶段(JDK或JRE映像):

  • 复制上一阶段的罐子

这里有两个例子。

a)一种没有缓存的简单方法,用于下载的Maven依赖项

Dockerfile:

mvn

该解决方案的缺点? pom.xml中的任何更改都意味着重新创建下载和存储maven依赖项的整个层。 总的来说,如果您在映像构建过程中不使用Maven存储库管理器,那么对于具有许多依赖项的应用程序(通常是Spring Boot拉动许多依赖项)来说,这是不可接受的。

b)一种更高效的缓存方式,用于下载maven依赖项

这里的方法是相同的,但是Maven依赖项下载已缓存在Docker构建器缓存中。
缓存操作依赖于buildkit(docker的实验api)。
要启用buildkit,必须设置环境变量DOCKER_BUILDKIT = 1(您可以在所需的位置进行操作:.bashrc,命令行,docker daemon json文件...)。

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

答案 4 :(得分:0)

Jib 作为 Maven 插件,使其足够简单和灵活,可以使用 Docker 守护程序或忽略它。无论是在命令行还是在 pom.xml 中。

更多信息可以参考build-a-docker-image-using-maven

这是一个简单的 pom.xml:

...
<properties>
    <java.version>11</java.version>
    <docker.name>amirkeshavarz/hellomavendocker</docker.name>
    <docker.REGISTRY_USERNAME>your-dockerhub-username</docker.REGISTRY_USERNAME>
    <docker.REGISTRY_PASSWORD>your-dockerhub-password</docker.REGISTRY_PASSWORD>
</properties>
...
<build>
    <plugins>
        ...
        <plugin>
            <groupId>com.google.cloud.tools</groupId>
            <artifactId>jib-maven-plugin</artifactId>
            <version>2.8.0</version>
            <configuration>
                <from>
                    <image>openjdk:17-jdk-alpine</image>
                    <auth>
                        <username>${docker.REGISTRY_USERNAME}</username>
                        <password>${docker.REGISTRY_PASSWORD}</password>
                    </auth>
                </from>
                <to>
                    <image>${docker.name}</image>
                    <auth>
                        <username>${docker.REGISTRY_USERNAME}</username>
                        <password>${docker.REGISTRY_PASSWORD}</password>
                    </auth>
                </to>
                <container>
                    <environment></environment>
                    <ports>
                        <port>8080</port>
                    </ports>
                    <creationTime>USE_CURRENT_TIMESTAMP</creationTime>
                </container>
            </configuration>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>build</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
...

答案 5 :(得分:-2)

Create a Dockerfile
#
# Build stage
#

FROM maven:3.6.3-jdk-11-slim AS build

WORKDIR usr/src/app

COPY . ./

RUN mvn clean package

#
# Package stage
#

FROM openjdk:11-jre-slim

ARG JAR_NAME="project-name"

WORKDIR /usr/src/app

EXPOSE ${HTTP_PORT}

COPY --from=build /usr/src/app/target/${JAR_NAME}.jar ./app.jar

CMD ["java","-jar", "./app.jar"]