2
votes

I have a multi-module maven application which uses Spring boot. It has Rest API's defined to provide service to the consumers.

  • spring boot parent
    • myproject parent (both parent and module pom)
      • module1
      • module-it (integration tests)

In my Module 1 Spring boot maven plugin configuration in pom is as follows

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>1.5.4.RELEASE</version>
    <configuration>
        <mainClass>com.package.Application</mainClass>
        <layout>JAR</layout>
    </configuration>
     <executions>
        <execution>
            <goals>
                <goal>repackage</goal> 
            </goals>
            <configuration>
                <classifier>exec</classifier>
            </configuration> 
        </execution> 
    </executions>
</plugin>   

I am using fabric io to create docker image. see below for fabric io plugin definition in my Module 1

<plugin>
    <groupId>io.fabric8</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <version>0.24.0</version>           
    <configuration>         
        <images>
            <image>         
                <alias>service</alias>
                <name>Sample</name>         
                <build>         
                    <from>greyfoxit/alpine-openjdk8</from>
                    <entryPoint>
                        <exec>
                            <arg>java</arg>
                            <arg>-jar</arg>
                            <arg>maven/sample-model-1.0.0-SNAPSHOT.jar</arg>
                        </exec>
                    </entryPoint>           
                    <assembly>          
                        <descriptorRef>artifact-with-dependencies</descriptorRef>
                    </assembly>
                    <ports>
                        <port>8080</port>
                    </ports>
                </build>                        
            </image>            
        </images>
    </configuration>
    <executions>
        <execution>
            <id>docker-build</id>
            <goals>
                <goal>build</goal>
            </goals>
        </execution>
    </executions>                       
</plugin>       

Added classifier configuration in Spring boot maven plugin as exec for the Integration Test module to identify the Spring boot application class to boot.

In my Integration Test module, i am using failsafe plugin to do integration test. see below for plugin definition in the integration Test module

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>2.18.1</version>
    <executions>
        <execution>
            <id>integration-tests</id>
            <goals>
                <goal>integration-test</goal>
                <goal>verify</goal>
            </goals>
            <configuration>
                <includes>
                    <include>**/*.java</include>
                </includes>
                <groups>io.sample.test.IntegrationTest</groups>
                <skipTests>${skip.integration.tests}</skipTests>
            </configuration>
        </execution>
    </executions>
</plugin>

My IntegrationTest class is defined as below.

@RunWith(SpringRunner.class)
@Category(IntegrationTest.class)
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

public class ControllerIT 
{
    @Autowired
    private MockMvc mockMvc;


    @Autowired
    private Environment env;



    @Test
    public void IntegrationTestForService() throws Exception {

        JsonNode node=mapper.readTree(new File("/src/integration-test/resources/Request.json"));
        RequestBuilder requestBuilder = MockMvcRequestBuilders
                .post("/api/sample/v1")
                .accept(MediaType.APPLICATION_JSON).content(node.toString())
                .contentType(MediaType.APPLICATION_JSON);

        MvcResult result = mockMvc.perform(requestBuilder).andReturn();

        MockHttpServletResponse response = result.getResponse();

        assertEquals(HttpStatus.CREATED.value(), response.getStatus());

    }
}

IntegrationTest is executing fine and able to test the REST API's. How ever when i try to run the docker file using docker run using the module1 jar file, spring boot is not starting. It says manifest is not found. below is the error message.

no main manifest attribute, in maven/sample-model-1.0.0-SNAPSHOT.jar.

When i removed the exec classifier from module 1, spring boot is able to start when docker run command is executed. However, i have problem with the execution of Integration test case with Spring boot Test if the classifier is not present.

Could you please suggest if there is any option.

1

1 Answers

0
votes

I think that if you're going to use the classifier to generate a separate repackaged jar for Spring Boot, then you need to reference that repackaged jar in your docker-maven-plugin configuration. That is, your <entrypoint><exec> should be invoking sample-model-1.0.0-SNAPSHOT-exec.jar. (Note the "-exec")

Also, just for good practice, you may want to consider using project variables for your jar target, rather than hardcoding the version, e.g.:

<entrypoint>
    <exec>
        <arg>java</arg>
        <arg>-jar</arg>
        <arg>maven/${project.artifactId}-${project.version}-exec.jar</arg>
    </exec>
</entrypoint>

You'll also need to change your assembly from the artifact-with-dependencies descriptorRef to an inline assembly, so that the "exec" version of the jar is built into your Docker image. (Note also that the artifact-with-dependencies was tossing all those redundant dependencies into your image, making it larger than needed.)

<assembly>
  <inline>
    <fileSets>
      <fileSet>
        <directory>target</directory>
        <outputDirectory>.</outputDirectory>
        <fileMode>0644</fileMode>
        <includes>
          <include>${project.artifactId}-${project.version}-exec.jar</include>
        </includes>
      </fileSet>
    </fileSets>      
  </inline>
</assembly>