micronaut-examples icon indicating copy to clipboard operation
micronaut-examples copied to clipboard

Suggestion: To be Docker friendly don't use Shade plugin etc but instead lib/* and MANIFEST.MF Classpath

Open rbygrave opened this issue 6 years ago • 2 comments

For the case where we are building a Docker image we avoid using war, uber jar or shade plugin.

  • Our app.jar only contains the application code and not the dependencies.
  • Dependencies go into target/lib
  • We use Class-Path in META-INF/MANIFEST.MF

The reason why we do this is when we are building docker images is so that we make use of docker caching. We can put all our dependency jars as a separate Docker layer which is cached. If we rebuild the application without changing our dependencies docker can use the cached layer of dependencies and our diff for the docker image is then just our application code.

To do this with maven:

Maven in build \ plugins

      <plugin>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>3.1.0</version>
        <executions>
          <execution>
            <phase>prepare-package</phase>
            <goals>
              <goal>copy-dependencies</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <useBaseVersion>false</useBaseVersion>
          <overWriteReleases>false</overWriteReleases>
          <overWriteSnapshots>true</overWriteSnapshots>
          <includeScope>runtime</includeScope>
          <outputDirectory>${project.build.directory}/lib</outputDirectory>
        </configuration>
      </plugin>

      <plugin>
        <artifactId>maven-jar-plugin</artifactId>
        <version>3.1.0</version>
        <configuration>
          <archive>
            <addMavenDescriptor>true</addMavenDescriptor>
            <manifest>
              <addClasspath>true</addClasspath>
              <classpathPrefix>lib/</classpathPrefix>
              <mainClass>${main.class}</mainClass>
            </manifest>
          </archive>
        </configuration>
      </plugin>

Maven tile alternative

For people using maven tiles instead of the above just include the maven tile:

<tile>org.avaje.tile:lib-classpath:1.1</tile>

The Dockerfile has:

COPY target/lib /app/lib
COPY target/app.jar /app/app.jar

So we get the separate docker layer for our dependencies.

We run the application as before with java -jar app.jar (the META-INF/MANIFEST.MF ... has the Class-Path: entry.

rbygrave avatar Jun 21 '18 23:06 rbygrave

Thanks we will consider this approach

graemerocher avatar Jun 29 '18 08:06 graemerocher

Another good resource is https://medium.com/holisticon-consultants/dont-build-fat-jars-for-docker-applications-6252a5571248

synox avatar Feb 13 '21 09:02 synox