Search code examples
mavendockermanifest.mffabric8docker-maven-plugin

Add MANIFEST.MF to docker image with fabric8 docker-maven-plugin


I've successfully created a docker image with fabric8 plugin, using a custom Dockerfile, for a Servlet WebApp.

The image is based on tomcat, and so I need to put the app in tomcat/webapps To optimize the image I'm not inserting the war directly, but instead the expanded content of it, in two separate layers: one for WEB-INF\lib and one with all other.

Image Layers:
- WEB-INF\classes and resources
- WEB-INF\lib
- tomcat (base layer)

this way if I create a new version but the libs are the same as the old one, the remote server only need to pull the app layer

I'm copying the content of the war from the folder "target/MyProject" generated by maven-war-plugin and from which it then creates the "MyProject.war" But this folder does not contains the META-INF\MANIFEST.MF file (is it created directly in the war?)

Is there a way to create the manifest file in some folder so I can copy it into the docker image?

Here part of the pom.xml

         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>3.2.0</version>
            <configuration>
                <failOnMissingWebXml>false</failOnMissingWebXml>
                <archive>
                    <manifestEntries>
                        /*...*/
                    </manifestEntries>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <groupId>io.fabric8</groupId>
            <artifactId>docker-maven-plugin</artifactId>
            <version>0.30.0</version>
            <extensions>true</extensions>

            <configuration>
                <images>
                    <image>
                        <name>${project.version}-${docker-image-tag}</name>
                        <build>
                            <contextDir>${project.basedir}/src/main/docker</contextDir>
                            <assembly>
                                <name>target</name>
                                <inline>
                                    <fileSets>
                                        <fileSet>
                                            <directory>${project.build.directory}/${project.build.finalName}</directory>
                                            <outputDirectory>slimWar</outputDirectory>
                                            <excludes>
                                                <exclude>WEB-INF\lib\**</exclude>
                                            </excludes>
                                            <useDefaultExcludes>false</useDefaultExcludes>
                                        </fileSet>
                                        <fileSet>
                                            <directory>${project.build.directory}/${project.build.finalName}</directory>
                                            <outputDirectory>libs</outputDirectory>
                                            <includes>
                                                <include>WEB-INF\lib\**</include>
                                            </includes>
                                            <useDefaultExcludes>false</useDefaultExcludes>
                                        </fileSet>
                                    </fileSets>
                                </inline>
                            </assembly>
                        </build>
                    </image>
                </images>
            </configuration>
        </plugin>

Solution

  • I've found a solution, in case someone will face this problem. The trick is to add and decompress the war directly, but doing so will result in a layer with the war and one (or more) with the extracted files

    To solve this we can use docker multi-stage build:

    pom.xml

    <build>
        <contextDir>${project.basedir}/src/main/docker/${docker-contextDir}</contextDir>
        <assembly>
           <descriptorRef>rootWar</descriptorRef>
        </assembly>
    </build>
    

    this will add the artifact as ROOT.war in the /maven directory (inside the image)

    Dockerfile

    FROM busybox AS unzippedWar
    
    ADD /maven/ROOT.war /
    RUN mkdir -p /war/slimWar
    RUN mkdir -p /war/libs
    RUN unzip -qq /ROOT.war -d /war/slimWar
    RUN mkdir -p /war/libs/WEB-INF/lib
    RUN mv /war/slimWar/WEB-INF/lib/* /war/libs/WEB-INF/lib
    
    FROM tomcat:9-jdk8-openjdk-slim
    
    RUN rm -rf  /usr/local/tomcat/webapps/*
    
    COPY --from=unzippedWar /war/libs /usr/local/tomcat/webapps/ROOT/
    COPY --from=unzippedWar /war/slimWar /usr/local/tomcat/webapps/ROOT/
    
    EXPOSE 80
    

    and this time the MANIFEST.MF will be there

    to be picky, the only downside (but it's hardly a problem) is the leftover intermediate image that need to be removed manually, as explained here.