Skip to content

Conversation

@kwon204
Copy link
Contributor

@kwon204 kwon204 commented Feb 5, 2025

#️⃣ 연관된 이슈>

📝 작업 내용> 이번 PR에서 작업한 내용을 간략히 설명해주세요(이미지 첨부 가능)

로컬에서 백엔드 api 테스트를 할 수 있는 환경을 만들었습니다.

🙏 여기는 꼭 봐주세요! > 리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요

Summary by CodeRabbit

  • Chores

    • Updated configuration to ensure unnecessary system files are ignored.
  • New Features

    • Introduced a containerized development environment with integrated MySQL database and API services.
    • Added automation script for setting up and running the backend service.
    • Included a script to check the availability of services before starting the application.

@kwon204 kwon204 added the 🛠️ BE Backend label Feb 5, 2025
@kwon204 kwon204 added this to the 1차 스프린트 milestone Feb 5, 2025
@kwon204 kwon204 requested a review from efdao as a code owner February 5, 2025 05:46
@coderabbitai
Copy link

coderabbitai bot commented Feb 5, 2025

Walkthrough

The changes reintroduce the .DS_Store entry in .gitignore and add new development environment files. A new Dockerfile is added in the backend to build a Java application container based on Amazon Corretto 17. Additionally, new orchestration scripts have been introduced—including a Docker Compose configuration for a MySQL database and API service, an automation shell script for building and running the application, and a script to wait until the database is ready. There are no modifications to the publicly exported entities.

Changes

File(s) Change Summary
.gitignore Re-added the .DS_Store ignore rule; note on missing newline at end.
backend/Dockerfile.dev New Dockerfile for the development environment; sets base image to Amazon Corretto 17, copies the JAR file and wait-for-it.sh, and defines the container entry point.
script/docker-compose-dev.yml, script/setup_and_run.sh, script/wait-for-it.sh New orchestration and automation scripts: Docker Compose for MySQL (db) and backend API (api) services, a shell script to build and run containers, and a TCP readiness check script.

Sequence Diagram(s)

sequenceDiagram
    participant Dev as Developer
    participant Setup as setup_and_run.sh
    participant Gradle as Gradle Build
    participant Image as Docker Image Build
    participant Compose as docker-compose
    participant DB as MySQL Container (db)
    participant API as API Container
    participant Wait as wait-for-it.sh

    Dev->>Setup: Execute setup_and_run.sh
    Setup->>Gradle: Run Gradle build
    Gradle-->>Setup: Build successful
    Setup->>Image: Build Docker image using Dockerfile.dev
    Image-->>Setup: Image built
    Setup->>Compose: Start services with docker-compose
    Compose->>DB: Launch MySQL container (db)
    Compose->>API: Launch API container
    API->>Wait: Invoke wait-for-it.sh to check DB readiness
    Wait->>DB: Check connection on port 3306
    DB-->>Wait: Connection established
    Wait-->>API: Signal readiness and start Java application
Loading

Poem

I hopped through code with nimble feet,
Containers and scripts, oh what a treat!
Gradle builds and Docker whirls,
MySQL and API in twirls.
With a gentle nudge and a bashy beat,
This rabbit celebrates change so sweet! 🐰🎉

Tip

🌐 Web search-backed reviews and chat
  • We have enabled web search-based reviews and chat for all users. This feature allows CodeRabbit to access the latest documentation and information on the web.
  • You can disable this feature by setting web_search: false in the knowledge_base settings.
  • Please share any feedback in the Discord discussion.

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
script/setup_and_run.sh (1)

31-43: Container Cleanup and Conflict Prevention

The script checks for existing containers by name and removes them if found. This proactive cleanup avoids potential conflicts when starting new instances. Optionally, additional error handling/logging can help troubleshoot removal failures.

script/wait-for-it.sh (2)

70-132: Comprehensive Argument Parsing

The argument parsing loop robustly handles different input formats (e.g., host:port, flags, and long option formats). It correctly assigns values to variables like WAITFORIT_HOST, WAITFORIT_PORT, and others.
Note:
For the case handling arguments in lines 74–75, using array substitution may risk word splitting. Consider refactoring as follows for added robustness:

- WAITFORIT_hostport=(${1//:/ })
+ IFS=':' read -ra WAITFORIT_hostport <<< "$1"

[shellcheck]

🧰 Tools
🪛 Shellcheck (0.10.0)

[warning] 75-75: Quote to prevent word splitting/globbing, or split robustly with mapfile or read -a.

(SC2206)


174-183: Subcommand Execution and Array Expansion Caution

Before executing a subcommand, the script checks if WAITFORIT_CLI is set. Note that expanding an array without an index (as in the condition on line 174) only evaluates its first element. It is more robust to check the array length as follows:

- if [[ $WAITFORIT_CLI != "" ]]; then
+ if [ ${#WAITFORIT_CLI[@]} -gt 0 ]; then

Then, executing the subcommand using exec "${WAITFORIT_CLI[@]}" is correct.
[shellcheck]

🧰 Tools
🪛 Shellcheck (0.10.0)

[warning] 174-174: Expanding an array without an index only gives the first element.

(SC2128)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 870c9a9 and ea7bf74.

📒 Files selected for processing (5)
  • .gitignore (1 hunks)
  • backend/Dockerfile.dev (1 hunks)
  • script/docker-compose-dev.yml (1 hunks)
  • script/setup_and_run.sh (1 hunks)
  • script/wait-for-it.sh (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🧰 Additional context used
🪛 Shellcheck (0.10.0)
script/setup_and_run.sh

[warning] 10-10: JAR_FILE appears unused. Verify use (or export if used externally).

(SC2034)

script/wait-for-it.sh

[warning] 61-61: Use single quotes, otherwise this expands now rather than when signalled.

(SC2064)


[warning] 75-75: Quote to prevent word splitting/globbing, or split robustly with mapfile or read -a.

(SC2206)


[error] 153-153: This redirection overrides the output pipe. Use 'tee' to output to both.

(SC2260)


[warning] 174-174: Expanding an array without an index only gives the first element.

(SC2128)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Send PR Notification to Reviewers
🔇 Additional comments (12)
backend/Dockerfile.dev (2)

1-9: Base Image and Build Setup

The Dockerfile correctly starts with amazoncorretto:17 and sets up the build context using an argument for the JAR file, working directory, and file copies. Ensure that the build context (especially the JAR file location and the script/wait-for-it.sh relative path) is correct when running the build.


10-11: ENTRYPOINT and Service Readiness Handling

The ENTRYPOINT command leverages the wait-for-it.sh script to pause container start-up until the database at db:3306 is ready. Consider adding an EXPOSE 8080 instruction to document the service port if desired.

script/docker-compose-dev.yml (2)

1-17: Database Service Configuration

The MySQL service is well configured for a development environment with proper environment variables, port mapping (exposing container port 3306 externally as 3307), character-set, and collation settings. For production, consider externalizing credentials.


18-30: API Service Configuration and Dependency

The API service correctly depends on the db service and sets the JDBC URL along with other environment variables for database connectivity. This clear separation fosters reliable inter-service communication. Ensure that any sensitive credentials are managed securely for production.

script/setup_and_run.sh (4)

1-12: Environment Setup and Variable Definitions

Directory paths and variable definitions (such as IMAGE_NAME, IMAGE_TAG, JAR_FILE, and DOCKERFILE) are clear and help manage the build context effectively.

🧰 Tools
🪛 Shellcheck (0.10.0)

[warning] 10-10: JAR_FILE appears unused. Verify use (or export if used externally).

(SC2034)


13-19: Gradle Build Process Execution

The script properly ensures the Gradle wrapper is executable and then invokes a clean build. This guarantees that the latest code is compiled before Docker image construction.


28-29: Returning to the Original Script Directory

Changing back to the original directory before executing Docker Compose is a good practice to avoid path confusion.


45-46: Executing Docker Compose

The final Docker Compose command starts the backend API and MySQL containers in detached mode, and a confirmation message is clearly logged.

script/wait-for-it.sh (4)

1-7: Script Initialization and Utility Functions

The shebang (#!/usr/bin/env bash) and initial helper functions (echoerr and usage) are implemented correctly and provide clear error handling and usage messaging.


25-49: Efficient Wait Function Implementation

The wait_for function correctly implements a connection check using either nc (netcat) or a direct TCP connection attempt via /dev/tcp. Timing information logged via timestamps aids in debugging wait durations.


139-143: Default Value Assignment

The use of default values for WAITFORIT_TIMEOUT, WAITFORIT_STRICT, and WAITFORIT_QUIET ensures that the script behaves predictably even if optional arguments are not provided.


160-171: Child Process and Wait Logic

The conditional handling for when the script runs as a child process versus as the main process is structured clearly, ensuring that the wait is performed correctly and the script exits with the appropriate code.

Comment on lines +20 to +24
echo "${IMAGE_NAME}/${IMAGE_TAG} 이미지를 빌드 중..."

docker build --build-arg --no-cache -f "${DOCKERFILE}" -t "${IMAGE_NAME}:${IMAGE_TAG}" "${BASE_DIR}"

echo "도커 이미지 빌드 완료"
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Missing Build Argument in Docker Build Command

The docker build command currently includes --build-arg without a key–value pair, which means the intended build argument (likely to pass JAR_FILE) isn’t actually provided. If the goal is to pass the JAR_FILE variable to the Docker build, update the command as follows:

-docker build --build-arg --no-cache -f "${DOCKERFILE}" -t "${IMAGE_NAME}:${IMAGE_TAG}" "${BASE_DIR}"
+docker build --no-cache --build-arg JAR_FILE="${JAR_FILE}" -f "${DOCKERFILE}" -t "${IMAGE_NAME}:${IMAGE_TAG}" "${BASE_DIR}"
📝 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
echo "${IMAGE_NAME}/${IMAGE_TAG} 이미지를 빌드 중..."
docker build --build-arg --no-cache -f "${DOCKERFILE}" -t "${IMAGE_NAME}:${IMAGE_TAG}" "${BASE_DIR}"
echo "도커 이미지 빌드 완료"
echo "${IMAGE_NAME}/${IMAGE_TAG} 이미지를 빌드 중..."
docker build --no-cache --build-arg JAR_FILE="${JAR_FILE}" -f "${DOCKERFILE}" -t "${IMAGE_NAME}:${IMAGE_TAG}" "${BASE_DIR}"
echo "도커 이미지 빌드 완료"

Comment on lines +52 to +68
wait_for_wrapper()
{
# In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
if [[ $WAITFORIT_QUIET -eq 1 ]]; then
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
else
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
fi
WAITFORIT_PID=$!
trap "kill -INT -$WAITFORIT_PID" INT
wait $WAITFORIT_PID
WAITFORIT_RESULT=$?
if [[ $WAITFORIT_RESULT -ne 0 ]]; then
echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
fi
return $WAITFORIT_RESULT
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Timeout Handling with Wait Wrapper

The wait_for_wrapper function uses the timeout command to ensure graceful termination if the wait exceeds the defined timeout.
Important:
Line 61 uses a trap command that presently expands variables immediately. To ensure the variable is expanded only when the signal is received, change line 61 to use single quotes:

-trap "kill -INT -$WAITFORIT_PID" INT
+trap 'kill -INT -$WAITFORIT_PID' INT

[shellcheck]

📝 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
wait_for_wrapper()
{
# In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
if [[ $WAITFORIT_QUIET -eq 1 ]]; then
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
else
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
fi
WAITFORIT_PID=$!
trap "kill -INT -$WAITFORIT_PID" INT
wait $WAITFORIT_PID
WAITFORIT_RESULT=$?
if [[ $WAITFORIT_RESULT -ne 0 ]]; then
echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
fi
return $WAITFORIT_RESULT
}
wait_for_wrapper()
{
# In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
if [[ $WAITFORIT_QUIET -eq 1 ]]; then
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
else
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
fi
WAITFORIT_PID=$!
- trap "kill -INT -$WAITFORIT_PID" INT
+ trap 'kill -INT -$WAITFORIT_PID' INT
wait $WAITFORIT_PID
WAITFORIT_RESULT=$?
if [[ $WAITFORIT_RESULT -ne 0 ]]; then
echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
fi
return $WAITFORIT_RESULT
}
🧰 Tools
🪛 Shellcheck (0.10.0)

[warning] 61-61: Use single quotes, otherwise this expands now rather than when signalled.

(SC2064)

Comment on lines +145 to +158
WAITFORIT_TIMEOUT_PATH=$(type -p timeout)
WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH)

WAITFORIT_BUSYTIMEFLAG=""
if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then
WAITFORIT_ISBUSY=1
# Check if busybox timeout uses -t flag
# (recent Alpine versions don't support -t anymore)
if timeout &>/dev/stdout | grep -q -e '-t '; then
WAITFORIT_BUSYTIMEFLAG="-t"
fi
else
WAITFORIT_ISBUSY=0
fi
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Busybox Timeout Detection

The script determines whether the available timeout command is from busybox, adjusting flags accordingly.
Note:
On line 153, the redirection &>/dev/stdout combined with piping to grep may not work as intended since the redirection overrides the pipe’s input. Consider capturing the output first or using tee:

- if timeout &>/dev/stdout | grep -q -e '-t '; then
+ if timeout --help 2>&1 | tee /dev/null | grep -q -e '-t '; then

[shellcheck]

📝 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
WAITFORIT_TIMEOUT_PATH=$(type -p timeout)
WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH)
WAITFORIT_BUSYTIMEFLAG=""
if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then
WAITFORIT_ISBUSY=1
# Check if busybox timeout uses -t flag
# (recent Alpine versions don't support -t anymore)
if timeout &>/dev/stdout | grep -q -e '-t '; then
WAITFORIT_BUSYTIMEFLAG="-t"
fi
else
WAITFORIT_ISBUSY=0
fi
WAITFORIT_TIMEOUT_PATH=$(type -p timeout)
WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH)
WAITFORIT_BUSYTIMEFLAG=""
if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then
WAITFORIT_ISBUSY=1
# Check if busybox timeout uses -t flag
# (recent Alpine versions don't support -t anymore)
- if timeout &>/dev/stdout | grep -q -e '-t '; then
+ if timeout --help 2>&1 | tee /dev/null | grep -q -e '-t '; then
WAITFORIT_BUSYTIMEFLAG="-t"
fi
else
WAITFORIT_ISBUSY=0
fi
🧰 Tools
🪛 Shellcheck (0.10.0)

[error] 153-153: This redirection overrides the output pipe. Use 'tee' to output to both.

(SC2260)

Copy link
Collaborator

@efdao efdao left a comment

Choose a reason for hiding this comment

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

고생하셨습니다.

@kwon204 kwon204 closed this Feb 6, 2025
@kwon204 kwon204 reopened this Feb 6, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
backend/Dockerfile.dev (1)

12-12: Configuring the Entry Point
The ENTRYPOINT is set to run the wait-for-it.sh script which blocks until the database at db:3306 becomes available before launching the Java application with the specified Spring profile and timezone settings. For increased flexibility in different deployment environments, consider making the database host and port configurable via environment variables.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ea7bf74 and 5511c6c.

📒 Files selected for processing (1)
  • backend/Dockerfile.dev (1 hunks)
🔇 Additional comments (7)
backend/Dockerfile.dev (7)

1-1: Base Image Selection
The base image amazoncorretto:17-alpine is a good choice for a lightweight Java environment. For reproducible builds, consider further pinning the image if necessary.


3-3: Parameterized JAR File Path
Using the ARG instruction for JAR_FILE enables flexible configuration at build time, which is especially useful when the build artifact location may change.


4-4: Bash Installation
The use of apk add --no-cache bash is appropriate to ensure the container has Bash installed, with the --no-cache option keeping the image lean.


6-6: Working Directory Setup
Setting the working directory with WORKDIR /app is a best practice that ensures all subsequent commands execute in the correct directory.


8-8: Copying Application JAR
Copying the JAR file using the build argument ${JAR_FILE} and renaming it to app.jar is flexible. Please verify that the intended JAR file exists in the build context when executing the build.


9-9: Copying Wait-for-it Script
Copying the wait-for-it.sh script into /app/config/ ensures the necessary script is available within the container. Double-check the relative path from your Docker build context to avoid path issues.


10-10: Granting Execution Permissions
Applying chmod +x to /app/config/wait-for-it.sh guarantees that the script will run as intended during container startup.

@kwon204 kwon204 merged commit 19daa9a into dev Feb 6, 2025
1 check passed
@kwon204 kwon204 deleted the feature/be/dockerfile branch February 6, 2025 02:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🛠️ BE Backend

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants