Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
5 changes: 4 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ logs
**/application-prod.yml
**/application-dev.yml
**/application-local.yml
**/application-*.yml
**/application-*.yml

!build/libs
!build/libs/*.jar
73 changes: 73 additions & 0 deletions .github/workflows/cd-dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: CD [Development]

on:
push:
branches:
- develop
paths:
- 'src/**'
- 'build.gradle.kts'
- 'docker/**'
- 'cd.yml'
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

워크플로우 파일 경로가 잘못되었습니다.

Line 11에서 cd.yml을 참조하고 있지만, 실제 파일명은 cd-dev.yml입니다. 이로 인해 워크플로우 파일 변경 시 자동 배포가 트리거되지 않습니다.

🔧 제안하는 수정안
     paths:
       - 'src/**'
       - 'build.gradle.kts'
       - 'docker/**'
-      - 'cd.yml'
+      - '.github/workflows/cd-dev.yml'
🤖 Prompt for AI Agents
In @.github/workflows/cd-dev.yml around lines 7 - 11, The workflow currently
references 'cd.yml' in the paths list which is incorrect; update the paths array
in .github/workflows/cd-dev.yml to replace 'cd.yml' with the actual filename
'cd-dev.yml' so changes to the deployment workflow trigger correctly (edit the
entry that currently reads 'cd.yml' to 'cd-dev.yml').


workflow_dispatch:
inputs:
environment:
description: 'Deploy environment'
required: true
type: choice
options:
- dev
- prod

jobs:
# 1. 공통 빌드/테스트 워크플로우 호출 (ci.yml 재사용)
ci-and-build:
uses: ./.github/workflows/ci.yml
with:
environment: ${{ inputs.environment }}
secrets: inherit

# 2. Deploy Job
deploy:
needs: ci-and-build
runs-on: ubuntu-latest
# 빌드 단계에서 결정된 환경 사용
environment: ${{ needs.ci-and-build.outputs.environment }}

env:
ENVIRONMENT: ${{ needs.ci-and-build.outputs.environment }}
REPO_OWNER: ${{ needs.ci-and-build.outputs.repo_owner }}
IMAGE_TAG: ${{ needs.ci-and-build.outputs.image_tag }}

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: SSH 접속 및 스크립트 실행
uses: appleboy/ssh-action@v1
env:
APPLICATION_PROD: ${{ secrets.APPLICATION_PROD }}
APPLICATION_DEV: ${{ secrets.APPLICATION_DEV }}
APPLICATION_SECRET: ${{ secrets.APPLICATION_SECRET }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
with:
host: ${{ secrets.SERVER_SSH_HOST }}
username: ${{ secrets.SERVER_SSH_USERNAME }}
key: ${{ secrets.SERVER_SSH_PRIVATE_KEY }}
port: ${{ secrets.SERVER_SSH_PORT }}
envs: APPLICATION_PROD,APPLICATION_DEV,APPLICATION_SECRET,ENVIRONMENT,IMAGE_TAG,REPO_OWNER,DOCKER_IMAGE_NAME,DOCKERHUB_TOKEN,DOCKERHUB_USERNAME
script_path: scripts/cd-dev.sh

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

필수 환경 변수가 누락되었습니다.

Line 59의 envs 목록에 APP_DIR_PRODUCTIONAPP_DIR_DEVELOPMENT가 포함되어 있지 않습니다. 배포 스크립트(cd-dev.sh)는 이 변수들을 필수로 검증하므로(lines 16-17), 없으면 배포가 실패합니다.

🐛 제안하는 수정안
       - name: SSH 접속 및 스크립트 실행
         uses: appleboy/ssh-action@v1
         env:
           APPLICATION_PROD: ${{ secrets.APPLICATION_PROD }}
           APPLICATION_DEV: ${{ secrets.APPLICATION_DEV }}
           APPLICATION_SECRET: ${{ secrets.APPLICATION_SECRET }}
           DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
           DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
+          DOCKER_IMAGE_NAME: ${{ secrets.DOCKER_IMAGE_NAME }}
+          APP_DIR_PRODUCTION: ${{ secrets.APP_DIR_PRODUCTION }}
+          APP_DIR_DEVELOPMENT: ${{ secrets.APP_DIR_DEVELOPMENT }}
         with:
           host: ${{ secrets.SERVER_SSH_HOST }}
           username: ${{ secrets.SERVER_SSH_USERNAME }}
           key: ${{ secrets.SERVER_SSH_PRIVATE_KEY }}
           port: ${{ secrets.SERVER_SSH_PORT }}
-          envs: APPLICATION_PROD,APPLICATION_DEV,APPLICATION_SECRET,ENVIRONMENT,IMAGE_TAG,REPO_OWNER,DOCKER_IMAGE_NAME,DOCKERHUB_TOKEN,DOCKERHUB_USERNAME
+          envs: APPLICATION_PROD,APPLICATION_DEV,APPLICATION_SECRET,ENVIRONMENT,IMAGE_TAG,REPO_OWNER,DOCKER_IMAGE_NAME,DOCKERHUB_TOKEN,DOCKERHUB_USERNAME,APP_DIR_PRODUCTION,APP_DIR_DEVELOPMENT
           script_path: scripts/cd-dev.sh
📝 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
- name: SSH 접속 및 스크립트 실행
uses: appleboy/ssh-action@v1
env:
APPLICATION_PROD: ${{ secrets.APPLICATION_PROD }}
APPLICATION_DEV: ${{ secrets.APPLICATION_DEV }}
APPLICATION_SECRET: ${{ secrets.APPLICATION_SECRET }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
with:
host: ${{ secrets.SERVER_SSH_HOST }}
username: ${{ secrets.SERVER_SSH_USERNAME }}
key: ${{ secrets.SERVER_SSH_PRIVATE_KEY }}
port: ${{ secrets.SERVER_SSH_PORT }}
envs: APPLICATION_PROD,APPLICATION_DEV,APPLICATION_SECRET,ENVIRONMENT,IMAGE_TAG,REPO_OWNER,DOCKER_IMAGE_NAME,DOCKERHUB_TOKEN,DOCKERHUB_USERNAME
script_path: scripts/cd-dev.sh
- name: SSH 접속 및 스크립트 실행
uses: appleboy/ssh-action@v1
env:
APPLICATION_PROD: ${{ secrets.APPLICATION_PROD }}
APPLICATION_DEV: ${{ secrets.APPLICATION_DEV }}
APPLICATION_SECRET: ${{ secrets.APPLICATION_SECRET }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKER_IMAGE_NAME: ${{ secrets.DOCKER_IMAGE_NAME }}
APP_DIR_PRODUCTION: ${{ secrets.APP_DIR_PRODUCTION }}
APP_DIR_DEVELOPMENT: ${{ secrets.APP_DIR_DEVELOPMENT }}
with:
host: ${{ secrets.SERVER_SSH_HOST }}
username: ${{ secrets.SERVER_SSH_USERNAME }}
key: ${{ secrets.SERVER_SSH_PRIVATE_KEY }}
port: ${{ secrets.SERVER_SSH_PORT }}
envs: APPLICATION_PROD,APPLICATION_DEV,APPLICATION_SECRET,ENVIRONMENT,IMAGE_TAG,REPO_OWNER,DOCKER_IMAGE_NAME,DOCKERHUB_TOKEN,DOCKERHUB_USERNAME,APP_DIR_PRODUCTION,APP_DIR_DEVELOPMENT
script_path: scripts/cd-dev.sh
🤖 Prompt for AI Agents
In @.github/workflows/cd-dev.yml around lines 46 - 61, Add the missing
APP_DIR_PRODUCTION and APP_DIR_DEVELOPMENT environment variables to the SSH
action: define them in the env: block (e.g., APP_DIR_PRODUCTION: ${{
secrets.APP_DIR_PRODUCTION }} and APP_DIR_DEVELOPMENT: ${{
secrets.APP_DIR_DEVELOPMENT }}) and include their names in the with: envs
comma-separated list (alongside APPLICATION_PROD,APPLICATION_DEV,...). This
ensures the deployment script referenced by script_path: cd-dev.sh receives the
required APP_DIR_PRODUCTION and APP_DIR_DEVELOPMENT values that it validates.

Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

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

P3: SSH 액션의 script_path 속성은 로컬 파일 경로를 원격 서버로 전송하는 용도입니다. 그러나 현재 구조에서는 scripts/cd-dev.sh 파일이 원격 서버에 존재해야 하는데, 이 파일을 원격 서버로 전송하는 단계가 없습니다.

다음 두 가지 방법 중 하나를 선택해야 합니다:

  1. script 속성을 사용하여 스크립트 내용을 직접 전달
  2. 또는 scp/rsync로 스크립트를 먼저 전송한 후 실행

script 속성 사용 예시:

script: |
  bash << 'EOF'
  $(cat scripts/cd-dev.sh의 내용)
  EOF
Suggested change
script_path: scripts/cd-dev.sh
script: |
bash << 'EOF'
# scripts/cd-dev.sh의 내용을 여기에 그대로 붙여넣습니다.
# 예: 기존 scripts/cd-dev.sh 파일의 모든 쉘 명령들
EOF

Copilot uses AI. Check for mistakes.
- name: Deployment Summary
if: always()
run: |
echo "### Deployment Summary :rocket:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Environment:** ${{ env.ENVIRONMENT }}" >> $GITHUB_STEP_SUMMARY
echo "- **Branch:** ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
echo "- **Commit:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
echo "- **Image:** ${{ secrets.DOCKER_IMAGE_NAME }}:${{ env.ENVIRONMENT }}-latest" >> $GITHUB_STEP_SUMMARY
echo "- **Server:** ${{ secrets.SERVER_SSH_HOST }}" >> $GITHUB_STEP_SUMMARY
echo "- **Status:** ${{ job.status }}" >> $GITHUB_STEP_SUMMARY
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Shellcheck 스타일 경고를 개선할 수 있습니다.

Deployment Summary 스크립트에서 여러 개의 echo 명령이 같은 파일로 리다이렉션됩니다. 이를 하나의 블록으로 묶으면 더 효율적이고 가독성이 좋아집니다.

♻️ 제안 수정사항
       - name: Deployment Summary
         if: always()
         run: |
-          echo "### Deployment Summary :rocket:" >> $GITHUB_STEP_SUMMARY
-          echo "" >> $GITHUB_STEP_SUMMARY
-          echo "- **Environment:** ${{ env.ENVIRONMENT }}" >> $GITHUB_STEP_SUMMARY
-          echo "- **Branch:** ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
-          echo "- **Commit:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
-          echo "- **Image:** ${{ secrets.DOCKER_IMAGE_NAME }}:${{ env.ENVIRONMENT }}-latest" >> $GITHUB_STEP_SUMMARY
-          echo "- **Server:** ${{ secrets.SERVER_SSH_HOST }}" >> $GITHUB_STEP_SUMMARY
-          echo "- **Status:** ${{ job.status }}" >> $GITHUB_STEP_SUMMARY
+          {
+            echo "### Deployment Summary :rocket:"
+            echo ""
+            echo "- **Environment:** ${{ env.ENVIRONMENT }}"
+            echo "- **Branch:** ${{ github.ref_name }}"
+            echo "- **Commit:** ${{ github.sha }}"
+            echo "- **Image:** ${{ secrets.DOCKER_IMAGE_NAME }}:${{ env.ENVIRONMENT }}-latest"
+            echo "- **Server:** ${{ secrets.SERVER_SSH_HOST }}"
+            echo "- **Status:** ${{ job.status }}"
+          } >> "$GITHUB_STEP_SUMMARY"
🧰 Tools
🪛 actionlint (1.7.10)

65-65: shellcheck reported issue in this script: SC2086:info:1:43: Double quote to prevent globbing and word splitting

(shellcheck)


65-65: shellcheck reported issue in this script: SC2086:info:2:12: Double quote to prevent globbing and word splitting

(shellcheck)


65-65: shellcheck reported issue in this script: SC2086:info:3:53: Double quote to prevent globbing and word splitting

(shellcheck)


65-65: shellcheck reported issue in this script: SC2086:info:4:48: Double quote to prevent globbing and word splitting

(shellcheck)


65-65: shellcheck reported issue in this script: SC2086:info:5:43: Double quote to prevent globbing and word splitting

(shellcheck)


65-65: shellcheck reported issue in this script: SC2086:info:6:87: Double quote to prevent globbing and word splitting

(shellcheck)


65-65: shellcheck reported issue in this script: SC2086:info:7:56: Double quote to prevent globbing and word splitting

(shellcheck)


65-65: shellcheck reported issue in this script: SC2086:info:8:43: Double quote to prevent globbing and word splitting

(shellcheck)


65-65: shellcheck reported issue in this script: SC2129:style:1:1: Consider using { cmd1; cmd2; } >> file instead of individual redirects

(shellcheck)

🤖 Prompt for AI Agents
In @.github/workflows/cd-dev.yml around lines 65 - 73, Multiple sequential echo
statements appending to $GITHUB_STEP_SUMMARY are inefficient and trigger
shellcheck style warnings; replace the repeated echo lines with a single
here-document that appends the entire Deployment Summary to $GITHUB_STEP_SUMMARY
(use an unquoted heredoc like cat <<EOF >> $GITHUB_STEP_SUMMARY so environment
variables like ${env.ENVIRONMENT} and ${github.sha} expand) to improve
readability and reduce subprocess calls, keeping the same content and ordering
as the original echo lines.

190 changes: 190 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
name: CI

on:
pull_request:
branches:
- develop
- main

workflow_dispatch:
inputs:
environment:
description: 'Deploy environment'
required: true
type: choice
options:
- dev
- prod

workflow_call:
inputs:
environment:
description: 'Deploy environment (optional)'
required: false
type: string
outputs:
environment:
description: "Determined environment"
value: ${{ jobs.build-and-test.outputs.environment }}
repo_owner:
description: "Repository owner"
value: ${{ jobs.build-and-test.outputs.repo_owner }}
image_tag:
description: "Docker image tag"
value: ${{ jobs.build-and-test.outputs.image_tag }}

concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true # 이전 실행 취소

jobs:
# Job 1: 빌드 및 테스트 (한 번만 실행)
build-and-test:
runs-on: self-hosted

permissions:
contents: read
checks: write
pull-requests: write

outputs:
environment: ${{ steps.set-env.outputs.environment }}
repo_owner: ${{ steps.set-env.outputs.repo_owner }}
image_tag: ${{ steps.set-env.outputs.image_tag }}

# strategy:
# matrix:
# platform: [ linux/amd64, linux/arm64 ]
# include:
# - platform: linux/amd64
# tag-suffix: amd64
# - platform: linux/arm64
# tag-suffix: arm64
Comment on lines +55 to +62
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

주석 처리된 matrix 전략 코드를 제거하세요.

더 이상 사용하지 않는 matrix 전략 코드가 주석으로 남아있습니다. 혼란을 방지하기 위해 제거하는 것이 좋습니다. 현재의 멀티 플랫폼 빌드 방식이 더 효율적이고 적절합니다.

♻️ 제거 권장
-    #    strategy:
-    #      matrix:
-    #        platform: [ linux/amd64, linux/arm64 ]
-    #        include:
-    #          - platform: linux/amd64
-    #            tag-suffix: amd64
-    #          - platform: linux/arm64
-    #            tag-suffix: arm64
-
     steps:
📝 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
# strategy:
# matrix:
# platform: [ linux/amd64, linux/arm64 ]
# include:
# - platform: linux/amd64
# tag-suffix: amd64
# - platform: linux/arm64
# tag-suffix: arm64
steps:
🤖 Prompt for AI Agents
In @.github/workflows/ci.yml around lines 55 - 62, Remove the commented-out
matrix strategy block in .github/workflows/ci.yml (the commented lines
containing "strategy:", "matrix:", "platform:", and "tag-suffix:") so the file
no longer contains dead/commented multi-platform matrix configuration; simply
delete those commented lines to avoid confusion and keep the workflow focused on
the current multi-platform build approach.


steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set deployment environment
id: set-env
run: |
INPUT_ENV="${{ inputs.environment }}"
# PR일 때는 'test' 환경으로 설정
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
echo "Running in PR mode - Setting test environment for build"
ENVIRONMENT="test"
elif [[ -n "$INPUT_ENV" ]]; then
ENVIRONMENT="$INPUT_ENV"
# CD에서 호출한 경우 branch에 따라서 환경 결정
elif [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
ENVIRONMENT="prod"
elif [[ "${{ github.ref }}" == "refs/heads/develop" ]]; then
ENVIRONMENT="dev"
else
ENVIRONMENT="test"
fi
Comment on lines +77 to +87
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

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

P2: 환경 변수 검증 로직에 else 분기가 누락되어 있습니다. 조건문이 elif로만 연결되어 있어, 마지막 elif 조건도 만족하지 않을 경우 ENVIRONMENT 변수가 설정되지 않은 상태로 다음 단계로 진행될 수 있습니다.

마지막 elif를 else로 변경하거나, 조건문 이후에 ENVIRONMENT 변수 검증을 추가해야 합니다.

Copilot uses AI. Check for mistakes.
echo "environment=${ENVIRONMENT}" >> $GITHUB_OUTPUT
REPO_OWNER=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')
echo "repo_owner=${REPO_OWNER}" >> $GITHUB_OUTPUT
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
IMAGE_TAG="${ENVIRONMENT}-${SHORT_SHA}"
echo "image_tag=${IMAGE_TAG}" >> $GITHUB_OUTPUT
Comment on lines +68 to +96
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

환경 결정 로직에 else 절이 누락되었습니다.

Line 77-79의 조건문에 else 절이 없어, 특정 경우에 ENVIRONMENT 변수가 설정되지 않을 수 있습니다. Line 86의 else가 전체 if-elif 체인의 최종 else로 작동하므로 로직상 문제는 없지만, 가독성을 위해 구조를 명확히 하는 것이 좋습니다.

♻️ 제안하는 수정안
           # PR일 때는 'test' 환경으로 설정
           if [[ "${{ github.event_name }}" == "pull_request" ]]; then
             echo "Running in PR mode - Setting test environment for build"
             ENVIRONMENT="test"
           elif [[ -n "$INPUT_ENV" ]]; then
             ENVIRONMENT="$INPUT_ENV"
-          
-          # CD에서 호출한 경우 branch에 따라서 환경 결정
           elif [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
             ENVIRONMENT="prod"
           elif [[ "${{ github.ref }}" == "refs/heads/develop" ]]; then
             ENVIRONMENT="dev"
           else
             ENVIRONMENT="test"
           fi
🧰 Tools
🪛 actionlint (1.7.10)

70-70: shellcheck reported issue in this script: SC2086:info:19:38: Double quote to prevent globbing and word splitting

(shellcheck)


70-70: shellcheck reported issue in this script: SC2086:info:22:36: Double quote to prevent globbing and word splitting

(shellcheck)


70-70: shellcheck reported issue in this script: SC2086:info:26:34: Double quote to prevent globbing and word splitting

(shellcheck)

🤖 Prompt for AI Agents
In @.github/workflows/ci.yml around lines 68 - 96, The if/elif chain inside the
"set-env" step can leave ENVIRONMENT unset due to a missing else after the
INPUT_ENV check; ensure every branch sets ENVIRONMENT by adding an explicit else
or restructuring the conditionals so that when INPUT_ENV is empty the subsequent
branch checks (github.ref for main/develop) always run; update the logic around
INPUT_ENV, ENVIRONMENT and the github.event_name/github.ref checks so
ENVIRONMENT is always assigned before it's echoed to GITHUB_OUTPUT (refer to
variables INPUT_ENV, ENVIRONMENT, github.event_name, github.ref and the
"set-env" step).

- name: Setup JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'corretto'
cache: gradle

- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Compile Check
run: ./gradlew compileJava compileTestJava

- name: Run Tests
run: ./gradlew test

- name: Publish Test Results
uses: EnricoMi/publish-unit-test-result-action@v2
if: always()
with:
files: build/test-results/test/*.xml
check_name: "Backend Test Results"

- name: Build JAR
run: ./gradlew bootJar

- name: Check build artifacts
run: |
ls -la build/libs/
echo "Current directory: $(pwd)"
- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

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

P3: 두 개의 Dockerfile이 존재하는데 (docker/kyeoungwoon/dockerfile과 docker/app/dockerfile), 목적과 사용처가 명확하지 않습니다.

  • kyeoungwoon/dockerfile: CI에서 사용 (eclipse-temurin 기반)
  • app/dockerfile: 사용처 불명확 (amazoncorretto 기반)

하나의 Dockerfile만 유지하거나, 각 파일의 목적을 README나 주석으로 명확히 문서화해야 합니다. 또한 CI 워크플로우에서 docker/kyeoungwoon/dockerfile을 사용하는 이유를 설명하는 주석을 추가하는 것이 좋습니다.

Suggested change
context: .
context: .
# CI용 이미지 빌드를 위해 eclipse-temurin 기반 Dockerfile 사용
# (amazoncorretto 기반 docker/app/dockerfile은 런타임/기타 용도로 별도 관리)

Copilot uses AI. Check for mistakes.
file: docker/app/dockerfile
push: true
tags: |
${{ secrets.DOCKER_IMAGE_NAME }}:${{ steps.set-env.outputs.image_tag }}
${{ secrets.DOCKER_IMAGE_NAME }}:${{ steps.set-env.outputs.environment }}-latest
cache-from: type=gha
cache-to: type=gha,mode=max

# Job 3: Multi-arch manifest 생성
create-manifest:
needs: [ build-and-test ]
runs-on: self-hosted
steps:
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Create and push manifest
run: |
IMAGE_TAG="${{ needs.build-and-test.outputs.image_tag }}"
ENVIRONMENT="${{ needs.build-and-test.outputs.environment }}"
# 특정 커밋용 manifest 생성
docker buildx imagetools create -t ${{ secrets.DOCKER_IMAGE_NAME }}:${IMAGE_TAG} \
${{ secrets.DOCKER_IMAGE_NAME }}:${IMAGE_TAG}-amd64 \
${{ secrets.DOCKER_IMAGE_NAME }}:${IMAGE_TAG}-arm64
# 환경별 latest manifest 생성
docker buildx imagetools create -t ${{ secrets.DOCKER_IMAGE_NAME }}:${ENVIRONMENT}-latest \
${{ secrets.DOCKER_IMAGE_NAME }}:${IMAGE_TAG}-amd64 \
${{ secrets.DOCKER_IMAGE_NAME }}:${IMAGE_TAG}-arm64
echo "✅ Created manifests:"
echo " - ${{ secrets.DOCKER_IMAGE_NAME }}:${IMAGE_TAG}"
echo " - ${{ secrets.DOCKER_IMAGE_NAME }}:${ENVIRONMENT}-latest"
- name: Build Summary
if: always()
run: |
echo "### Build Summary :package:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Environment:** ${{ steps.set-env.outputs.environment }}" >> $GITHUB_STEP_SUMMARY
echo "- **Image Tag:** ${{ steps.set-env.outputs.image_tag }}" >> $GITHUB_STEP_SUMMARY
Comment on lines +159 to +160
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

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

P2: Build Summary 단계가 잘못된 위치에 있습니다. steps.set-env는 build-and-test job에 속하지만, 현재 이 단계는 create-manifest job에 있습니다. steps.set-env.outputs는 다른 job에서 접근할 수 없으므로 항상 빈 값이 출력됩니다.

needs를 통해 전달받은 값을 사용해야 합니다:

echo "- **Environment:** ${{ needs.build-and-test.outputs.environment }}" >> $GITHUB_STEP_SUMMARY
echo "- **Image Tag:** ${{ needs.build-and-test.outputs.image_tag }}" >> $GITHUB_STEP_SUMMARY
Suggested change
echo "- **Environment:** ${{ steps.set-env.outputs.environment }}" >> $GITHUB_STEP_SUMMARY
echo "- **Image Tag:** ${{ steps.set-env.outputs.image_tag }}" >> $GITHUB_STEP_SUMMARY
echo "- **Environment:** ${{ needs.build-and-test.outputs.environment }}" >> $GITHUB_STEP_SUMMARY
echo "- **Image Tag:** ${{ needs.build-and-test.outputs.image_tag }}" >> $GITHUB_STEP_SUMMARY

Copilot uses AI. Check for mistakes.
echo "- **Platforms:** linux/amd64, linux/arm64" >> $GITHUB_STEP_SUMMARY
Comment on lines +154 to +161
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

Build Summary 단계에서 존재하지 않는 step 출력을 참조하고 있습니다.

steps.set-env.outputs를 참조하고 있지만, create-manifest 잡에는 set-env라는 id를 가진 step이 없습니다. build-and-test 잡의 출력을 참조해야 합니다.

🔧 수정 방법 (create-manifest 잡을 유지하는 경우)
       - name: Build Summary
         if: always()
         run: |
           echo "### Build Summary :package:" >> $GITHUB_STEP_SUMMARY
           echo "" >> $GITHUB_STEP_SUMMARY
-          echo "- **Environment:** ${{ steps.set-env.outputs.environment }}" >> $GITHUB_STEP_SUMMARY
-          echo "- **Image Tag:** ${{ steps.set-env.outputs.image_tag }}" >> $GITHUB_STEP_SUMMARY
+          echo "- **Environment:** ${{ needs.build-and-test.outputs.environment }}" >> $GITHUB_STEP_SUMMARY
+          echo "- **Image Tag:** ${{ needs.build-and-test.outputs.image_tag }}" >> $GITHUB_STEP_SUMMARY
           echo "- **Platforms:** linux/amd64, linux/arm64" >> $GITHUB_STEP_SUMMARY

Static analysis 도구의 지적사항을 기반으로 함.

📝 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
- name: Build Summary
if: always()
run: |
echo "### Build Summary :package:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Environment:** ${{ steps.set-env.outputs.environment }}" >> $GITHUB_STEP_SUMMARY
echo "- **Image Tag:** ${{ steps.set-env.outputs.image_tag }}" >> $GITHUB_STEP_SUMMARY
echo "- **Platforms:** linux/amd64, linux/arm64" >> $GITHUB_STEP_SUMMARY
- name: Build Summary
if: always()
run: |
echo "### Build Summary :package:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Environment:** ${{ needs.build-and-test.outputs.environment }}" >> $GITHUB_STEP_SUMMARY
echo "- **Image Tag:** ${{ needs.build-and-test.outputs.image_tag }}" >> $GITHUB_STEP_SUMMARY
echo "- **Platforms:** linux/amd64, linux/arm64" >> $GITHUB_STEP_SUMMARY
🧰 Tools
🪛 actionlint (1.7.10)

186-186: property "set-env" is not defined in object type {}

(expression)

🤖 Prompt for AI Agents
In @.github/workflows/ci.yml around lines 184 - 191, The Build Summary step is
referencing nonexistent step outputs (steps.set-env.outputs.environment and
steps.set-env.outputs.image_tag); update the echo lines in the Build Summary
step to use the outputs from the build-and-test job instead
(needs.build-and-test.outputs.environment and
needs.build-and-test.outputs.image_tag), and ensure the create-manifest job
declares needs: build-and-test so those job outputs are available.

13 changes: 7 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ application-*.yml

.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/

### STS ###
.apt_generated
Expand All @@ -33,10 +30,8 @@ bin/
*.iml
*.ipr

!**/src/main/**/out/
!**/src/test/**/out/
# 빌드 결과물인 out은 무시해야 하나, 소스코드 내에 있는건 지켜야 함
/out/
out/

### NetBeans ###
/nbproject/private/
Expand Down Expand Up @@ -237,3 +232,9 @@ $RECYCLE.BIN/
*.lnk

# End of https://www.toptal.com/developers/gitignore/api/java,intellij+all,macos,windows,linux

!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
!**/src/main/**/out/
!**/src/test/**/out/
41 changes: 41 additions & 0 deletions docker/app/dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
FROM amazoncorretto:21-alpine
WORKDIR /app

LABEL maintainer="UMC PRODUCT SERVER TEAM"
LABEL description="UMC PRODUCT Official SpringBoot Backend Server"

# curl 설치 (헬스체크용) + non-root 유저 생성
RUN apk add --no-cache curl && \
addgroup -S spring && \
adduser -S spring -G spring && \
mkdir -p /app/logs && \
chown -R spring:spring /app
Comment on lines +8 to +12
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

패키지 버전 고정을 고려하세요.

curl 패키지가 버전 고정 없이 설치되고 있습니다. 빌드 재현성과 보안을 위해 특정 버전을 명시하는 것이 권장됩니다.

♻️ 제안하는 수정안
-RUN apk add --no-cache curl && \
+RUN apk add --no-cache curl=8.5.0-r0 && \
     addgroup -S spring && \
     adduser -S spring -G spring && \
     mkdir -p /app/logs && \
     chown -R spring:spring /app

참고: Alpine 버전에 따라 사용 가능한 curl 버전이 다를 수 있으므로 apk search curl 명령으로 확인 후 적절한 버전을 지정하세요.

📝 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
RUN apk add --no-cache curl && \
addgroup -S spring && \
adduser -S spring -G spring && \
mkdir -p /app/logs && \
chown -R spring:spring /app
RUN apk add --no-cache curl=8.5.0-r0 && \
addgroup -S spring && \
adduser -S spring -G spring && \
mkdir -p /app/logs && \
chown -R spring:spring /app
🧰 Tools
🪛 Hadolint (2.14.0)

[warning] 10-10: Pin versions in apk add. Instead of apk add <package> use apk add <package>=<version>

(DL3018)

🤖 Prompt for AI Agents
In @docker/app/dockerfile around lines 10 - 14, The RUN step installs curl
without a pinned version; change the Dockerfile RUN line that currently uses
"apk add --no-cache curl" to pin a specific curl package version (e.g., "apk add
--no-cache curl=<version>" or the exact release string like
"curl=<pkg>-r<revision>") so builds are reproducible and secure, and verify the
correct available version for your Alpine base with "apk search curl" before
setting the version.

Comment on lines +7 to +12
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

curl 버전을 고정하고 중복 디렉토리 생성 제거 필요

이 섹션에는 두 가지 개선이 필요합니다:

  1. Line 8에서 curl 패키지 버전을 고정하지 않았습니다. 재현 가능한 빌드를 위해 버전을 명시해야 합니다.
  2. Line 11에서 /app/logs 디렉토리를 생성했지만, Line 19에서 동일한 작업을 다시 수행합니다.
🔧 제안하는 수정사항
-RUN apk add --no-cache curl && \
+RUN apk add --no-cache curl=8.5.0-r0 && \
     addgroup -S spring && \
     adduser -S spring -G spring && \
     mkdir -p /app/logs && \
     chown -R spring:spring /app

그리고 Line 18-19를 제거하세요 (중복):

-# 로그 디렉토리 생성 및 권한 설정
-RUN mkdir -p /app/logs && chown -R spring:spring /app/logs

참고: curl 버전은 Alpine 버전에 따라 다를 수 있으므로, apk search curl로 사용 가능한 버전을 확인하세요.

📝 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
# curl 설치 (헬스체크용) + non-root 유저 생성
RUN apk add --no-cache curl && \
addgroup -S spring && \
adduser -S spring -G spring && \
mkdir -p /app/logs && \
chown -R spring:spring /app
# curl 설치 (헬스체크용) + non-root 유저 생성
RUN apk add --no-cache curl=8.5.0-r0 && \
addgroup -S spring && \
adduser -S spring -G spring && \
mkdir -p /app/logs && \
chown -R spring:spring /app
🧰 Tools
🪛 Hadolint (2.14.0)

[warning] 8-8: Pin versions in apk add. Instead of apk add <package> use apk add <package>=<version>

(DL3018)

🤖 Prompt for AI Agents
In @docker/app/dockerfile around lines 7 - 12, Pin the curl package version in
the RUN apk add command (e.g., apk add --no-cache curl=<VERSION>) to ensure
reproducible builds and remove the duplicate /app/logs creation by deleting the
later mkdir -p /app/logs (the second occurrence); keep a single mkdir -p
/app/logs and its chown -R spring:spring in the RUN block that also creates the
spring user/group (the RUN line containing apk add, addgroup -S spring, adduser
-S spring -G spring, mkdir -p /app/logs, chown -R spring:spring), and replace
<VERSION> with the appropriate Alpine curl package version found via apk search.


# 이미 build된 jar 파일을 docker 안으로 복사
COPY --chown=spring:spring build/libs/*.jar app.jar
RUN chmod 444 app.jar
Comment on lines +14 to +16
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

와일드카드 사용으로 인한 빌드 실패 가능성

Line 15의 build/libs/*.jar 와일드카드는 여러 JAR 파일이 존재할 경우 Docker 빌드가 실패합니다. Spring Boot Gradle 프로젝트는 bootJar 태스크 외에도 일반 jar 태스크가 실행될 수 있어 app-plain.jarapp.jar가 동시에 생성될 수 있습니다.

🔧 제안하는 수정사항

옵션 1: Gradle에서 plain JAR 생성 비활성화 (권장)

build.gradle에 추가:

tasks.named('jar') {
    enabled = false
}

옵션 2: Dockerfile에서 명시적으로 bootJar 파일만 복사

-COPY --chown=spring:spring build/libs/*.jar app.jar
+COPY --chown=spring:spring build/libs/*[!plain].jar app.jar

또는 프로젝트명을 사용:

-COPY --chown=spring:spring build/libs/*.jar app.jar
+COPY --chown=spring:spring build/libs/umc-product-server-*.jar app.jar

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @docker/app/dockerfile around lines 14 - 16, The COPY in the Dockerfile uses
a wildcard (build/libs/*.jar) which can fail when multiple jars exist; either
disable the plain jar in Gradle by adding tasks.named('jar') { enabled = false }
to build.gradle so only the bootJar exists, or change the Dockerfile COPY to
target the boot jar explicitly (e.g., COPY --chown=spring:spring
build/libs/*-boot.jar app.jar or use the exact artifact name) and keep the
existing RUN chmod line; apply one of these fixes to prevent multi-match
failures.


# 로그 디렉토리 생성 및 권한 설정
RUN mkdir -p /app/logs && chown -R spring:spring /app/logs

# Switch to non-root user
USER spring:spring

# Expose application port
EXPOSE 8080

# JVM options
ENV JAVA_OPTS="-XX:+UseContainerSupport \
-XX:MaxRAMPercentage=75.0 \
-XX:+UseG1GC \
-XX:+ExitOnOutOfMemoryError \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/tmp/heapdump.hprof \
-Duser.timezone=Asia/Seoul \
-Djava.security.egd=file:/dev/./urandom"

# Use exec form with sh -c so JAVA_OPTS is expanded and signals forwarded
ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS -jar app.jar"]

# Optional healthcheck (uncomment if actuator/health endpoint exists)
# HEALTHCHECK --interval=30s --timeout=5s CMD curl -f http://localhost:8080/actuator/health || exit 1
Comment on lines +40 to +41
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "dockerfile" -o -name "Dockerfile" | head -20

Repository: UMC-PRODUCT/umc-product-server

Length of output: 121


🏁 Script executed:

find . -type f \( -name "pom.xml" -o -name "build.gradle" -o -name "build.gradle.kts" \) | head -10

Repository: UMC-PRODUCT/umc-product-server

Length of output: 92


🏁 Script executed:

git ls-files | grep -E "(docker|Dockerfile)" | head -20

Repository: UMC-PRODUCT/umc-product-server

Length of output: 150


🏁 Script executed:

cat build.gradle.kts

Repository: UMC-PRODUCT/umc-product-server

Length of output: 4848


🏁 Script executed:

cat docker/app/dockerfile

Repository: UMC-PRODUCT/umc-product-server

Length of output: 1383


헬스체크 활성화 필요

Spring Boot Actuator가 프로젝트에 포함되어 있고, curl도 이미 설치되어 있으므로 헬스체크를 활성화하세요.

-# Optional healthcheck (uncomment if actuator/health endpoint exists)
-# HEALTHCHECK --interval=30s --timeout=5s CMD curl -f http://localhost:8080/actuator/health || exit 1
+HEALTHCHECK --interval=30s --timeout=5s CMD curl -f http://localhost:8080/actuator/health || exit 1
📝 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
# Optional healthcheck (uncomment if actuator/health endpoint exists)
# HEALTHCHECK --interval=30s --timeout=5s CMD curl -f http://localhost:8080/actuator/health || exit 1
HEALTHCHECK --interval=30s --timeout=5s CMD curl -f http://localhost:8080/actuator/health || exit 1
🧰 Tools
🪛 Checkov (3.2.334)

[low] 1-41: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)

🤖 Prompt for AI Agents
In @docker/app/dockerfile around lines 40 - 41, Uncomment and enable the Docker
HEALTHCHECK by activating the existing HEALTHCHECK instruction that pings the
Spring Boot Actuator endpoint (e.g., "HEALTHCHECK --interval=30s --timeout=5s
CMD curl -f http://localhost:8080/actuator/health || exit 1") so the container
reports health status; ensure the Actuator endpoint is exposed and curl remains
installed in the image.

Binary file added gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
Loading
Loading