Skip to content
Merged
Show file tree
Hide file tree
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
114 changes: 114 additions & 0 deletions .env.local.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# =============================================================================
# Local Development Environment Configuration
# =============================================================================
# 로컬 개발 환경용 설정 파일
#
# 사용법:
# 1. 이 파일을 .env.local로 복사하세요
# 2. 필요한 값들을 채워넣으세요
# 3. docker-compose -f docker-compose.local.yml up --build 로 실행하세요
# =============================================================================

# =============================================================================
# Application Configuration
# =============================================================================
SERVER_PORT=8080
SPRING_PROFILES_ACTIVE=local

# =============================================================================
# Database Configuration
# =============================================================================
# 로컬 MySQL 사용 시 (Docker로 MySQL 실행하는 경우)
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

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

The .env.local.sample suggests using DB_IP=host.docker.internal for accessing a MySQL on the host machine, but docker-compose-local.yml line 30 overrides this with DB_IP: mysql (the Docker service name) in the environment section. This configuration in the sample file will be ignored and may confuse users. Update the comment to clarify that the MySQL service is included in the compose file and the DB_IP is overridden.

Suggested change
# 로컬 MySQL 사용 시 (Docker로 MySQL 실행하는 경우)
# 로컬 MySQL 사용 시
# ⚠️ docker-compose.local.yml을 사용할 경우, DB_IP는 'mysql'(서비스 이름)로 오버라이드됩니다.
# 아래 값은 Docker Compose를 사용하지 않고 직접 실행할 때만 적용됩니다.

Copilot uses AI. Check for mistakes.
DB_IP=host.docker.internal # Docker 컨테이너에서 호스트 머신 접근
# DB_IP=localhost # 호스트 머신에서 직접 실행 시
DB_PORT=3306
DB_SCHEMA=devnogi
DB_USER=root
DB_PASSWORD=your_local_password

# =============================================================================
# Security Configuration (로컬 개발용 - 운영 환경과 다른 값 사용)
# =============================================================================
JWT_SECRET_KEY=local-development-secret-key-do-not-use-in-production-change-this
JWT_ACCESS_TOKEN_VALIDITY=3600000 # 1시간 (밀리초)
JWT_REFRESH_TOKEN_VALIDITY=86400000 # 24시간 (밀리초)

# =============================================================================
# External API Configuration
# =============================================================================
# Nexon Open API 키 (https://openapi.nexon.com/에서 발급)
NEXON_OPEN_API_KEY=your_nexon_api_key_here

# 경매 데이터 수집 설정
AUCTION_HISTORY_DELAY_MS=1000 # API 호출 간 딜레이 (1초)
AUCTION_HISTORY_CRON=0 0 * * * * # 매시간 정각에 실행 (초 분 시 일 월 요일)
AUCTION_HISTORY_MIN_PRICE_CRON=0 30 * * * * # 매시간 30분에 실행

# =============================================================================
# Docker Configuration (로컬 개발에서는 불필요)
# =============================================================================
# DOCKER_USERNAME=your_dockerhub_username
# DOCKER_PASSWORD=your_dockerhub_password
# DOCKER_REPO=open-api-batch-server
# DOCKER_IMAGE_TAG=local

# =============================================================================
# JVM Memory Configuration (로컬 개발용 - 메모리 사용량 감소)
# =============================================================================
# Heap Memory - 로컬에서는 적은 메모리로 실행
JAVA_OPTS_XMS=256m # 초기 힙 메모리
JAVA_OPTS_XMX=512m # 최대 힙 메모리

# Non-Heap Memory
JAVA_OPTS_MAX_METASPACE_SIZE=128m # Metaspace 최대 크기
JAVA_OPTS_RESERVED_CODE_CACHE_SIZE=64m # JIT 컴파일된 코드 캐시
JAVA_OPTS_MAX_DIRECT_MEMORY_SIZE=64m # Direct Buffer 최대 크기
JAVA_OPTS_XSS=512k # 스레드 스택 크기

# =============================================================================
# JVM GC Configuration (G1GC)
# =============================================================================
JAVA_OPTS_MAX_GC_PAUSE_MILLIS=200 # GC 일시정지 목표 시간
JAVA_OPTS_G1_HEAP_REGION_SIZE=1m # G1 힙 영역 크기
JAVA_OPTS_INITIATING_HEAP_OCCUPANCY_PERCENT=45 # GC 시작 힙 점유율

# =============================================================================
# JVM Compiler Configuration
# =============================================================================
# 로컬 개발에서는 빠른 시작을 위해 TieredStopAtLevel=1 (C1 컴파일러만 사용)
JAVA_OPTS_TIERED_STOP_AT_LEVEL=1 # 1: 빠른 시작, 4: 최적 성능
JAVA_OPTS_CI_COMPILER_COUNT=2 # 컴파일러 스레드 수

# =============================================================================
# Docker Container Resource Limits (로컬 개발용)
# =============================================================================
DOCKER_MEMORY_LIMIT=1g # 컨테이너 최대 메모리
DOCKER_MEMORY_RESERVATION=512m # 예약 메모리

# =============================================================================
# Container Restart Policy
# =============================================================================
RESTART_POLICY_MAX_RETRIES=3 # 실패 시 최대 재시작 횟수

# =============================================================================
# Health Check Configuration (로컬 개발용 - 더 짧은 간격)
# =============================================================================
HEALTHCHECK_INTERVAL=30s # 헬스 체크 주기
HEALTHCHECK_TIMEOUT=10s # 헬스 체크 타임아웃
HEALTHCHECK_RETRIES=3 # 연속 실패 횟수
HEALTHCHECK_START_PERIOD=60s # 시작 유예 기간

# =============================================================================
# Autoheal Configuration
# =============================================================================
AUTOHEAL_INTERVAL=30 # unhealthy 체크 주기 (초)
AUTOHEAL_START_PERIOD=0 # 체크 시작 유예 시간
AUTOHEAL_DEFAULT_STOP_TIMEOUT=10 # 재시작 시 강제 종료 대기 시간
AUTOHEAL_MEMORY_LIMIT=50M # autoheal 최대 메모리
AUTOHEAL_MEMORY_RESERVATION=20M # autoheal 예약 메모리

# =============================================================================
# Logging Configuration
# =============================================================================
LOGGING_MAX_SIZE=10m # 로그 파일 최대 크기
LOGGING_MAX_FILE=3 # 로그 파일 보관 개수
2 changes: 1 addition & 1 deletion .github/workflows/push-cd-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ jobs:
run: |
ssh -i ~/.ssh/my-key.pem ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }} "mkdir -p /home/${{ secrets.SERVER_USER }}/app/logs"

- name: Copy docker-compose.yaml to server
- name: Copy docker-compose-dev.yaml to server
run: |
scp -i ~/.ssh/my-key.pem docker-compose.yaml ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }}:/home/${{ secrets.SERVER_USER }}/app/
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

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

The step name says 'Copy docker-compose-dev.yaml to server' but the command copies 'docker-compose.yaml'. Either update the command to scp docker-compose-dev.yaml to match the step name, or revert the step name change if 'docker-compose.yaml' is the correct file to copy.

Suggested change
scp -i ~/.ssh/my-key.pem docker-compose.yaml ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }}:/home/${{ secrets.SERVER_USER }}/app/
scp -i ~/.ssh/my-key.pem docker-compose-dev.yaml ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }}:/home/${{ secrets.SERVER_USER }}/app/

Copilot uses AI. Check for mistakes.

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/push-cd-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ jobs:
run: |
ssh -i ~/.ssh/my-key.pem ${{ secrets.PROD_SERVER_USER }}@${{ secrets.PROD_SERVER_HOST }} "mkdir -p /home/${{ secrets.PROD_SERVER_USER }}/app/logs"

- name: Copy docker-compose.yaml to server
- name: Copy docker-compose-dev.yaml to server
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

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

The step name says 'Copy docker-compose-dev.yaml to server' but the command copies 'docker-compose.yaml'. Either update the command to scp docker-compose-dev.yaml to match the step name, or revert the step name change if 'docker-compose.yaml' is the correct file to copy.

Suggested change
- name: Copy docker-compose-dev.yaml to server
- name: Copy docker-compose.yaml to server

Copilot uses AI. Check for mistakes.
run: |
scp -i ~/.ssh/my-key.pem docker-compose.yaml ${{ secrets.PROD_SERVER_USER }}@${{ secrets.PROD_SERVER_HOST }}:/home/${{ secrets.PROD_SERVER_USER }}/app/
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

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

The step name says 'Copy docker-compose-dev.yaml' but the actual command copies 'docker-compose.yaml'. This mismatch will cause the deployment to fail as the file being copied doesn't exist in the repository. Change the filename in the scp command to 'docker-compose-dev.yaml'.

Suggested change
scp -i ~/.ssh/my-key.pem docker-compose.yaml ${{ secrets.PROD_SERVER_USER }}@${{ secrets.PROD_SERVER_HOST }}:/home/${{ secrets.PROD_SERVER_USER }}/app/
scp -i ~/.ssh/my-key.pem docker-compose-dev.yaml ${{ secrets.PROD_SERVER_USER }}@${{ secrets.PROD_SERVER_HOST }}:/home/${{ secrets.PROD_SERVER_USER }}/app/

Copilot uses AI. Check for mistakes.

Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,13 @@ spy.log
### Environment Variables
# Exclude actual .env file (contains real secrets)
.env
.env.local
.env.dev
.env.prod

# Include environment templates (placeholder values only)
# - .env.sample: Template with all available variables
# - .env: Local development configuration template
# - .env.local.sample: Local development configuration template
# - .env.dev: Development server configuration template
# - .env.prod: Production server configuration template
# NOTE: These template files should ONLY contain placeholder values, never real secrets!
Expand Down
7 changes: 6 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
# Stage 3: Runtime Stage - 최종 런타임 이미지

# Stage 1: Build Stage
FROM gradle:8.5-jdk21-alpine AS builder
# alpine 제거하여 ARM64(Apple Silicon)와 AMD64(Intel/AMD) 모두 지원
FROM gradle:8.5-jdk21 AS builder

# 작업 디렉토리 설정
WORKDIR /app
Expand Down Expand Up @@ -60,6 +61,10 @@ COPY --from=extractor --chown=spring:spring /app/spring-boot-loader/ ./
COPY --from=extractor --chown=spring:spring /app/snapshot-dependencies/ ./
COPY --from=extractor --chown=spring:spring /app/application/ ./

# 로그 디렉토리 생성 및 권한 설정 (Named volume 마운트 전에 실행됨)
RUN mkdir -p /app/logs /app/logs/archive && \
chown -R spring:spring /app/logs

# 사용자 전환
USER spring:spring

Expand Down
59 changes: 59 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,62 @@
- **Git branch 전략**: Git-flow [관련 블로그](https://velog.io/@kw2577/Git-branch-%EC%A0%84%EB%9E%B5)

<br>

### 🐳 로컬 개발 환경 (Docker)

로컬에서 코드를 수정하면서 개발할 때는 Docker Hub에 푸시하지 않고 로컬 빌드로 실행할 수 있습니다.

#### 1. 환경 설정

```bash
# .env.local.sample을 복사하여 .env.local 생성
cp .env.local.sample .env.local

# .env.local 파일을 열어서 필요한 값들을 수정
# - NEXON_OPEN_API_KEY: Nexon Open API 키 입력
# - DB_PASSWORD: 로컬 MySQL 비밀번호 입력
# - 기타 필요한 설정 수정
```

#### 2. 로컬에서 Docker로 실행

```bash
# 로컬 코드를 빌드하고 Docker 컨테이너로 실행
docker-compose -f docker-compose-local.yml up --build

# 백그라운드 실행
docker-compose -f docker-compose-local.yml up -d --build

# 로그 확인
docker-compose -f docker-compose-local.yml logs -f spring-app

# 중지
docker-compose -f docker-compose-local.yml down
```

#### 3. 코드 수정 후 재실행

```bash
# 코드 수정 후 다시 빌드하여 실행
docker-compose -f docker-compose-local.yml up --build

# 또는 기존 컨테이너 정리 후 재실행
docker-compose -f docker-compose-local.yml down
docker-compose -f docker-compose-local.yml up --build
```

#### 4. 환경별 실행 방법

| 환경 | Docker Compose 파일 | 설명 |
|------|---------------------|------|
| **로컬 개발** | `docker-compose.local.yml` | 로컬 코드 빌드, 낮은 리소스 사용 |
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

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

Filename inconsistency: The table references docker-compose.local.yml but the actual filename is docker-compose-local.yml (with hyphen, not dot). Update the table to use the correct filename.

Suggested change
| **로컬 개발** | `docker-compose.local.yml` | 로컬 코드 빌드, 낮은 리소스 사용 |
| **로컬 개발** | `docker-compose-local.yml` | 로컬 코드 빌드, 낮은 리소스 사용 |

Copilot uses AI. Check for mistakes.
| **개발/운영 서버** | `docker-compose.yaml` | Docker Hub 이미지 사용 |

#### 5. 참고사항

- **로컬 개발**: 코드 수정 시마다 `--build` 옵션으로 재빌드 필요
- **메모리 설정**: 로컬 환경은 메모리 사용량이 낮게 설정되어 있음 (512MB)
- **데이터베이스**: `DB_IP=host.docker.internal`로 호스트 머신의 MySQL에 접근
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

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

The documentation states that DB_IP=host.docker.internal is used to access MySQL on the host machine, but according to the docker-compose-local.yml (line 31), it's set to mysql which refers to the MySQL container service name, not the host. This documentation is inconsistent with the actual implementation. Update to reflect that the local setup uses a containerized MySQL service.

Suggested change
- **데이터베이스**: `DB_IP=host.docker.internal`호스트 머신의 MySQL에 접근
- **데이터베이스**: `DB_IP=mysql`Docker Compose의 MySQL 컨테이너에 접근 (`mysql`은 서비스 이름)

Copilot uses AI. Check for mistakes.
- **포트**: 기본 8080 포트 사용 (`.env.local`에서 변경 가능)

<br>
9 changes: 8 additions & 1 deletion docker-compose.yaml → docker-compose-dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ version: "3.8"

services:
spring-app:
build:
context: .
dockerfile: Dockerfile
image: ${DOCKER_USERNAME}/${DOCKER_REPO}:${DOCKER_IMAGE_TAG:-latest}
container_name: spring-app
ports:
Expand Down Expand Up @@ -62,7 +65,7 @@ services:
-Djava.security.egd=file:/dev/./urandom
-Dspring.jmx.enabled=false
volumes:
- ./logs:/app/logs
- app-logs:/app/logs # Named volume 사용 (권한 문제 해결)
# - ./config:/app/config:ro # Optional: mount external config directory
# Restart Policy:
# - always: 항상 재시작 (수동 stop 포함)
Expand Down Expand Up @@ -124,6 +127,10 @@ services:
reservations:
memory: ${AUTOHEAL_MEMORY_RESERVATION}

volumes:
app-logs:
driver: local

networks:
app-network:
driver: bridge
Loading