Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Build stage
FROM gradle:8.5-jdk17 AS builder

WORKDIR /app

# Copy gradle files
COPY server/build.gradle server/settings.gradle server/gradlew ./
COPY server/gradle ./gradle

# Copy source code
COPY server/src ./src

# Make gradlew executable
RUN chmod +x ./gradlew

# Build the application
RUN ./gradlew bootJar --no-daemon

# Runtime stage
FROM eclipse-temurin:17-jre

WORKDIR /app

# Copy the built jar from builder stage
COPY --from=builder /app/build/libs/*.jar app.jar
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find and display build.gradle to check for plain JAR configuration
fd build.gradle -type f --exec cat {}

Repository: OneBiteArticle/oba_backend

Length of output: 240


🏁 Script executed:

#!/bin/bash
# Find and display Dockerfile to verify the COPY command on line 25
fd Dockerfile -type f --exec cat -n {}

Repository: OneBiteArticle/oba_backend

Length of output: 240


🏁 Script executed:

#!/bin/bash
# Check for Spring Boot gradle plugin configuration and JAR settings
fd -e gradle -type f --exec grep -l "bootJar\|plain.*jar\|jar.*enabled" {} \;

Repository: OneBiteArticle/oba_backend

Length of output: 240


🏁 Script executed:

#!/bin/bash
# Find build.gradle files
fd build.gradle

Repository: OneBiteArticle/oba_backend

Length of output: 89


🏁 Script executed:

#!/bin/bash
# Find Dockerfile
fd Dockerfile

Repository: OneBiteArticle/oba_backend

Length of output: 80


🏁 Script executed:

#!/bin/bash
# Display Dockerfile with line numbers
cat -n Dockerfile

Repository: OneBiteArticle/oba_backend

Length of output: 802


🏁 Script executed:

#!/bin/bash
# Display server/build.gradle to check jar configuration
cat -n server/build.gradle

Repository: OneBiteArticle/oba_backend

Length of output: 2037


🌐 Web query:

Spring Boot gradle plugin plain jar generation default behavior

💡 Result:

  • Spring Boot Gradle plugin (Spring Boot ≤ 2.4.x): when bootJar is configured, the plugin disables the standard jar task by default, so a “plain” jar is not produced unless you re-enable jar. [1]
  • Spring Boot Gradle plugin (Spring Boot ≥ 2.5.0 and still in Spring Boot 3.x): the plugin leaves jar enabled, but configures it as a separate “plain” artifact by giving it the default classifier plain (so you typically get app-plain.jar alongside the executable bootJar). You can disable the plain jar by disabling jar, or change classifiers if you don’t want the plain suffix. [2][3]

Common knobs

  • Don’t build the plain jar: tasks.named("jar") { enabled = false } [3]
  • Don’t use the plain classifier (so the plain jar is just app.jar): set archiveClassifier = "" on jar (and optionally move a classifier to bootJar). [2][3]

Sources: Spring Boot Gradle Plugin reference (2.4) for “jar disabled by default”; Spring Boot Gradle Plugin reference (2.5 / 3.x) for “plain archive” behavior and how to disable or reclassify. [1][2][3]


🌐 Web query:

Docker COPY command multiple files wildcard pattern behavior

💡 Result:

  • Wildcards are expanded by the Docker builder (not your shell), and each <src> in COPY <src>... <dest> may include wildcards matched using Go’s filepath.Match rules (e.g. *, ?, []). This is relative to the build context. [1]
  • If a wildcard (or multiple explicit sources) resolves to more than one source, then <dest> must be a directory and must end with / (e.g. COPY *.png /dest/). [1]
  • For a single file source, if <dest> ends with /, Docker treats it as a directory and writes the file as <dest>/<basename(src)> (i.e., it uses the source file’s basename). [1]
  • For a directory source, Docker copies the directory contents (not the directory entry itself). Subdirectories are copied/merged into the destination. [1]
  • Builder implementations can differ (e.g., Docker vs Buildah/other tools) in edge cases like enforcing the “dest must end with /” rule, so the same Dockerfile can behave differently across builders. [2]
  • If you need to preserve parent directories when copying matched files, BuildKit’s newer Dockerfile features support COPY --parents ..., including examples using wildcards (and even ** in that mode). [3]

Sources:
[1] Dockerfile reference (COPY / pattern matching / multi-source dest rules) — Docker Docs (docs.docker.com)
[2] Buildah issue discussing divergence from Docker’s trailing-slash rule for multi-source COPY (github.com)
[3] Docker blog: Dockerfile v1.7.0 capabilities (COPY --parents, wildcards, **) (docker.com)

Citations:


Docker 빌드 실패: 와일드카드로 인한 다중 JAR 매칭 문제

Spring Boot 3.5.4에서는 기본적으로 bootJar 외에도 *-plain.jar 파일을 생성합니다. COPY --from=builder /app/build/libs/*.jar app.jar 명령은 두 개의 JAR 파일과 매칭되는데, 목적지(app.jar)가 디렉토리가 아니므로 Docker 빌드가 실패합니다.

server/build.gradle에 다음을 추가하여 plain JAR 생성을 비활성화하거나, Dockerfile의 경로를 더 구체적으로 지정하세요:

♻️ build.gradle에 plain JAR 비활성화 추가
tasks.named('jar') {
    enabled = false
}
🤖 Prompt for AI Agents
In `@Dockerfile` at line 25, The Dockerfile COPY uses a wildcard that matches
multiple JARs (COPY --from=builder /app/build/libs/*.jar app.jar) causing the
build to fail; fix by either disabling the plain jar in the Gradle build (add
tasks.named('jar') { enabled = false } to server/build.gradle so only the
bootJar remains) or by making the Dockerfile copy a single, explicit artifact
(replace the wildcard with the exact boot JAR filename or a pattern that matches
only the boot JAR). Ensure the Docker COPY references the single artifact
produced by bootJar to avoid multiple-match errors.


EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app.jar"]
Comment on lines +20 to +29
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

컨테이너가 root 사용자로 실행됩니다

런타임 스테이지에서 non-root 사용자를 지정하지 않아 컨테이너가 root로 실행됩니다. 컨테이너 탈출 취약점 발생 시 호스트에 대한 권한 상승 위험이 있습니다.

🔒 non-root 사용자 추가 제안
 FROM eclipse-temurin:17-jre
 
 WORKDIR /app
 
+RUN addgroup --system appgroup && adduser --system --ingroup appgroup appuser
+
 # Copy the built jar from builder stage
 COPY --from=builder /app/build/libs/*.jar app.jar
 
+USER appuser
+
 EXPOSE 8080
 
 ENTRYPOINT ["java", "-jar", "app.jar"]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
FROM eclipse-temurin:17-jre
WORKDIR /app
# Copy the built jar from builder stage
COPY --from=builder /app/build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
FROM eclipse-temurin:17-jre
WORKDIR /app
RUN addgroup --system appgroup && adduser --system --ingroup appgroup appuser
# Copy the built jar from builder stage
COPY --from=builder /app/build/libs/*.jar app.jar
USER appuser
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
🤖 Prompt for AI Agents
In `@Dockerfile` around lines 20 - 29, 런타임 Dockerfile이 현재 root로 컨테이너를 실행하므로 권한 상승
위험이 있으니 non-root 사용자로 실행되도록 수정하세요: 런타임 stage에 그룹/사용자(예: appuser, uid 1000)를 생성하고
WORKDIR /app 및 복사된 app.jar에 대해 소유권을 해당 사용자로 chown 한 뒤 ENTRYPOINT 실행 전에 USER
appuser를 설정해 컨테이너가 root가 아닌 appuser로 시작되도록 하십시오 (참고 대상 토큰: WORKDIR, COPY
--from=builder ..., app.jar, ENTRYPOINT, USER).