config: 서비스 포트를 8877로 고정
application.yml에 server.port가 없어 기본 8080으로 뜨고, 실행 스크립트마다 --server.port를 따로 넘기고 있어서 환경별로 포트가 달랐다. 앱 자체 기본값을 8877로 두어 어디서 띄우든 같은 포트가 되게 한다. SERVER_PORT 환경변수로는 여전히 덮어쓸 수 있다. 함께 맞춘 곳: - Dockerfile EXPOSE / HEALTHCHECK, docker-compose 포트 매핑 - deploy/start.sh 기본값, itnhub.env.example (SERVER_PORT·TZ 항목 추가) - vite 개발 프록시 대상(:8080 -> :8877). 이걸 안 바꾸면 npm run dev 에서 /api 가 죽는다 - run-local.ps1 은 --server.port 인자를 떼고 앱 기본값을 따르게 함 - README / deploy/README 의 포트 표기 로컬에서 재빌드 후 확인: 8877 /login 200, 8080 닫힘. Co-Authored-By: Claude Opus 5 (1M context)
@5d0c7bcfdc2aaccb074d6e2ffe774a1ad7a3d67b
--- Dockerfile
+++ Dockerfile
... | ... | @@ -35,12 +35,12 @@ |
| 35 | 35 |
WORKDIR /app |
| 36 | 36 |
COPY --from=build /build/app.jar /app/app.jar |
| 37 | 37 |
|
| 38 |
-# 컨테이너 안에서는 스프링 기본 포트를 그대로 쓴다. 바깥 포트는 실행할 때 -p 로 정한다. |
|
| 39 |
-EXPOSE 8080 |
|
| 38 |
+# 컨테이너 안에서도 앱 기본 포트(8877)를 그대로 쓴다. 바깥 포트는 실행할 때 -p 로 정한다. |
|
| 39 |
+EXPOSE 8877 |
|
| 40 | 40 |
|
| 41 | 41 |
# actuator를 넣지 않아서 헬스체크는 로그인 화면 200으로 확인한다(익명 접근 허용 경로). |
| 42 | 42 |
HEALTHCHECK --interval=30s --timeout=5s --start-period=90s --retries=3 \ |
| 43 |
- CMD wget -q --spider http://127.0.0.1:8080/login || exit 1 |
|
| 43 |
+ CMD wget -q --spider http://127.0.0.1:8877/login || exit 1 |
|
| 44 | 44 |
|
| 45 | 45 |
# 컨테이너 메모리 한도에 맞춰 힙을 잡는다. |
| 46 | 46 |
ENV JAVA_OPTS="-XX:MaxRAMPercentage=75 -XX:+UseContainerSupport" |
--- README.md
+++ README.md
... | ... | @@ -93,7 +93,7 @@ |
| 93 | 93 |
export APP_ADMIN_USERNAME=admin |
| 94 | 94 |
export APP_ADMIN_PASSWORD=... |
| 95 | 95 |
|
| 96 |
-java -jar target/itnhub-0.1.0.jar --server.port=8091 |
|
| 96 |
+java -jar target/itnhub-0.1.0.jar |
|
| 97 | 97 |
``` |
| 98 | 98 |
|
| 99 | 99 |
기동하면 Flyway가 `itnhub` 스키마와 테이블(V1~V12)을 **자동으로 만든다.** 수동 DDL은 없다. |
... | ... | @@ -101,7 +101,7 @@ |
| 101 | 101 |
### 프런트만 반복 개발할 때 |
| 102 | 102 |
|
| 103 | 103 |
```bash |
| 104 |
-cd frontend && npm install && npm run dev # Vite가 /api 를 :8080 으로 프록시 |
|
| 104 |
+cd frontend && npm install && npm run dev # Vite가 /api 를 :8877 로 프록시 |
|
| 105 | 105 |
mvn spring-boot:run # 백엔드는 따로 띄워 둔다 |
| 106 | 106 |
``` |
| 107 | 107 |
|
--- deploy/README.md
+++ deploy/README.md
... | ... | @@ -6,8 +6,8 @@ |
| 6 | 6 |
| 항목 | 값 | |
| 7 | 7 |
|---|---| |
| 8 | 8 |
| 런타임 | JDK 21 (이미지에 포함) | |
| 9 |
-| 컨테이너 내부 포트 | 8080 | |
|
| 10 |
-| 서버에 노출할 포트 | 8091 (compose에서 변경 가능) | |
|
| 9 |
+| 컨테이너 내부 포트 | 8877 | |
|
| 10 |
+| 서버에 노출할 포트 | 8877 | |
|
| 11 | 11 |
| DB | 외부 PostgreSQL 16 `192.168.0.60:5432/itnhub` (컨테이너로 띄우지 않음) | |
| 12 | 12 |
| 영속 볼륨 | **불필요** — 업로드 파일은 DB(`org_report`)와 Mattermost에 저장된다 | |
| 13 | 13 |
| 스키마 생성 | 기동 시 Flyway가 `itnhub` 스키마와 V1~V12를 자동 적용 | |
... | ... | @@ -33,7 +33,7 @@ |
| 33 | 33 |
sudo cp deploy/docker-compose.yml /opt/itnhub/ |
| 34 | 34 |
|
| 35 | 35 |
# 방화벽 |
| 36 |
-sudo firewall-cmd --add-port=8091/tcp --permanent && sudo firewall-cmd --reload |
|
| 36 |
+sudo firewall-cmd --add-port=8877/tcp --permanent && sudo firewall-cmd --reload |
|
| 37 | 37 |
``` |
| 38 | 38 |
|
| 39 | 39 |
서버 밖에서 챙길 것 두 가지: |
... | ... | @@ -72,7 +72,7 @@ |
| 72 | 72 |
|
| 73 | 73 |
```bash |
| 74 | 74 |
ssh deploy@192.168.0.176 "sudo docker compose -f /opt/itnhub/docker-compose.yml ps" |
| 75 |
-curl -f http://192.168.0.176:8091/login && echo OK |
|
| 75 |
+curl -f http://192.168.0.176:8877/login && echo OK |
|
| 76 | 76 |
ssh deploy@192.168.0.176 "sudo docker logs --tail 100 itnhub" |
| 77 | 77 |
``` |
| 78 | 78 |
|
... | ... | @@ -103,4 +103,4 @@ |
| 103 | 103 |
- 테스트(`mvn test`)는 Testcontainers로 PostgreSQL을 띄우므로 **에이전트에 Docker 소켓이 필요**하다. |
| 104 | 104 |
이미지 빌드 안에서는 테스트를 돌리지 않는다(Docker-in-Docker가 되므로). |
| 105 | 105 |
- 권장 순서: `mvn -B verify`(테스트) → `docker build` → 레지스트리 push → 176에서 `compose up -d` |
| 106 |
- → `curl -f http://192.168.0.176:8091/login` 로 확인. |
|
| 106 |
+ → `curl -f http://192.168.0.176:8877/login` 로 확인. |
--- deploy/docker-compose.yml
+++ deploy/docker-compose.yml
... | ... | @@ -12,9 +12,9 @@ |
| 12 | 12 |
env_file: |
| 13 | 13 |
- /etc/itnhub/itnhub.env |
| 14 | 14 |
|
| 15 |
- # 왼쪽이 서버에서 열리는 포트. 로컬 개발과 같은 8091로 맞춰 둔다. |
|
| 15 |
+ # 앱 포트는 8877로 고정되어 있다(application.yml). |
|
| 16 | 16 |
ports: |
| 17 |
- - "8091:8080" |
|
| 17 |
+ - "8877:8877" |
|
| 18 | 18 |
|
| 19 | 19 |
# 컨테이너 로그가 무한정 쌓이지 않게 한다. |
| 20 | 20 |
logging: |
--- deploy/itnhub.env.example
+++ deploy/itnhub.env.example
... | ... | @@ -27,5 +27,11 @@ |
| 27 | 27 |
APP_ADMIN_PASSWORD= |
| 28 | 28 |
|
| 29 | 29 |
# --- 선택 --- |
| 30 |
+# 앱 포트. application.yml에 8877로 고정돼 있으니 보통 건드릴 일이 없다. |
|
| 31 |
+# SERVER_PORT=8877 |
|
| 32 |
+ |
|
| 33 |
+# 서버 시간대. UTC로 두면 업무단계 도달 일시와 칸반 D+n이 9시간 어긋난다. |
|
| 34 |
+TZ=Asia/Seoul |
|
| 35 |
+ |
|
| 30 | 36 |
# nginx 등 TLS 종단 프록시를 앞에 두면 켠다(리다이렉트·쿠키 Secure 판정이 정상화된다). |
| 31 | 37 |
# SERVER_FORWARD_HEADERS_STRATEGY=framework |
+++ deploy/start.sh
... | ... | @@ -0,0 +1,76 @@ |
| 1 | +#!/usr/bin/env bash | |
| 2 | +# | |
| 3 | +# ITN-HUB 기동 스크립트 (nohup 방식). | |
| 4 | +# | |
| 5 | +# application.yml의 ${DB_URL} 같은 자리는 Spring이 "같은 이름의 환경변수"에서 찾아 채운다. | |
| 6 | +# 그래서 java를 띄우기 전에 env 파일을 읽어 export 해두기만 하면 된다. | |
| 7 | +# 비밀값을 java 명령 인자로 넘기면 `ps` 에 그대로 보이므로 반드시 환경변수로 준다. | |
| 8 | +set -euo pipefail | |
| 9 | + | |
| 10 | +# ── 경로 (환경에 맞게 수정) ────────────────────────────────────────── | |
| 11 | +JAVA_HOME_BIN=/home/hubAdmin/jdk-21.0.11/bin | |
| 12 | +DEPLOY_PATH=/home/hubAdmin/deploy | |
| 13 | +FILE_NM=itnhub-0.1.0.jar | |
| 14 | +LOG_FILE_PATH=/home/hubAdmin/logs | |
| 15 | +LOG_FILE_NM=itnhub.log | |
| 16 | +PID_FILE=/home/hubAdmin/itnhub.pid | |
| 17 | + | |
| 18 | +# 값이 든 파일. 소유자만 읽게 두고(chmod 600) 저장소에는 올리지 않는다. | |
| 19 | +ENV_FILE=/home/hubAdmin/itnhub.env | |
| 20 | + | |
| 21 | +# ── 환경변수 주입 ──────────────────────────────────────────────────── | |
| 22 | +if [ ! -f "$ENV_FILE" ]; then | |
| 23 | + echo "환경변수 파일이 없습니다: $ENV_FILE" >&2 | |
| 24 | + echo "deploy/itnhub.env.example 을 복사해 값을 채우세요." >&2 | |
| 25 | + exit 1 | |
| 26 | +fi | |
| 27 | + | |
| 28 | +# set -a 를 켜면 이후 대입되는 변수가 모두 export 된다(파일에 export를 안 써도 된다). | |
| 29 | +set -a | |
| 30 | +# shellcheck disable=SC1090 | |
| 31 | +. "$ENV_FILE" | |
| 32 | +set +a | |
| 33 | + | |
| 34 | +# 필수 8개가 비어 있으면 기동 도중에 죽으므로 여기서 먼저 걸러낸다. | |
| 35 | +for v in DB_URL DB_USERNAME DB_PASSWORD MATTERMOST_URL MATTERMOST_TOKEN \ | |
| 36 | + MATTERMOST_TEAM_ID APP_ADMIN_USERNAME APP_ADMIN_PASSWORD; do | |
| 37 | + if [ -z "${!v:-}" ]; then | |
| 38 | + echo "필수 환경변수가 비어 있습니다: $v ($ENV_FILE 확인)" >&2 | |
| 39 | + exit 1 | |
| 40 | + fi | |
| 41 | +done | |
| 42 | + | |
| 43 | +# 서버 시간대가 UTC면 업무단계 도달 일시, 칸반의 D+n, 연락 이력 날짜가 9시간 어긋난다. | |
| 44 | +export TZ="${TZ:-Asia/Seoul}" | |
| 45 | +# 앱 기본 포트는 application.yml에 8877로 고정되어 있다. 필요하면 env 파일에서 바꾼다. | |
| 46 | +export SERVER_PORT="${SERVER_PORT:-8877}" | |
| 47 | + | |
| 48 | +JAVA_OPTS="${JAVA_OPTS:--Xms512m -Xmx1g -Duser.timezone=Asia/Seoul -Dfile.encoding=UTF-8}" | |
| 49 | + | |
| 50 | +# ── 중복 기동 방지 ─────────────────────────────────────────────────── | |
| 51 | +if [ -f "$PID_FILE" ] && kill -0 "$(cat "$PID_FILE")" 2>/dev/null; then | |
| 52 | + echo "이미 실행 중입니다 (PID $(cat "$PID_FILE")). 먼저 stop.sh 를 실행하세요." >&2 | |
| 53 | + exit 1 | |
| 54 | +fi | |
| 55 | + | |
| 56 | +mkdir -p "$LOG_FILE_PATH" | |
| 57 | + | |
| 58 | +# ── 기동 ───────────────────────────────────────────────────────────── | |
| 59 | +nohup "$JAVA_HOME_BIN/java" $JAVA_OPTS -jar "$DEPLOY_PATH/$FILE_NM" \ | |
| 60 | + >> "$LOG_FILE_PATH/$LOG_FILE_NM" 2>&1 & | |
| 61 | + | |
| 62 | +echo $! > "$PID_FILE" | |
| 63 | +echo "기동 요청 완료 (PID $(cat "$PID_FILE"), 포트 $SERVER_PORT)" | |
| 64 | + | |
| 65 | +# ── 기동 확인 ──────────────────────────────────────────────────────── | |
| 66 | +# actuator를 넣지 않아서 로그인 화면 200으로 확인한다. | |
| 67 | +for _ in $(seq 1 60); do | |
| 68 | + if curl -fs -o /dev/null "http://127.0.0.1:${SERVER_PORT}/login"; then | |
| 69 | + echo "정상 기동 확인: http://127.0.0.1:${SERVER_PORT}/login" | |
| 70 | + exit 0 | |
| 71 | + fi | |
| 72 | + sleep 1 | |
| 73 | +done | |
| 74 | + | |
| 75 | +echo "60초 안에 응답이 없습니다. 로그를 확인하세요: $LOG_FILE_PATH/$LOG_FILE_NM" >&2 | |
| 76 | +exit 1 |
+++ deploy/stop.sh
... | ... | @@ -0,0 +1,34 @@ |
| 1 | +#!/usr/bin/env bash | |
| 2 | +# | |
| 3 | +# ITN-HUB 종료 스크립트. start.sh가 남긴 PID 파일을 쓴다. | |
| 4 | +set -euo pipefail | |
| 5 | + | |
| 6 | +PID_FILE=/home/hubAdmin/itnhub.pid | |
| 7 | + | |
| 8 | +if [ ! -f "$PID_FILE" ]; then | |
| 9 | + echo "PID 파일이 없습니다: $PID_FILE" | |
| 10 | + exit 0 | |
| 11 | +fi | |
| 12 | + | |
| 13 | +PID=$(cat "$PID_FILE") | |
| 14 | + | |
| 15 | +if ! kill -0 "$PID" 2>/dev/null; then | |
| 16 | + echo "이미 종료된 프로세스입니다 (PID $PID)." | |
| 17 | + rm -f "$PID_FILE" | |
| 18 | + exit 0 | |
| 19 | +fi | |
| 20 | + | |
| 21 | +# 먼저 정상 종료를 요청하고, 20초를 기다렸다가 그래도 살아 있으면 강제 종료한다. | |
| 22 | +kill "$PID" | |
| 23 | +for _ in $(seq 1 20); do | |
| 24 | + if ! kill -0 "$PID" 2>/dev/null; then | |
| 25 | + rm -f "$PID_FILE" | |
| 26 | + echo "종료 완료 (PID $PID)" | |
| 27 | + exit 0 | |
| 28 | + fi | |
| 29 | + sleep 1 | |
| 30 | +done | |
| 31 | + | |
| 32 | +echo "정상 종료되지 않아 강제 종료합니다 (PID $PID)" >&2 | |
| 33 | +kill -9 "$PID" | |
| 34 | +rm -f "$PID_FILE" |
--- frontend/vite.config.ts
+++ frontend/vite.config.ts
... | ... | @@ -9,7 +9,7 @@ |
| 9 | 9 |
}, |
| 10 | 10 |
server: {
|
| 11 | 11 |
proxy: {
|
| 12 |
- '/api': 'http://localhost:8080', |
|
| 12 |
+ '/api': 'http://localhost:8877', |
|
| 13 | 13 |
}, |
| 14 | 14 |
}, |
| 15 | 15 |
test: {
|
--- run-local.ps1
+++ run-local.ps1
... | ... | @@ -29,5 +29,5 @@ |
| 29 | 29 |
$env:APP_ADMIN_PASSWORD = 'itntest123' |
| 30 | 30 |
|
| 31 | 31 |
Set-Location 'D:\Development\InteliJ_repository\itnhub' |
| 32 |
-Write-Host 'Starting ITN-HUB with the REAL Mattermost token. Port 8091. Stop: Ctrl+C' |
|
| 33 |
-java -jar target\itnhub-0.1.0.jar --server.port=8091 |
|
| 32 |
+Write-Host 'Starting ITN-HUB with the REAL Mattermost token. Port 8877. Stop: Ctrl+C' |
|
| 33 |
+java -jar target\itnhub-0.1.0.jar |
--- src/main/resources/application.yml
+++ src/main/resources/application.yml
... | ... | @@ -1,3 +1,7 @@ |
| 1 |
+server: |
|
| 2 |
+ # 운영·개발 모두 8877을 쓴다. 필요하면 SERVER_PORT 환경변수로 덮어쓸 수 있다. |
|
| 3 |
+ port: ${SERVER_PORT:8877}
|
|
| 4 |
+ |
|
| 1 | 5 |
spring: |
| 2 | 6 |
application: |
| 3 | 7 |
name: itnhub |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?