I currently use Github Actions to do the following - checkout a repo, setup java (11), setup Gradle (5.6, I know it’s very old…), setup nodeJs and then run the gradle wrapper.
I asked ChatGTP to covert these steps into a multi staged docker file.
This is what it rendered out (after I deleted the repo checkout stuff).
# Stage 1: Java and Node Setup
FROM adoptopenjdk:11-jdk-hotspot AS setup
RUN apt-get update && \
apt-get install -y curl && \
curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \
apt-get install -y nodejs
# Stage 2: Gradle Build
FROM gradle:5.6 AS builder
WORKDIR /app
COPY . .
RUN ./gradlew clean build
# Stage 3: Final image
FROM adoptopenjdk:11-jre-hotspot
RUN addgroup --system userapp && \
adduser -system --no-create-home --uid 1001 userapp --ingroup userapp
WORKDIR /app
COPY --from=builder /app /app
# Expose the application port
EXPOSE 8080
# Run the application
ENTRYPOINT ["java", "-jar", "/app/frontend.jar"]
However I’m seeing this error which is a NodeJS (npm) issue. It thinks Node isn’t installed.
#0 13.03 Starting a Gradle Daemon (subsequent builds will be faster)
#0 32.14 > Task :clean UP-TO-DATE
#0 32.23 > Task :bootBuildInfo
#0 62.23 > Task :compileJava
#0 71.83 > Task :nodeSetup SKIPPED
#0 71.83 > Task :npmSetup SKIPPED
#0 71.93 > Task :installGulp FAILED
#0 71.93
#0 71.93 FAILURE: Build failed with an exception.
#0 71.93
#0 71.93 * What went wrong:
#0 71.93 Execution failed for task ':installGulp'.
#0 71.93 > A problem occurred starting process 'command 'npm''
#0 71.93
#0 71.93 * Try:
#0 71.93 Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
#0 71.93
#0 71.93 * Get more help at https://help.gradle.org
#0 71.93
#0 71.93 BUILD FAILED in 1m 11s
#0 71.93 4 actionable tasks: 3 executed, 1 up-to-date
------
Dockerfile:12
--------------------
10 | WORKDIR /app
11 | COPY . .
12 | >>> RUN ./gradlew clean build
13 |
14 | # Stage 3: Final image
--------------------
ERROR: failed to solve: process "/bin/sh -c ./gradlew clean build" did not complete successfully: exit code: 1
Can anyone advise on the correct usages of when to use SETUP, BUILDER and BASE for my use case please?
The problem with ChatGPT is that people believe that it will create a valid code. It could sometimes, depending on what you ask it about, but you still need to interpret the result and ask back if something seems wrong. Then it will say something like “You are right. I apologise for the confusion. That’s the right code:” and can make a mistake again. For example I don’t see that you do anything with the “setup” stage where you installed nodejs.
The other issue I think is that you asked ChatGPT to create a multi-stage Dockerfile from the GitHub actions and it didn’t tell you that might not what you need or the steps are not easily convertable to stages so it created something that looks like a multi-stage build and contains similar lines that the GitHub actions had.
If you want a final image that contains Java and nodejs, choose a base image either nodejs or java and install the missing dependencies in it in one stage. Multistage build could be good for gradle if it creates files that compatible with the base image into which you copy the result, but installed packages in a previous stage will not be installed in the other stages. That is basically one of the points of multi-stage builds
I will try to modify your dockerfile without testing, so it might not work either but can give you an idea:
# Stage 1: Gradle Build
FROM gradle:5.6 AS builder
RUN apt-get update && \
apt-get install -y curl && \
curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \
apt-get install -y nodejs
WORKDIR /app
COPY . .
RUN ./gradlew clean build
# Stage 2: Final image
FROM adoptopenjdk:11-jre-hotspot
RUN addgroup --system userapp && \
adduser -system --no-create-home --uid 1001 userapp --ingroup userapp
WORKDIR /app
COPY --from=builder /app /app
# Expose the application port
EXPOSE 8080
# Run the application
ENTRYPOINT ["java", "-jar", "/app/frontend.jar"]
I didn’t change the COPY instruction because I had no idea what it contained. In your version you copy only a single jar file not the whole /app folder. You could do that with “my version” as well, which was basically your version as I didn’t change anything in the last stage and that is the only stage which had the COPY instruction.
So the choice is yours. If you think the code you shared is not elegant, you can just change the COPY instruction in the other code I shared.