Search code examples
javadockerdockerfile

Dockerfile for compiling and running Java code received as parameter


I'm trying to create a Dockerfile for building an image that compiles and runs Java code provided as a parameter when running the container. Here's what I have so far:

# Using a base Java image
FROM openjdk:11

# Set the working directory inside the container
WORKDIR /usr/src/app

# Define a shell script for compiling and executing Java code
COPY run_java_code.sh .

# Set execute permissions for the shell script
RUN chmod +x run_java_code.sh

# Define the command to run the container
CMD ["./run_java_code.sh"]

And here is the run_java_code.sh script:

#!/bin/bash

# Save the Java code from the parameter to a temporary file
echo "$1" > Main.java

# Compile the Java code and save any errors to a temporary file
javac Main.java 2> compile_errors.txt

# Check if there are compilation errors
if [ -s compile_errors.txt ]; then
    echo "Compilation error:"
    cat compile_errors.txt
else
    # Run the compiled code
    java Main
fi

# Remove temporary files after execution
rm -f Main.java Main.class compile_errors.txt

I tried to run the image like this with a simple program: docker run java_code public class Main { public static void main(String[] args) { System.out.println("Hello, world!"); }}

I'm getting this error:

docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "public class Main { public static void main(String[] args) { System.out.println(\"Hello, world!\"); }}": executable file not found in $PATH: unknown.

What am I doing wrong? How can I fix this issue?


Solution

  • Your issue is that the parameter you give your container on the docker run command replaces the CMD defined in the image.

    So Docker tries to run your Java program as a shell command, but it can't find an executable called public class Main { public ....

    If you instead define your script as the ENTRYPOINT, Docker will concatenate the entrypoint and the parameters you give on the docker run command into a single command, which is what you want.

    So instead of

    CMD ["./run_java_code.sh"]
    

    use

    ENTRYPOINT ["./run_java_code.sh"]
    

    and your container will compile and run the program, given the command

    docker run java_code 'public class Main { public static void main(String[] args) { System.out.println("Hello, world!"); }}'
    

    For more information, you can read this for an explanation of how ENTRYPOINT, CMD and docker run parameters work together.