Problem

When we use docker with spring boot projects, sometimes, we get this error:

➜  bin git:(main) ✗ ./docker-run.sh myharbor.com/bswen/spring
Error: Could not find or load main class com.bswen.app7.Main

The core exception is:

Error: Could not find or load main class com.bswen.app7.Main

Environment

  • java 1.8
  • Spring Boot 2.3
  • Intellij IDEA
  • Docker 19

Debug

The Dockerfile:

FROM openjdk:8-jdk-alpine
MAINTAINER [email protected]
ENV APPROOT="/opt/app7"
ARG DEPENDENCY=build/dependency
COPY ${DEPENDENCY}/BOOT-INF/lib ${APPROOT}/lib
COPY ${DEPENDENCY}/META-INF ${APPROOT}/META-INF
COPY ${DEPENDENCY}/BOOT-INF/classes ${APPROOT}

ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-cp","/opt/app8:/opt/app7/lib/*","-Droot.dir=/opt/app7","com.bswen.app7.Main"]
EXPOSE 8082

The Main class of this spring boot application:

package com.bswen.app7;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class,args);
    }
}

If we run the app with gradle directly like this:

./gradlew app7:bootRun

It works, and if we run the spring boot docker image directly without kubernetes like this:

docker run app7:latest

We get the error again:

Error: Could not find or load main class com.bswen.app7.Main

Reason

According to the above debug process, we can found that the real problem should be the Dockerfile, it caused the exception in docker environment.

Solution

We found that there is a wrong character in the Dockerfile, which cause the spring boot app starts with a wrong classpath, that’s the key problem, we changed the Dockerfile like this:

FROM openjdk:8-jdk-alpine
MAINTAINER [email protected]
ENV APPROOT="/opt/app7"
ARG DEPENDENCY=build/dependency
COPY ${DEPENDENCY}/BOOT-INF/lib ${APPROOT}/lib
COPY ${DEPENDENCY}/META-INF ${APPROOT}/META-INF
COPY ${DEPENDENCY}/BOOT-INF/classes ${APPROOT}

ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-cp","/opt/app7:/opt/app7/lib/*","-Droot.dir=/opt/app7","com.bswen.app7.Main"]
EXPOSE 8082

Pay attention to the last command in the Dockerfile of this spring boot app:

ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-cp","/opt/app7:/opt/app7/lib/*","-Droot.dir=/opt/app7","com.bswen.app7.Main"]
EXPOSE 8082

The wrong configuration is “java … -cp /opt/app8…”, the right configuration is “java … -cp /opt/app7..”, this app is installed in “/opt/app7”, not “/opt/app8”, that’s the key point.