我想加快速度。

场景是这样的:

  1. 触摸/更改一些源代码
  2. docker build
  3. Maven下载世界
  4. Maven编译我的项目
  5. docker run
  6. 触摸/更改一些源代码
  7. docker build
  8. Maven下载世界
  9. Maven编译我的项目
  10. docker run
  11. 触摸/更改一些源代码
  12. docker build
  13. Maven下载世界
  14. Maven编译我的项目
  15. docker run

maven下载世界

让我们继续前进,让我的情况有所好转。 为了说明起见,我们将从这个通用的原型创建的骨架项目开始:

package com.keyholesoftware.blog;

public class App
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );
    }
}
package com.keyholesoftware.blog;

import junit.framework.*;

public class AppTest extends TestCase
{
    public void testApp()
    {
        assertTrue( true );
    }
}
FROM maven:3.2.5-jdk-8u40

RUN mkdir --parents /usr/src/app
WORKDIR /usr/src/app

ADD . /usr/src/app
RUN mvn verify
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.keyholesoftware.blog</groupId>
  <artifactId>khs-docker-caching-blog</artifactId>
  <version>1.0-SNAPSHOT</version>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

当我进行背对背构建时,情况还不错。

$ docker build .
  ...
$ docker build .
  ...

请注意,由于所有内容都已缓存,因此第二个构建速度很快。 但是当我们做这样的事情呢:

$ docker build .
  ...
$ touch src/main/java/com/keyholesoftware/blog/App.java
  ...
$ docker build .
  ...

请注意,重新下载部分不必要地减慢了第二个构建的速度。

我围坐在一旁,绝望了一段时间,直到我想起了选择性缓存的技巧:

FROM maven:3.2.5-jdk-8u40

RUN mkdir --parents /usr/src/app
WORKDIR /usr/src/app


# selectively add the POM file
ADD pom.xml /usr/src/app/
# get all the downloads out of the way
RUN mvn verify clean --fail-never


ADD . /usr/src/app
RUN mvn verify

让我们再次尝试该顺序。

$ docker build .
 ...
$ touch src/main/java/com/keyholesoftware/blog/App.java
  ...
$ docker build .
  ...

越来越好,但是在第二个版本中仍然有一些下载。 它们与surefire测试/插件相关。 实际上,此过程将帮助我们消除动态选择的下载并将其锁定。 在这种情况下,我们将锁定surefire提供程序。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.keyholesoftware.blog</groupId>
  <artifactId>khs-docker-caching-blog</artifactId>
  <version>1.0-SNAPSHOT</version>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <properties>
    <surefire.version>2.8.1</surefire.version>
  </properties>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>${surefire.version}</version>
        <!-- lock down our surefire provider -->
        <dependencies>
          <dependency>
            <groupId>org.apache.maven.surefire</groupId>
            <artifactId>surefire-junit3</artifactId>
            <version>${surefire.version}</version>
          </dependency>
        </dependencies>
      </plugin>
    </plugins>
  </build>

</project>

让我们再次尝试该顺序。

$ docker build .
  ...
$ touch src/main/java/com/keyholesoftware/blog/App.java
  ...
$ docker build .
  ...

因此,现在,除非我们更改POM,否则不必重新下载任何内容。 真好

现在的场景是这样的:

  1. 触摸/更改一些源代码
  2. docker build
  3. Maven下载世界
  4. Maven编译我的项目
  5. docker run
  6. 触摸/更改一些源代码
  7. docker build
  8. Maven编译我的项目
  9. docker run
  10. 触摸/更改一些源代码
  11. docker build
  12. Maven编译我的项目
  13. docker run

注意,“ maven下载世界 ”步骤仅发生一次(当然,除非我实际上更改了POM)。

最后的想法

也许有更好的方法来处理其中的某些问题(例如,dependency:resolve / resolve-plugin,但似乎无法完全解决问题,并且可能与图有关),但我主要想强调一下选择性添加的可能用途。 /缓存。

其他说明:
  • 对于您Ruby + Rakefile,Python + requirements.txt,Node + package.json,Go + GoDeps.json等。伙计们-Maven没有明确的“安装依赖项”步骤。 如果您觉得无聊,请参阅《构建生命周期简介》
  • 对于您的Gradle员工,我用的不多。 你怎么看?

谢谢阅读!