Home > Software design >  Running crontab from dockerfile to execute java program
Running crontab from dockerfile to execute java program

Time:07-18

This is my Dockerfile

FROM Base-Image
COPY --from=baseimage:version /
ENTRYPOINT ["/bin/Startup.py"]

RUN yum install --setopt=obsoletes=0 graalvm20-ee-8-jdk-20.3.3 && \
    yum -y install cronie && \
    yum clean all

RUN mkdir -p /etc/runit/artifacts && \
    mkdir -p /etc/runit/artifacts/projectname/target
COPY ./target/projectname-*.jar /etc/runit/artifacts/projectname/target
COPY ./target/classes/com/company/team/internal/cron/JavaCronFile.class 
/etc/runit/artifacts/projectname/target/
COPY ./start.sh /etc/runit/artifacts/projectname


COPY docker/scripts/crontab /etc/crontab
RUN chmod 660 /etc/crontab && \
    /usr/bin/crontab /etc/crontab && \
    setup-supercronic /etc/crontab

docker/scripts/crontab file :

* * * * * java JavaCronFile
# * * * * * java -cp /etc/runit/artifacts/projectname/target/ JavaCronFile
# * * * * * java -version

I have a dockerfile which copies the java project "projectname" , installs cronie and runs the above crontab.

If I run just

* * * * * java -version 

I do see java version getting printed at the cadence ( 1 min in this case) . Also if I go to the docker container and cd /etc/runit/artifacts/projectname/target/ I do see the .class file JavaCronFile.class present.

But for

1: * * * * * java JavaCronFile 

2: * * * * * java -cp /etc/runit/artifacts/projectname/target/ JavaCronFile

3: * * * * * java com.company.team.internal.cron.JavaCronFile

4: * * * * * java -classpath /etc/runit/artifacts/projectname/target/ 
 com.company.team.internal.cron.JavaCronFile

I get : Error: Could not find or load main class JavaCronFile.

I have already referred to following stackoverflow links :

1: Cron job for a Java Program

2: What does "Could not find or load main class" mean?

CodePudding user response:

--classpath can be tricky, but the snippet from Oracle documentation at the end of this post explains it quite well.

You seem to copy both your class files and jar to the container, but do not copy the classes appropriately, nor set the classpath to include the jar file.

To specify a classes directory, the classes must live in the directory that correspond to their package. You copy your target/com/company/team/internal/cron/JavaCronFile.class to target/JavaCronFile.class; Java won't read the class in that case because it expects the file to be in target/com/company/team/internal/cron/JavaCronFile.class in the container, too.

To specify your jar you have to specify the jar. You can do that explicitly or using the * or *.jar pattern, but note well java needs to expand those patterns not your shell!

Thus you should not need to copy your classes and only need to add the wildcard to your classpath to match your copied projectname jar (note the quotes to prevent the shell from expanding "*.jar"):

java -cp "/etc/runit/artifacts/projectname/target/*.jar" com.company.team.internal.cron.JavaCronFile

--class-path classpath, -classpath classpath, or -cp classpath A semicolon (;) [or : on Linux] separated list of directories, JAR archives, and ZIP archives to search for class files.

Specifying classpath overrides any setting of the CLASSPATH environment variable. If the class path option isn't used and classpath isn't set, then the user class path consists of the current directory (.).

As a special convenience, a class path element that contains a base name of an asterisk (*) is considered equivalent to specifying a list of all the files in the directory with the extension .jar or .JAR . A Java program can't tell the difference between the two invocations. For example, if the directory mydir contains a.jar and b.JAR, then the class path element mydir/* is expanded to A.jar:b.JAR, except that the order of JAR files is unspecified. All .jar files in the specified directory, even hidden ones, are included in the list. A class path entry consisting of an asterisk (*) expands to a list of all the jar files in the current directory. The CLASSPATH environment variable, where defined, is similarly expanded. Any class path wildcard expansion that occurs before the Java VM is started. Java programs never see wildcards that aren't expanded except by querying the environment, such as by calling System.getenv("CLASSPATH").

-- https://docs.oracle.com/en/java/javase/13/docs/specs/man/java.html

  • Related