자산관리 시스템 도커라이징
This commit is contained in:
10
.dockerignore
Normal file
10
.dockerignore
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
build
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
.env
|
||||||
|
npm-debug.log
|
||||||
|
uploads
|
||||||
|
*.xlsx
|
||||||
|
*.log
|
||||||
6
.env
6
.env
@@ -1,6 +0,0 @@
|
|||||||
DB_HOST=172.16.8.151
|
|
||||||
DB_PORT=3306
|
|
||||||
DB_USER=itam_admin
|
|
||||||
DB_PASS=itam1234
|
|
||||||
DB_NAME=itam
|
|
||||||
PORT=3000
|
|
||||||
12
Dockerfile.backend
Normal file
12
Dockerfile.backend
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["npm", "run", "server"]
|
||||||
12
Dockerfile.frontend
Normal file
12
Dockerfile.frontend
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
|
||||||
729
doc_readme.md
Normal file
729
doc_readme.md
Normal file
@@ -0,0 +1,729 @@
|
|||||||
|
# ITAM 도커라이징 실전 가이드
|
||||||
|
|
||||||
|
## 1. 문서 목적
|
||||||
|
|
||||||
|
이 문서는 Gitea에 올라가 있는 현재 저장소를 기준으로, 개발 PC에 WSL2와 Ubuntu만 설치되어 있는 상태에서 지금의 Docker 실행 구조를 재현하는 방법을 처음부터 끝까지 설명하는 실전 가이드다.
|
||||||
|
|
||||||
|
이 문서는 아래 상황을 가정한다.
|
||||||
|
|
||||||
|
1. 소스 코드는 아직 로컬에 없거나, Gitea에서 막 받아올 예정이다.
|
||||||
|
2. Windows에는 WSL2와 Ubuntu는 설치되어 있다.
|
||||||
|
3. 그 외 Docker 관련 세팅은 아직 안 되어 있을 수 있다.
|
||||||
|
4. 최종 목표는 현재 저장소 기준 `frontend + backend + external DB` 구조를 Docker로 재현하는 것이다.
|
||||||
|
|
||||||
|
이 문서의 목적은 아래 네 가지다.
|
||||||
|
|
||||||
|
1. 현재 시스템 구조와 Docker 구조를 먼저 이해하게 한다.
|
||||||
|
2. 기존 파일 중 무엇이 새로 추가되었고 무엇이 수정되었는지 정리한다.
|
||||||
|
3. 각 단계별로 정확히 어디에서 명령을 실행해야 하는지 명시한다.
|
||||||
|
4. Gitea 소스만 받은 상태에서 지금과 같은 Docker 실행 상태까지 도달하게 한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 현재 시스템 구조 개요
|
||||||
|
|
||||||
|
## 2.1 애플리케이션 원래 구조
|
||||||
|
|
||||||
|
현재 저장소의 본래 실행 구조는 다음과 같다.
|
||||||
|
|
||||||
|
1. 프런트엔드: Vite 기반 TypeScript 앱
|
||||||
|
2. 백엔드: Express 기반 Node.js API 서버
|
||||||
|
3. 데이터베이스: 외부 MySQL 서버
|
||||||
|
|
||||||
|
즉, 원래부터 MySQL이 Docker 안에 들어 있던 구조가 아니다.
|
||||||
|
|
||||||
|
프런트와 백엔드는 각각 별도 프로세스로 실행되며, 프런트는 `/api` 상대 경로로 백엔드 API를 호출한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2.2 현재 Docker 구조
|
||||||
|
|
||||||
|
현재 최종 Docker 구조는 아래와 같다.
|
||||||
|
|
||||||
|
1. `frontend` 컨테이너
|
||||||
|
2. `backend` 컨테이너
|
||||||
|
3. 외부 MySQL DB
|
||||||
|
|
||||||
|
즉, 지금은 내부 `db` 컨테이너가 없고, 내부 `db-bootstrap` 컨테이너도 없다.
|
||||||
|
|
||||||
|
현재 구조를 문장으로 풀면 다음과 같다.
|
||||||
|
|
||||||
|
1. 브라우저는 `http://localhost:8080`으로 `frontend` 컨테이너에 접속한다.
|
||||||
|
2. `frontend`는 `/api` 요청을 `backend:3000`으로 프록시한다.
|
||||||
|
3. `backend`는 `.env`에 적힌 외부 DB 정보로 외부 MySQL에 직접 접속한다.
|
||||||
|
4. 조회 결과 JSON을 프런트가 받아 화면에 렌더링한다.
|
||||||
|
|
||||||
|
간단한 흐름은 아래와 같다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
Browser
|
||||||
|
-> frontend container :8080
|
||||||
|
-> Vite proxy (/api)
|
||||||
|
-> backend container :3000
|
||||||
|
-> external MySQL (.env)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2.3 왜 이 구조가 맞는가
|
||||||
|
|
||||||
|
현재 구조가 적절한 이유는 다음과 같다.
|
||||||
|
|
||||||
|
1. 원래 시스템도 외부 MySQL을 쓰는 구조였다.
|
||||||
|
2. 지금 목표는 운영형 단일 배포가 아니라 현재 개발형 구조를 Docker로 재현하는 것이다.
|
||||||
|
3. 프런트는 Vite dev server 기반이라 운영형 nginx 정적 배포 구조로 억지로 바꾸는 것보다, 현 구조를 유지하는 편이 안전하다.
|
||||||
|
4. 실무 표준 관점에서도 앱 컨테이너는 무상태로 유지하고, DB는 외부 인프라를 사용하는 구성이 더 일반적이다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 이번 도커라이징에서 추가되거나 수정된 파일 정리
|
||||||
|
|
||||||
|
아래 파일들은 이번 Docker 재현 구조를 위해 새로 추가되었거나 수정된 핵심 파일이다.
|
||||||
|
|
||||||
|
## 3.1 새로 추가된 파일
|
||||||
|
|
||||||
|
1. `Dockerfile.frontend`
|
||||||
|
2. `Dockerfile.backend`
|
||||||
|
3. `.dockerignore`
|
||||||
|
4. `docker-compose.yaml`
|
||||||
|
5. `start_docker_wsl.ps1`
|
||||||
|
6. `stop_docker_wsl.ps1`
|
||||||
|
7. `start_docker_wsl.bat`
|
||||||
|
8. `stop_docker_wsl.bat`
|
||||||
|
9. `docker/mysql/init/README.md`
|
||||||
|
10. `docker_task_plan.md`
|
||||||
|
11. `doc_readme2.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3.2 기존 파일 중 수정된 핵심 파일
|
||||||
|
|
||||||
|
1. `server.js`
|
||||||
|
2. `vite.config.ts`
|
||||||
|
3. `doc_readme.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3.3 각 파일의 역할
|
||||||
|
|
||||||
|
### `Dockerfile.frontend`
|
||||||
|
|
||||||
|
역할:
|
||||||
|
|
||||||
|
1. 프런트 Vite 개발 서버 이미지를 만든다.
|
||||||
|
2. 컨테이너 내부에서 `npm run dev -- --host 0.0.0.0`를 실행한다.
|
||||||
|
|
||||||
|
### `Dockerfile.backend`
|
||||||
|
|
||||||
|
역할:
|
||||||
|
|
||||||
|
1. 백엔드 Express 서버 이미지를 만든다.
|
||||||
|
2. 컨테이너 내부에서 `npm run server`를 실행한다.
|
||||||
|
|
||||||
|
### `.dockerignore`
|
||||||
|
|
||||||
|
역할:
|
||||||
|
|
||||||
|
1. `node_modules`, `build`, `.git`, `.env`, `uploads` 같은 불필요한 파일을 Docker build context에서 제외한다.
|
||||||
|
|
||||||
|
### `docker-compose.yaml`
|
||||||
|
|
||||||
|
역할:
|
||||||
|
|
||||||
|
1. `frontend`, `backend` 두 컨테이너를 동시에 띄운다.
|
||||||
|
2. `backend`는 `.env`의 외부 DB를 사용한다.
|
||||||
|
3. `frontend`는 `backend:3000`으로 프록시한다.
|
||||||
|
|
||||||
|
### `start_docker_wsl.ps1`
|
||||||
|
|
||||||
|
역할:
|
||||||
|
|
||||||
|
1. Windows 경로를 WSL 경로로 안전하게 바꾼다.
|
||||||
|
2. WSL 내부 Docker를 사용해 `docker compose up --build -d`를 실행한다.
|
||||||
|
3. 한글 경로와 공백 경로에서도 안정적으로 실행되게 한다.
|
||||||
|
|
||||||
|
### `stop_docker_wsl.ps1`
|
||||||
|
|
||||||
|
역할:
|
||||||
|
|
||||||
|
1. 같은 방식으로 WSL 내부에서 `docker compose down`을 실행한다.
|
||||||
|
|
||||||
|
### `start_docker_wsl.bat`, `stop_docker_wsl.bat`
|
||||||
|
|
||||||
|
역할:
|
||||||
|
|
||||||
|
1. PowerShell 스크립트를 쉽게 실행하는 래퍼 역할을 한다.
|
||||||
|
|
||||||
|
### `server.js`
|
||||||
|
|
||||||
|
중요 수정 사항:
|
||||||
|
|
||||||
|
1. `dotenv.config({ override: true })`가 아니라 `dotenv.config()`를 사용한다.
|
||||||
|
|
||||||
|
이유:
|
||||||
|
|
||||||
|
1. Compose나 실행 환경이 주는 환경변수를 `.env`가 덮어써 버리면 안 된다.
|
||||||
|
2. 외부 DB 정보와 포트 설정 등 실행 환경 우선 구조를 유지해야 한다.
|
||||||
|
|
||||||
|
### `vite.config.ts`
|
||||||
|
|
||||||
|
중요 수정 사항:
|
||||||
|
|
||||||
|
1. 프록시 타깃을 고정 `localhost:3000`이 아니라 환경변수 기반으로 받도록 바꿨다.
|
||||||
|
|
||||||
|
현재 구조:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const proxyTarget = process.env.VITE_DEV_PROXY_TARGET || 'http://localhost:3000';
|
||||||
|
```
|
||||||
|
|
||||||
|
이유:
|
||||||
|
|
||||||
|
1. 로컬에서 직접 프런트를 띄울 때는 `localhost:3000`이 맞다.
|
||||||
|
2. Docker 안에서는 `frontend` 컨테이너에서 보는 `localhost`가 백엔드가 아니므로 `backend:3000`을 써야 한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 현재 `docker-compose.yaml` 기준 실제 동작 구조
|
||||||
|
|
||||||
|
현재 `docker-compose.yaml`은 아래 구조다.
|
||||||
|
|
||||||
|
### `backend`
|
||||||
|
|
||||||
|
1. `Dockerfile.backend`로 이미지를 빌드한다.
|
||||||
|
2. `.env`를 읽는다.
|
||||||
|
3. DB 관련 변수는 `${DB_HOST}`, `${DB_PORT}`, `${DB_USER}`, `${DB_PASS}`, `${DB_NAME}`를 그대로 사용한다.
|
||||||
|
4. 포트 `3000:3000`으로 노출한다.
|
||||||
|
5. `uploads`, `map_config.json`을 마운트한다.
|
||||||
|
|
||||||
|
### `frontend`
|
||||||
|
|
||||||
|
1. `Dockerfile.frontend`로 이미지를 빌드한다.
|
||||||
|
2. `VITE_DEV_PROXY_TARGET: http://backend:3000` 환경변수를 사용한다.
|
||||||
|
3. 포트 `8080:8080`으로 노출한다.
|
||||||
|
4. 브라우저의 `/api` 요청을 `backend`로 프록시한다.
|
||||||
|
|
||||||
|
즉, 현재 Compose는 DB를 띄우지 않고 앱 두 개만 띄운다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 사전 준비 사항
|
||||||
|
|
||||||
|
이 섹션은 Gitea에서 코드를 받기 전 또는 받은 직후에 확인해야 한다.
|
||||||
|
|
||||||
|
## 5.1 가정하는 기본 상태
|
||||||
|
|
||||||
|
이미 설치되어 있다고 가정하는 것:
|
||||||
|
|
||||||
|
1. Windows
|
||||||
|
2. WSL2
|
||||||
|
3. Ubuntu 배포판
|
||||||
|
|
||||||
|
아직 없을 수 있는 것:
|
||||||
|
|
||||||
|
1. Docker Desktop 또는 WSL 내부 Docker 사용 환경
|
||||||
|
2. Git 클라이언트
|
||||||
|
3. 프로젝트 `.env`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5.2 권장 Docker 실행 방식
|
||||||
|
|
||||||
|
현재 저장소 구조상 가장 권장하는 방식은 다음이다.
|
||||||
|
|
||||||
|
1. Windows에 Docker Desktop 설치
|
||||||
|
2. Docker Desktop에서 WSL2 통합 활성화
|
||||||
|
3. Ubuntu WSL 내부에서 `docker` 명령을 사용할 수 있게 한다.
|
||||||
|
|
||||||
|
이유:
|
||||||
|
|
||||||
|
1. 현재 `start_docker_wsl.ps1`가 WSL 내부의 `docker`를 호출하는 구조다.
|
||||||
|
2. 실제 검증도 WSL 내부 Docker 기준으로 이루어졌다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5.3 외부 DB 정보 준비
|
||||||
|
|
||||||
|
현재 구조는 외부 MySQL을 사용하므로 `.env` 파일이 반드시 필요하다.
|
||||||
|
|
||||||
|
최소한 아래 값이 필요하다.
|
||||||
|
|
||||||
|
```env
|
||||||
|
DB_HOST=<외부 MySQL 호스트>
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_USER=<외부 MySQL 계정>
|
||||||
|
DB_PASS=<외부 MySQL 비밀번호>
|
||||||
|
DB_NAME=itam
|
||||||
|
```
|
||||||
|
|
||||||
|
필요 시 추가 환경변수는 현재 백엔드 코드 기준으로 함께 넣을 수 있다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Gitea에서 소스 받기
|
||||||
|
|
||||||
|
## 6.1 작업 실행 위치
|
||||||
|
|
||||||
|
이 단계는 **Windows PowerShell** 또는 **Windows 터미널의 PowerShell**에서 수행한다.
|
||||||
|
|
||||||
|
실행 위치 이유:
|
||||||
|
|
||||||
|
1. 이후 `start_docker_wsl.ps1`도 Windows PowerShell에서 실행하는 것이 가장 자연스럽다.
|
||||||
|
2. 로컬 작업 폴더를 Windows 경로 기준으로 준비할 수 있다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6.2 소스 클론
|
||||||
|
|
||||||
|
예시:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git clone <Gitea 저장소 URL>
|
||||||
|
cd <클론된 저장소 경로>
|
||||||
|
```
|
||||||
|
|
||||||
|
현재 프로젝트처럼 한글 경로를 사용할 수도 있지만, 가능하면 너무 복잡한 경로는 피하는 것이 좋다.
|
||||||
|
|
||||||
|
현재 실제 프로젝트 경로 예시는 아래였다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
c:\Users\user\Desktop\안건 파일\itam
|
||||||
|
```
|
||||||
|
|
||||||
|
이 경로도 현재 스크립트로는 동작 가능하다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Docker 환경 준비
|
||||||
|
|
||||||
|
## 7.1 작업 실행 위치
|
||||||
|
|
||||||
|
이 단계는 **Windows PowerShell**과 **WSL Ubuntu 터미널**을 둘 다 사용한다.
|
||||||
|
|
||||||
|
1. 설치 확인은 Windows PowerShell에서 시작
|
||||||
|
2. 실제 Docker 동작 확인은 WSL Ubuntu에서 수행
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7.2 Docker Desktop 설치 여부 확인
|
||||||
|
|
||||||
|
**실행 위치: Windows PowerShell**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
docker version
|
||||||
|
```
|
||||||
|
|
||||||
|
만약 여기서 바로 안 잡혀도 현재 프로젝트는 WSL 내부 Docker를 쓰므로, 다음 단계로 넘어가 WSL 내부 확인을 한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7.3 WSL 내부 Docker 확인
|
||||||
|
|
||||||
|
**실행 위치: Windows PowerShell**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
wsl -l -v
|
||||||
|
wsl sh -lc "docker --version"
|
||||||
|
```
|
||||||
|
|
||||||
|
정상 기대 결과:
|
||||||
|
|
||||||
|
1. Ubuntu가 Running 상태
|
||||||
|
2. `docker --version`이 정상 출력
|
||||||
|
|
||||||
|
만약 `docker --version`이 실패하면, Docker Desktop 설치 및 WSL 통합을 먼저 완료해야 한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. `.env` 파일 준비
|
||||||
|
|
||||||
|
## 8.1 작업 실행 위치
|
||||||
|
|
||||||
|
이 단계는 **Windows PowerShell**, **VS Code**, 또는 아무 텍스트 편집기**에서 수행한다.
|
||||||
|
|
||||||
|
즉, 프로젝트 루트에 `.env` 파일을 만드는 작업이다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8.2 `.env` 작성
|
||||||
|
|
||||||
|
프로젝트 루트에 `.env`를 만든다.
|
||||||
|
|
||||||
|
예시:
|
||||||
|
|
||||||
|
```env
|
||||||
|
DB_HOST=your-external-db-host
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_USER=your-db-user
|
||||||
|
DB_PASS=your-db-password
|
||||||
|
DB_NAME=itam
|
||||||
|
```
|
||||||
|
|
||||||
|
주의:
|
||||||
|
|
||||||
|
1. 현재 Compose는 내부 DB를 만들지 않는다.
|
||||||
|
2. 따라서 이 값이 곧 실제 운영/개발 외부 DB 연결 정보다.
|
||||||
|
3. 이 정보가 틀리면 `backend`는 기동해도 API에서 DB 오류가 난다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 현재 Docker 파일이 어떻게 동작하는지 이해하기
|
||||||
|
|
||||||
|
## 9.1 `Dockerfile.frontend`
|
||||||
|
|
||||||
|
**확인 위치: 프로젝트 루트 / VS Code**
|
||||||
|
|
||||||
|
현재 내용 핵심:
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
FROM node:20-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci
|
||||||
|
COPY . .
|
||||||
|
EXPOSE 8080
|
||||||
|
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
|
||||||
|
```
|
||||||
|
|
||||||
|
의미:
|
||||||
|
|
||||||
|
1. Node 20 Alpine 기반
|
||||||
|
2. 의존성 설치 후 전체 소스 복사
|
||||||
|
3. Vite 개발 서버 실행
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9.2 `Dockerfile.backend`
|
||||||
|
|
||||||
|
**확인 위치: 프로젝트 루트 / VS Code**
|
||||||
|
|
||||||
|
현재 내용 핵심:
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
FROM node:20-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci
|
||||||
|
COPY . .
|
||||||
|
EXPOSE 3000
|
||||||
|
CMD ["npm", "run", "server"]
|
||||||
|
```
|
||||||
|
|
||||||
|
의미:
|
||||||
|
|
||||||
|
1. Node 20 Alpine 기반
|
||||||
|
2. Express 서버 실행
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9.3 `vite.config.ts`
|
||||||
|
|
||||||
|
**확인 위치: 프로젝트 루트 / VS Code**
|
||||||
|
|
||||||
|
현재 핵심:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const proxyTarget = process.env.VITE_DEV_PROXY_TARGET || 'http://localhost:3000';
|
||||||
|
```
|
||||||
|
|
||||||
|
그리고 `/api`, `/uploads`가 모두 `proxyTarget`으로 프록시된다.
|
||||||
|
|
||||||
|
의미:
|
||||||
|
|
||||||
|
1. 로컬 실행 시 기본값은 `localhost:3000`
|
||||||
|
2. Docker 실행 시 Compose가 `http://backend:3000`을 주입
|
||||||
|
|
||||||
|
이 수정이 있어야 Docker 안에서도 화면에 데이터가 표시된다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Docker Compose 기동
|
||||||
|
|
||||||
|
## 10.1 작업 실행 위치
|
||||||
|
|
||||||
|
이 단계는 반드시 **Windows PowerShell**에서 수행하는 것을 권장한다.
|
||||||
|
|
||||||
|
이유:
|
||||||
|
|
||||||
|
1. `start_docker_wsl.ps1`가 Windows 경로를 받아 WSL 경로로 바꾸는 구조다.
|
||||||
|
2. 한글/공백 경로에서 가장 안전하다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10.2 권장 기동 방법
|
||||||
|
|
||||||
|
**실행 위치: 프로젝트 루트의 Windows PowerShell**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\start_docker_wsl.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
또는
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\start_docker_wsl.bat
|
||||||
|
```
|
||||||
|
|
||||||
|
이 스크립트는 내부적으로 아래를 수행한다.
|
||||||
|
|
||||||
|
1. PowerShell 출력 인코딩을 UTF-8로 설정
|
||||||
|
2. 현재 Windows 경로를 WSL 경로로 변환
|
||||||
|
3. WSL 동작 확인
|
||||||
|
4. WSL 내부 Docker 동작 확인
|
||||||
|
5. `docker compose up --build -d` 수행
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10.3 직접 기동이 필요할 때
|
||||||
|
|
||||||
|
**실행 위치: WSL Ubuntu 터미널**
|
||||||
|
|
||||||
|
직접 실행 예시는 아래와 같다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /mnt/c/Users/user/Desktop/안건\ 파일/itam
|
||||||
|
docker compose up --build -d
|
||||||
|
```
|
||||||
|
|
||||||
|
하지만 현재 프로젝트는 한글 경로 이슈가 있었기 때문에, 특별한 이유가 없으면 `start_docker_wsl.ps1`를 우선 사용한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. 컨테이너 기동 후 검증
|
||||||
|
|
||||||
|
## 11.1 컨테이너 상태 확인
|
||||||
|
|
||||||
|
**실행 위치: Windows PowerShell**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
wsl sh -lc "docker ps -a --format 'table {{.Names}}\t{{.Status}}' | grep itam"
|
||||||
|
```
|
||||||
|
|
||||||
|
정상 기대 상태:
|
||||||
|
|
||||||
|
1. `itam-backend` -> `Up`
|
||||||
|
2. `itam-frontend` -> `Up`
|
||||||
|
|
||||||
|
현재는 `itam-db`, `itam-db-bootstrap`가 없어야 정상이다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11.2 백엔드 API 확인
|
||||||
|
|
||||||
|
**실행 위치: Windows PowerShell**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Invoke-WebRequest -Uri http://localhost:3000/api/assets/master -UseBasicParsing | Select-Object -ExpandProperty StatusCode
|
||||||
|
```
|
||||||
|
|
||||||
|
정상 기대값:
|
||||||
|
|
||||||
|
1. `200`
|
||||||
|
|
||||||
|
이 검사는 `backend`가 외부 DB에 정상 연결됐는지 보는 가장 직접적인 검사다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11.3 프런트 경유 API 확인
|
||||||
|
|
||||||
|
**실행 위치: Windows PowerShell**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Invoke-WebRequest -Uri http://localhost:8080/api/assets/master -UseBasicParsing | Select-Object -ExpandProperty StatusCode
|
||||||
|
```
|
||||||
|
|
||||||
|
정상 기대값:
|
||||||
|
|
||||||
|
1. `200`
|
||||||
|
|
||||||
|
이 검사는 프런트 프록시가 정상인지 확인한다.
|
||||||
|
|
||||||
|
예전에 화면에 데이터가 안 보였던 것은 외부 DB 자체가 아니라, 이 프록시 경로가 잘못돼 있었기 때문이다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11.4 브라우저 화면 확인
|
||||||
|
|
||||||
|
**실행 위치: 브라우저**
|
||||||
|
|
||||||
|
```text
|
||||||
|
http://localhost:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
확인 포인트:
|
||||||
|
|
||||||
|
1. 화면이 열리는지
|
||||||
|
2. 목록/대시보드/테이블 데이터가 비어 있지 않은지
|
||||||
|
3. 모달 진입 시 데이터가 정상적으로 보이는지
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. 지금 데이터가 표시되는 원리
|
||||||
|
|
||||||
|
현재는 내부 DB로 데이터를 옮겨 담지 않는다.
|
||||||
|
|
||||||
|
현재 실제 동작 원리는 다음과 같다.
|
||||||
|
|
||||||
|
1. 브라우저가 `frontend`에 접속한다.
|
||||||
|
2. 프런트가 `/api/...`로 요청한다.
|
||||||
|
3. Vite 프록시가 `backend:3000`으로 요청을 넘긴다.
|
||||||
|
4. `backend`가 `.env`의 외부 MySQL에 직접 접속한다.
|
||||||
|
5. 조회 결과 JSON을 프런트가 받아 화면에 렌더링한다.
|
||||||
|
|
||||||
|
즉, 현재는 아래 구조다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
Browser -> frontend -> backend -> external MySQL
|
||||||
|
```
|
||||||
|
|
||||||
|
예전 외부 DB 구조에서 화면에 데이터가 안 보였던 이유는 외부 DB 때문이 아니라, 프런트 컨테이너가 `localhost:3000`을 잘못 바라보고 있었기 때문이다.
|
||||||
|
|
||||||
|
지금은 `VITE_DEV_PROXY_TARGET: http://backend:3000`으로 수정되어 있기 때문에 정상 표시된다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. 자주 헷갈리는 포인트
|
||||||
|
|
||||||
|
## 13.1 현재는 내부 DB 컨테이너가 없다
|
||||||
|
|
||||||
|
현재 `docker-compose.yaml`에는 아래가 없다.
|
||||||
|
|
||||||
|
1. `db` 서비스
|
||||||
|
2. `db-bootstrap` 서비스
|
||||||
|
3. `itam_mysql_data` 볼륨
|
||||||
|
|
||||||
|
즉, DB는 Docker 스택 밖에 있다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13.2 현재는 `.env`가 곧 실제 DB 연결 정보다
|
||||||
|
|
||||||
|
현재 `backend`는 아래처럼 Compose에서 그대로 받는다.
|
||||||
|
|
||||||
|
1. `DB_HOST: ${DB_HOST}`
|
||||||
|
2. `DB_PORT: ${DB_PORT}`
|
||||||
|
3. `DB_USER: ${DB_USER}`
|
||||||
|
4. `DB_PASS: ${DB_PASS}`
|
||||||
|
5. `DB_NAME: ${DB_NAME}`
|
||||||
|
|
||||||
|
즉, `.env`를 틀리게 적으면 화면도 데이터가 안 뜬다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13.3 `server.js`는 여전히 중요하게 수정된 상태다
|
||||||
|
|
||||||
|
현재 `server.js`는 `dotenv.config()`를 사용한다.
|
||||||
|
|
||||||
|
이 구조는 이후 Compose나 실행 환경에서 변수를 주입할 때, 애플리케이션이 그 값을 받아들일 수 있게 하기 위해 유지해야 한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14. 스택 중지 방법
|
||||||
|
|
||||||
|
## 14.1 작업 실행 위치
|
||||||
|
|
||||||
|
**Windows PowerShell / 프로젝트 루트**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14.2 권장 종료 명령
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\stop_docker_wsl.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
또는
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\stop_docker_wsl.bat
|
||||||
|
```
|
||||||
|
|
||||||
|
이 스크립트는 내부적으로 WSL 경로 변환 후 `docker compose down`을 수행한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 15. 장애 발생 시 점검 순서
|
||||||
|
|
||||||
|
## 15.1 `frontend` 화면은 뜨는데 데이터가 없을 때
|
||||||
|
|
||||||
|
**실행 위치: Windows PowerShell**
|
||||||
|
|
||||||
|
먼저 아래 두 API를 분리해서 본다.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Invoke-WebRequest -Uri http://localhost:3000/api/assets/master -UseBasicParsing | Select-Object -ExpandProperty StatusCode
|
||||||
|
Invoke-WebRequest -Uri http://localhost:8080/api/assets/master -UseBasicParsing | Select-Object -ExpandProperty StatusCode
|
||||||
|
```
|
||||||
|
|
||||||
|
판단 기준:
|
||||||
|
|
||||||
|
1. `3000`은 200이고 `8080`만 실패 -> 프런트 프록시 문제
|
||||||
|
2. 둘 다 실패 -> 백엔드 또는 외부 DB 연결 문제
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 15.2 백엔드가 외부 DB에 연결되지 않을 때
|
||||||
|
|
||||||
|
**실행 위치: Windows PowerShell**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
wsl sh -lc "docker logs --tail=200 itam-backend"
|
||||||
|
```
|
||||||
|
|
||||||
|
점검 항목:
|
||||||
|
|
||||||
|
1. `.env`의 DB 정보가 정확한지
|
||||||
|
2. 외부 DB 서버 접근이 가능한지
|
||||||
|
3. 계정/비밀번호가 맞는지
|
||||||
|
4. 방화벽 또는 네트워크 이슈가 없는지
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 15.3 프런트 프록시가 의심될 때
|
||||||
|
|
||||||
|
**확인 위치: `vite.config.ts`, `docker-compose.yaml`**
|
||||||
|
|
||||||
|
다음 두 설정이 유지되는지 확인한다.
|
||||||
|
|
||||||
|
`vite.config.ts`
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const proxyTarget = process.env.VITE_DEV_PROXY_TARGET || 'http://localhost:3000';
|
||||||
|
```
|
||||||
|
|
||||||
|
`docker-compose.yaml`
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
VITE_DEV_PROXY_TARGET: http://backend:3000
|
||||||
|
```
|
||||||
|
|
||||||
|
이 둘 중 하나라도 바뀌면 Docker 안에서 화면 데이터가 다시 안 보일 수 있다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 16. 현재 기준 재현 절차 요약
|
||||||
|
|
||||||
|
가장 짧게 정리하면 아래 순서다.
|
||||||
|
|
||||||
|
1. Gitea에서 소스를 클론한다.
|
||||||
|
2. Windows PowerShell에서 프로젝트 루트로 이동한다.
|
||||||
|
3. `.env`에 외부 MySQL 정보를 작성한다.
|
||||||
|
4. Docker Desktop + WSL 통합 또는 WSL 내부 Docker 사용 가능 상태를 만든다.
|
||||||
|
5. `start_docker_wsl.ps1`를 실행한다.
|
||||||
|
6. `http://localhost:3000/api/assets/master`가 200인지 확인한다.
|
||||||
|
7. `http://localhost:8080/api/assets/master`가 200인지 확인한다.
|
||||||
|
8. 브라우저에서 `http://localhost:8080`을 열어 실제 데이터 표시를 확인한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 17. 현재 최종 결론
|
||||||
|
|
||||||
|
현재 저장소의 도커라이징 구조는 실무 표준에 맞는 `무상태 앱 컨테이너 + 외부 DB` 구조다.
|
||||||
|
|
||||||
|
현재 핵심은 아래 세 가지다.
|
||||||
|
|
||||||
|
1. `backend`는 외부 MySQL에 직접 연결한다.
|
||||||
|
2. `frontend`는 `backend:3000`으로 API 프록시한다.
|
||||||
|
3. WSL 경로 변환 스크립트를 통해 Windows 한글 경로에서도 안정적으로 실행한다.
|
||||||
|
|
||||||
|
즉, 이 문서대로 진행하면 Gitea 소스만 받은 상태에서 지금과 같은 Docker 실행 구조를 재현할 수 있다.
|
||||||
730
doc_readme2.md
Normal file
730
doc_readme2.md
Normal file
@@ -0,0 +1,730 @@
|
|||||||
|
# ITAM 도커라이징 최종 재현 가이드
|
||||||
|
|
||||||
|
## 1. 문서 목적
|
||||||
|
|
||||||
|
이 문서는 현재 Git 저장소에 올라간 파일만 가지고, 지금과 동일한 수준으로 ITAM 시스템을 도커라이징하고 실행하는 절차를 처음부터 끝까지 정리한 최종 가이드다.
|
||||||
|
|
||||||
|
이 문서만 읽어도 아래 목표를 달성할 수 있게 작성한다.
|
||||||
|
|
||||||
|
1. 현재 저장소 구조를 이해한다.
|
||||||
|
2. 왜 이렇게 도커라이징했는지 판단 근거를 안다.
|
||||||
|
3. WSL2 기반으로 실제 스택을 기동한다.
|
||||||
|
4. 외부 MySQL에서 내부 MySQL 컨테이너로 초기 데이터를 bootstrap 한다.
|
||||||
|
5. 프런트 8080과 백엔드 3000이 모두 정상 동작하는지 검증한다.
|
||||||
|
6. 재초기화, 재기동, 장애 확인까지 수행한다.
|
||||||
|
|
||||||
|
이 문서는 최종 성공 구조 기준이다. 실패 기록은 `doc_readme.md`를 본다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 최종 목표 구조
|
||||||
|
|
||||||
|
현재 최종 구조는 아래 4개 서비스/역할로 나뉜다.
|
||||||
|
|
||||||
|
1. `frontend`: Vite 개발 서버 컨테이너, 포트 8080
|
||||||
|
2. `backend`: Express API 서버 컨테이너, 포트 3000
|
||||||
|
3. `db`: MySQL 8 컨테이너, 포트 3306
|
||||||
|
4. `db-bootstrap`: 외부 MySQL -> 내부 MySQL로 1회성 복제 수행 후 종료되는 도우미 컨테이너
|
||||||
|
|
||||||
|
논리 흐름은 다음과 같다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
브라우저 -> frontend:8080 -> Vite proxy -> backend:3000 -> db:3306
|
||||||
|
\
|
||||||
|
-> /uploads -> backend 정적 경로
|
||||||
|
|
||||||
|
초기 1회 기동 시
|
||||||
|
외부 MySQL(.env) -> db-bootstrap -> 내부 MySQL(db)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 왜 이 구조를 선택했는가
|
||||||
|
|
||||||
|
이 저장소는 처음부터 운영형 정적 배포 앱이 아니었다. 실제 구조는 다음과 같았다.
|
||||||
|
|
||||||
|
1. 프런트는 Vite 개발 서버가 따로 돈다.
|
||||||
|
2. 백엔드는 Express API가 따로 돈다.
|
||||||
|
3. 프런트는 상대 경로 `/api`를 호출한다.
|
||||||
|
4. 백엔드는 프런트의 `dist`를 서빙하지 않는다.
|
||||||
|
|
||||||
|
따라서 내일 바로 시연 가능한 수준까지 빠르게 안정화하려면 아래 전략이 가장 맞다.
|
||||||
|
|
||||||
|
1. 프런트를 Vite dev server 그대로 컨테이너화한다.
|
||||||
|
2. 백엔드를 별도 컨테이너로 유지한다.
|
||||||
|
3. DB는 MySQL 8 컨테이너로 묶되, 초기 데이터는 외부 DB에서 복제한다.
|
||||||
|
4. 프런트 프록시는 컨테이너 네트워크 서비스명 `backend`로 붙게 한다.
|
||||||
|
|
||||||
|
즉, 현재 구조는 "개발형 구조를 Docker로 재현한 시연/개발용 Compose"다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 저장소 내 최종 관련 파일 목록
|
||||||
|
|
||||||
|
현재 도커라이징과 직접 관련된 핵심 파일은 아래와 같다.
|
||||||
|
|
||||||
|
1. `.dockerignore`
|
||||||
|
2. `Dockerfile.frontend`
|
||||||
|
3. `Dockerfile.backend`
|
||||||
|
4. `docker-compose.yaml`
|
||||||
|
5. `start_docker_wsl.ps1`
|
||||||
|
6. `stop_docker_wsl.ps1`
|
||||||
|
7. `start_docker_wsl.bat`
|
||||||
|
8. `stop_docker_wsl.bat`
|
||||||
|
9. `docker/mysql/init/README.md`
|
||||||
|
10. `server.js`
|
||||||
|
11. `vite.config.ts`
|
||||||
|
|
||||||
|
각 파일 역할은 다음과 같다.
|
||||||
|
|
||||||
|
### 4.1 `.dockerignore`
|
||||||
|
|
||||||
|
Docker build context에서 제외할 파일을 정의한다.
|
||||||
|
|
||||||
|
주요 제외 대상은 다음과 같다.
|
||||||
|
|
||||||
|
1. `node_modules`
|
||||||
|
2. `dist`
|
||||||
|
3. `build`
|
||||||
|
4. `.git`
|
||||||
|
5. `.env`
|
||||||
|
6. `uploads`
|
||||||
|
7. `*.xlsx`
|
||||||
|
8. `*.log`
|
||||||
|
|
||||||
|
### 4.2 `Dockerfile.frontend`
|
||||||
|
|
||||||
|
프런트 컨테이너 이미지 정의다.
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
|
||||||
|
```
|
||||||
|
|
||||||
|
이 이미지는 Vite dev server를 컨테이너에서 띄우기 위한 것이다.
|
||||||
|
|
||||||
|
### 4.3 `Dockerfile.backend`
|
||||||
|
|
||||||
|
백엔드 컨테이너 이미지 정의다.
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["npm", "run", "server"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.4 `docker-compose.yaml`
|
||||||
|
|
||||||
|
전체 스택의 핵심 파일이다.
|
||||||
|
|
||||||
|
현재 최종 구성은 다음 논리를 가진다.
|
||||||
|
|
||||||
|
1. `db`는 MySQL 8 내부 DB다.
|
||||||
|
2. `db-bootstrap`은 외부 DB 데이터를 내부 DB로 1회 복제한다.
|
||||||
|
3. `backend`는 내부 `db`에 붙는다.
|
||||||
|
4. `frontend`는 `backend` 서비스명으로 프록시한다.
|
||||||
|
|
||||||
|
### 4.5 `start_docker_wsl.ps1`
|
||||||
|
|
||||||
|
Windows에서 WSL 경유로 Docker Compose를 안전하게 기동하는 진입점이다.
|
||||||
|
|
||||||
|
핵심은 다음 두 가지다.
|
||||||
|
|
||||||
|
1. 프로젝트 Windows 경로를 `wslpath`로 WSL 경로로 바꾼다.
|
||||||
|
2. 그 경로로 이동한 뒤 `docker compose up --build -d`를 수행한다.
|
||||||
|
|
||||||
|
### 4.6 `stop_docker_wsl.ps1`
|
||||||
|
|
||||||
|
같은 방식으로 WSL 내부에서 `docker compose down`을 수행해 스택을 안전하게 내린다.
|
||||||
|
|
||||||
|
### 4.7 `start_docker_wsl.bat`, `stop_docker_wsl.bat`
|
||||||
|
|
||||||
|
더블클릭 또는 간단 실행용 래퍼다. 내부적으로 PowerShell 스크립트를 호출한다.
|
||||||
|
|
||||||
|
### 4.8 `server.js`
|
||||||
|
|
||||||
|
중요 포인트는 다음 두 가지다.
|
||||||
|
|
||||||
|
1. `dotenv.config();`를 사용한다.
|
||||||
|
2. `dotenv.config({ override: true })`를 사용하지 않는다.
|
||||||
|
|
||||||
|
이 차이로 Compose 환경변수 `DB_HOST=db`가 `.env`보다 우선하도록 보장한다.
|
||||||
|
|
||||||
|
### 4.9 `vite.config.ts`
|
||||||
|
|
||||||
|
현재 프록시는 환경변수 기반으로 동작한다.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const proxyTarget = process.env.VITE_DEV_PROXY_TARGET || 'http://localhost:3000';
|
||||||
|
```
|
||||||
|
|
||||||
|
로컬 PC에서 직접 Vite를 띄우면 기본값 `http://localhost:3000`을 쓴다.
|
||||||
|
컨테이너에서는 Compose가 `http://backend:3000`을 주입한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 현재 최종 `docker-compose.yaml` 구조 설명
|
||||||
|
|
||||||
|
아래는 실제 동작 관점에서 읽어야 할 핵심 내용이다.
|
||||||
|
|
||||||
|
### 5.1 `db` 서비스
|
||||||
|
|
||||||
|
역할:
|
||||||
|
|
||||||
|
1. 내부 MySQL 데이터 저장소
|
||||||
|
2. 앱이 최종적으로 붙는 DB
|
||||||
|
|
||||||
|
핵심 설정:
|
||||||
|
|
||||||
|
1. 이미지: `mysql:8.0`
|
||||||
|
2. DB 이름: `itam`
|
||||||
|
3. 앱 계정: `itam_admin`
|
||||||
|
4. 데이터 볼륨: `itam_mysql_data`
|
||||||
|
5. healthcheck 사용
|
||||||
|
|
||||||
|
healthcheck는 `mysqladmin ping`으로 동작하며, `backend`와 `db-bootstrap`은 이 상태를 기다린다.
|
||||||
|
|
||||||
|
### 5.2 `db-bootstrap` 서비스
|
||||||
|
|
||||||
|
역할:
|
||||||
|
|
||||||
|
1. 외부 원본 DB에서 내부 `db`로 초기 데이터 복제
|
||||||
|
2. 1회성 작업 후 종료
|
||||||
|
|
||||||
|
핵심 포인트:
|
||||||
|
|
||||||
|
1. `.env`를 읽어 외부 DB 접속 정보를 가져온다.
|
||||||
|
2. 내부 `db`에 `asset_core` 테이블이 이미 존재하면 아무 것도 하지 않고 종료한다.
|
||||||
|
3. 그렇지 않으면 `mysqldump | mysql` 파이프라인으로 복제한다.
|
||||||
|
4. `restart: "no"` 이므로 정상 종료 후 반복 실행하지 않는다.
|
||||||
|
|
||||||
|
또한 source DB와 target DB 변수는 분리돼 있다.
|
||||||
|
|
||||||
|
1. source: `SOURCE_DB_*`
|
||||||
|
2. target: `TARGET_DB_*`
|
||||||
|
|
||||||
|
이 구조로 외부 원본 DB 자격증명과 내부 컨테이너 DB 자격증명이 섞이지 않는다.
|
||||||
|
|
||||||
|
### 5.3 `backend` 서비스
|
||||||
|
|
||||||
|
역할:
|
||||||
|
|
||||||
|
1. Express API 제공
|
||||||
|
2. 내부 `db`에 연결
|
||||||
|
3. `/uploads` 정적 제공
|
||||||
|
|
||||||
|
핵심 포인트:
|
||||||
|
|
||||||
|
1. `env_file: .env`를 유지하지만,
|
||||||
|
2. Compose `environment`에서 `DB_HOST=db`, `DB_PORT=3306`, `DB_USER=itam_admin`, `DB_PASS=itam1234`, `DB_NAME=itam`를 다시 지정한다.
|
||||||
|
3. `depends_on`은 `db` healthy와 `db-bootstrap` 성공 종료를 모두 기다린다.
|
||||||
|
|
||||||
|
즉, 백엔드는 DB bootstrap이 끝난 뒤 시작한다.
|
||||||
|
|
||||||
|
### 5.4 `frontend` 서비스
|
||||||
|
|
||||||
|
역할:
|
||||||
|
|
||||||
|
1. Vite dev server 제공
|
||||||
|
2. 브라우저 요청 `/api`, `/uploads`를 `backend`로 프록시
|
||||||
|
|
||||||
|
핵심 포인트:
|
||||||
|
|
||||||
|
1. `VITE_DEV_PROXY_TARGET: http://backend:3000`
|
||||||
|
2. `CHOKIDAR_USEPOLLING: "true"`
|
||||||
|
3. `npm run dev -- --host 0.0.0.0`
|
||||||
|
|
||||||
|
중요한 이유는 컨테이너 안의 `localhost`가 호스트의 `localhost`가 아니기 때문이다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 사전 준비 조건
|
||||||
|
|
||||||
|
이 저장소를 지금처럼 기동하려면 다음 전제가 필요하다.
|
||||||
|
|
||||||
|
### 6.1 운영체제와 런타임
|
||||||
|
|
||||||
|
1. Windows
|
||||||
|
2. WSL2 Ubuntu 설치 및 실행 중
|
||||||
|
3. Docker CLI가 WSL 내부에서 동작 가능
|
||||||
|
|
||||||
|
권장 확인 명령:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
wsl -l -v
|
||||||
|
wsl sh -lc "docker --version"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 `.env` 파일
|
||||||
|
|
||||||
|
현재 최종 구조는 "첫 기동 시 외부 DB에서 내부 DB로 bootstrap" 하는 방식이므로 `.env`가 반드시 필요하다.
|
||||||
|
|
||||||
|
최소한 다음 값은 외부 원본 DB를 가리켜야 한다.
|
||||||
|
|
||||||
|
```env
|
||||||
|
DB_HOST=<external-mysql-host>
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_USER=<external-db-user>
|
||||||
|
DB_PASS=<external-db-password>
|
||||||
|
DB_NAME=itam
|
||||||
|
```
|
||||||
|
|
||||||
|
주의:
|
||||||
|
|
||||||
|
1. `.env`는 `db-bootstrap`이 외부 원본 DB에 접속할 때 사용한다.
|
||||||
|
2. `backend`는 최종적으로 내부 `db` 컨테이너를 쓰므로, 런타임에서는 Compose `environment`가 우선한다.
|
||||||
|
|
||||||
|
### 6.3 한글 경로 주의
|
||||||
|
|
||||||
|
현재 프로젝트 경로는 한글과 공백을 포함한다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
c:\Users\user\Desktop\안건 파일\itam
|
||||||
|
```
|
||||||
|
|
||||||
|
이 때문에 Docker 관련 명령은 수동으로 경로를 조립하지 말고, `start_docker_wsl.ps1` / `stop_docker_wsl.ps1`을 우선 사용해야 한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 첫 기동 절차
|
||||||
|
|
||||||
|
이 절차는 "Git에서 소스를 받은 뒤 처음 올리는 경우" 기준이다.
|
||||||
|
|
||||||
|
### 7.1 저장소 준비
|
||||||
|
|
||||||
|
1. 저장소를 받는다.
|
||||||
|
2. `.env`가 올바른 외부 원본 DB를 가리키는지 확인한다.
|
||||||
|
3. WSL이 켜져 있는지 확인한다.
|
||||||
|
|
||||||
|
### 7.2 권장 실행 방법
|
||||||
|
|
||||||
|
Windows PowerShell에서 프로젝트 루트로 이동한 뒤 아래 중 하나를 사용한다.
|
||||||
|
|
||||||
|
방법 A:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\start_docker_wsl.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
방법 B:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\start_docker_wsl.bat
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.3 내부 실행 순서
|
||||||
|
|
||||||
|
스크립트는 내부적으로 다음 순서로 동작한다.
|
||||||
|
|
||||||
|
1. 현재 Windows 경로를 WSL 경로로 변환한다.
|
||||||
|
2. WSL 동작 여부를 확인한다.
|
||||||
|
3. WSL 내부 Docker 사용 가능 여부를 확인한다.
|
||||||
|
4. `docker compose up --build -d`를 수행한다.
|
||||||
|
|
||||||
|
### 7.4 기대되는 컨테이너 순서
|
||||||
|
|
||||||
|
정상이라면 다음 순서로 올라온다.
|
||||||
|
|
||||||
|
1. `itam-db`
|
||||||
|
2. `itam-db-bootstrap`
|
||||||
|
3. `itam-backend`
|
||||||
|
4. `itam-frontend`
|
||||||
|
|
||||||
|
`itam-db-bootstrap`은 정상이라면 최종 상태가 `Exited (0)`이어야 한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 첫 기동 후 검증 절차
|
||||||
|
|
||||||
|
기동 후에는 반드시 아래 검증을 수행한다.
|
||||||
|
|
||||||
|
### 8.1 컨테이너 상태 확인
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
wsl sh -lc "docker ps -a --format 'table {{.Names}}\t{{.Status}}' | grep itam"
|
||||||
|
```
|
||||||
|
|
||||||
|
정상 기대 상태:
|
||||||
|
|
||||||
|
1. `itam-db` -> `Up ... (healthy)`
|
||||||
|
2. `itam-db-bootstrap` -> `Exited (0)`
|
||||||
|
3. `itam-backend` -> `Up`
|
||||||
|
4. `itam-frontend` -> `Up`
|
||||||
|
|
||||||
|
### 8.2 백엔드 API 직접 확인
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Invoke-WebRequest -Uri http://localhost:3000/api/assets/master -UseBasicParsing | Select-Object -ExpandProperty StatusCode
|
||||||
|
```
|
||||||
|
|
||||||
|
정상 기대값:
|
||||||
|
|
||||||
|
1. `200`
|
||||||
|
|
||||||
|
### 8.3 프런트 경유 API 확인
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Invoke-WebRequest -Uri http://localhost:8080/api/assets/master -UseBasicParsing | Select-Object -ExpandProperty StatusCode
|
||||||
|
```
|
||||||
|
|
||||||
|
정상 기대값:
|
||||||
|
|
||||||
|
1. `200`
|
||||||
|
|
||||||
|
### 8.4 데이터가 실제로 들어왔는지 확인
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
wsl sh -lc "docker exec itam-db mysql -uitam_admin -pitam1234 -D itam -e 'SHOW TABLES' | head -n 20"
|
||||||
|
```
|
||||||
|
|
||||||
|
정상이라면 아래와 같은 테이블들이 보여야 한다.
|
||||||
|
|
||||||
|
1. `asset_core`
|
||||||
|
2. `asset_remote`
|
||||||
|
3. `asset_spec`
|
||||||
|
4. `asset_location`
|
||||||
|
5. `asset_history`
|
||||||
|
6. `asset_software_perpetual`
|
||||||
|
7. `asset_software_subscription`
|
||||||
|
8. `hardware_components_master`
|
||||||
|
9. `job_spec_standards`
|
||||||
|
|
||||||
|
### 8.5 브라우저 화면 확인
|
||||||
|
|
||||||
|
브라우저에서 아래 주소를 연다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
http://localhost:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
목록/대시보드 데이터가 보이면 화면까지 정상 연결된 것이다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 재기동 절차
|
||||||
|
|
||||||
|
코드만 수정됐고 DB는 유지하고 싶다면 다음처럼 하면 된다.
|
||||||
|
|
||||||
|
### 9.1 스택 종료
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\stop_docker_wsl.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
또는
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\stop_docker_wsl.bat
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.2 스택 재기동
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\start_docker_wsl.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
이 경우 `itam_mysql_data` 볼륨이 유지되므로, `db-bootstrap`은 내부 DB에 `asset_core`가 이미 있음을 감지하고 빠르게 종료한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. DB를 완전히 다시 초기화하는 절차
|
||||||
|
|
||||||
|
외부 원본 DB에서 다시 처음부터 내부 DB를 복제하고 싶다면, MySQL 볼륨을 제거해야 한다.
|
||||||
|
|
||||||
|
### 10.1 스택 중지
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\stop_docker_wsl.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
### 10.2 MySQL 데이터 볼륨 삭제
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
wsl sh -lc "docker volume rm -f itam_itam_mysql_data"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 10.3 다시 시작
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\start_docker_wsl.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
이때 `db-bootstrap`이 외부 DB에서 내부 DB로 전체를 다시 복제한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. 현재 구조에서 꼭 알아야 할 설계 포인트
|
||||||
|
|
||||||
|
### 11.1 `server.js`의 `dotenv.config()` 변경 이유
|
||||||
|
|
||||||
|
백엔드가 내부 DB로 붙게 하려면 Compose가 준 환경변수가 `.env`보다 우선해야 한다.
|
||||||
|
|
||||||
|
만약 아래처럼 `override: true`를 쓰면 안 된다.
|
||||||
|
|
||||||
|
```js
|
||||||
|
dotenv.config({ override: true });
|
||||||
|
```
|
||||||
|
|
||||||
|
이렇게 되면 내부 `db`가 아니라 `.env`의 외부 DB로 다시 붙을 수 있다.
|
||||||
|
|
||||||
|
현재는 아래가 맞다.
|
||||||
|
|
||||||
|
```js
|
||||||
|
dotenv.config();
|
||||||
|
```
|
||||||
|
|
||||||
|
### 11.2 왜 `docker-entrypoint-initdb.d` 기반 dump 파일을 안 쓰는가
|
||||||
|
|
||||||
|
처음에는 이 방식을 시도했지만, 실제 데이터의 긴 문자열/깨진 텍스트 때문에 import가 line 97에서 중단됐다.
|
||||||
|
|
||||||
|
그래서 현재는 더 안정적인 아래 방식을 쓴다.
|
||||||
|
|
||||||
|
1. 외부 DB에서 `mysqldump`
|
||||||
|
2. 파이프로 내부 `db`에 즉시 `mysql` import
|
||||||
|
|
||||||
|
즉, 파일 중간 생성물을 신뢰하지 않는 구조다.
|
||||||
|
|
||||||
|
### 11.3 왜 프런트 프록시 타깃을 환경변수화했는가
|
||||||
|
|
||||||
|
로컬 직접 실행과 컨테이너 실행의 네트워크 기준이 다르기 때문이다.
|
||||||
|
|
||||||
|
1. 로컬 직접 실행: `localhost:3000`이 맞다.
|
||||||
|
2. 컨테이너 내부 실행: `backend:3000`이 맞다.
|
||||||
|
|
||||||
|
그래서 `vite.config.ts`는 둘 다 수용할 수 있게 작성됐다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. 문제 발생 시 진단 순서
|
||||||
|
|
||||||
|
이 프로젝트에서는 문제를 아래 순서로 자르면 가장 빠르다.
|
||||||
|
|
||||||
|
### 12.1 브라우저 화면에 데이터가 없을 때
|
||||||
|
|
||||||
|
먼저 다음 둘을 분리해서 본다.
|
||||||
|
|
||||||
|
1. `http://localhost:3000/api/assets/master`
|
||||||
|
2. `http://localhost:8080/api/assets/master`
|
||||||
|
|
||||||
|
판단 기준:
|
||||||
|
|
||||||
|
1. `3000`은 200이고 `8080`만 실패면 프런트 프록시 문제다.
|
||||||
|
2. 둘 다 실패면 백엔드 또는 DB 문제다.
|
||||||
|
|
||||||
|
### 12.2 DB bootstrap이 성공했는지 확인할 때
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
wsl sh -lc "docker ps -a --format 'table {{.Names}}\t{{.Status}}' | grep itam"
|
||||||
|
```
|
||||||
|
|
||||||
|
여기서 `itam-db-bootstrap`이 `Exited (0)`인지 본다.
|
||||||
|
|
||||||
|
### 12.3 내부 DB에 실제 데이터가 있는지 확인할 때
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
wsl sh -lc "docker exec itam-db mysql -uitam_admin -pitam1234 -D itam -e 'SHOW TABLES'"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 12.4 백엔드 로그 확인
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
wsl sh -lc "docker logs --tail=200 itam-backend"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 12.5 DB 로그 확인
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
wsl sh -lc "docker logs --tail=200 itam-db"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 12.6 프런트 로그 확인
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
wsl sh -lc "docker logs --tail=200 itam-frontend"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. 자주 나올 수 있는 장애와 해석
|
||||||
|
|
||||||
|
### 13.1 `docker` 명령이 PowerShell에서 안 보임
|
||||||
|
|
||||||
|
의미:
|
||||||
|
|
||||||
|
1. Windows 셸이 아니라 WSL에서 Docker를 쓰는 환경이다.
|
||||||
|
|
||||||
|
대응:
|
||||||
|
|
||||||
|
1. `start_docker_wsl.ps1` 사용
|
||||||
|
|
||||||
|
### 13.2 `asset_core` 테이블 없음
|
||||||
|
|
||||||
|
의미:
|
||||||
|
|
||||||
|
1. 내부 DB 초기화가 안 됐거나 bootstrap이 안 끝났다.
|
||||||
|
|
||||||
|
대응:
|
||||||
|
|
||||||
|
1. `db-bootstrap` 상태 확인
|
||||||
|
2. `.env` 외부 DB 접속 정보 확인
|
||||||
|
3. 필요하면 볼륨 삭제 후 재초기화
|
||||||
|
|
||||||
|
### 13.3 `3000` API는 되는데 화면은 비어 있음
|
||||||
|
|
||||||
|
의미:
|
||||||
|
|
||||||
|
1. DB는 정상이고 프런트 프록시 또는 화면 렌더링 문제다.
|
||||||
|
|
||||||
|
대응:
|
||||||
|
|
||||||
|
1. `8080/api/assets/master` 상태 먼저 확인
|
||||||
|
|
||||||
|
### 13.4 `db-bootstrap`가 실패 종료함
|
||||||
|
|
||||||
|
의미 후보:
|
||||||
|
|
||||||
|
1. `.env` 외부 DB 접속 정보 오류
|
||||||
|
2. 외부 DB 네트워크 접근 불가
|
||||||
|
3. 외부 계정 권한 문제
|
||||||
|
|
||||||
|
대응:
|
||||||
|
|
||||||
|
1. `docker logs itam-db-bootstrap` 확인
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14. 현재 최종 검증 완료 상태
|
||||||
|
|
||||||
|
이 저장소는 아래 상태까지 검증이 완료됐다.
|
||||||
|
|
||||||
|
1. WSL2 Ubuntu에서 Docker 실행 가능
|
||||||
|
2. `start_docker_wsl.ps1`로 전체 스택 기동 가능
|
||||||
|
3. `db` 컨테이너 healthcheck 통과
|
||||||
|
4. `db-bootstrap`가 외부 DB에서 내부 DB로 데이터 복제 후 `Exited (0)` 종료
|
||||||
|
5. `backend`가 내부 `db`를 사용해 API 응답 가능
|
||||||
|
6. `frontend`가 `backend`를 프록시해 8080 기준 화면/API 동작 가능
|
||||||
|
7. 내부 MySQL에 실데이터 적재 확인
|
||||||
|
|
||||||
|
즉, 현재 Git에 올라간 상태만으로도 WSL2와 외부 원본 DB 정보만 있으면 지금과 같은 수준의 Docker 실행 재현이 가능하다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 15. 현재 구조의 한계와 다음 단계
|
||||||
|
|
||||||
|
현재 구조는 충분히 시연 가능하고 개발 재현도 가능하지만, 다음은 아직 별도 작업이 필요하다.
|
||||||
|
|
||||||
|
1. 운영형 정적 배포 구조 전환
|
||||||
|
2. 외부 DB 없이도 완전 독립 실행 가능한 정식 dump/backup 체계
|
||||||
|
3. `.env.example` 정리
|
||||||
|
4. DB bootstrap 전용 계정/권한 최소화
|
||||||
|
5. 장기적으로 `map_config.json` 파일 저장 정책 정리
|
||||||
|
|
||||||
|
하지만 "현재 저장소만으로 지금과 같은 Docker 실행 상태 재현"이라는 목표는 이미 충족한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 16. 빠른 실행 요약
|
||||||
|
|
||||||
|
가장 짧게 요약하면 다음 순서다.
|
||||||
|
|
||||||
|
1. `.env`에 외부 원본 MySQL 접속 정보를 넣는다.
|
||||||
|
2. WSL2 Ubuntu와 WSL 내부 Docker가 살아 있는지 확인한다.
|
||||||
|
3. `start_docker_wsl.ps1`를 실행한다.
|
||||||
|
4. `itam-db-bootstrap`가 `Exited (0)`인지 확인한다.
|
||||||
|
5. `http://localhost:3000/api/assets/master`와 `http://localhost:8080/api/assets/master`가 모두 200인지 확인한다.
|
||||||
|
6. 브라우저에서 `http://localhost:8080`을 열어 데이터가 보이는지 확인한다.
|
||||||
|
|
||||||
|
이 순서대로 진행하면 현재 저장소 기준 Dockerized ITAM 시연 환경을 재현할 수 있다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 17. 2026-06-16 최신 정정
|
||||||
|
|
||||||
|
이 문서의 상단 본문은 한동안 사용했던 `내부 db + db-bootstrap` 구조를 기준으로 작성됐다. 하지만 오늘 기준 현재 저장소의 실제 `docker-compose.yaml`은 다시 `무상태 앱 컨테이너 + 외부 DB` 구조로 되돌아가 있다.
|
||||||
|
|
||||||
|
따라서 현재 시점의 정답 아키텍처는 아래다.
|
||||||
|
|
||||||
|
1. `backend` 컨테이너
|
||||||
|
2. `frontend` 컨테이너
|
||||||
|
3. 외부 MySQL DB
|
||||||
|
|
||||||
|
현재는 더 이상 아래 항목이 없다.
|
||||||
|
|
||||||
|
1. `db` 서비스 없음
|
||||||
|
2. `db-bootstrap` 서비스 없음
|
||||||
|
3. `itam_mysql_data` 볼륨 없음
|
||||||
|
|
||||||
|
### 17.1 현재 실제 `docker-compose.yaml` 기준 backend 동작
|
||||||
|
|
||||||
|
현재 backend는 `.env`의 외부 DB 접속 정보를 그대로 사용한다.
|
||||||
|
|
||||||
|
즉, 아래 환경변수 매핑이 현재 기준이다.
|
||||||
|
|
||||||
|
1. `DB_HOST: ${DB_HOST}`
|
||||||
|
2. `DB_PORT: ${DB_PORT}`
|
||||||
|
3. `DB_USER: ${DB_USER}`
|
||||||
|
4. `DB_PASS: ${DB_PASS}`
|
||||||
|
5. `DB_NAME: ${DB_NAME}`
|
||||||
|
|
||||||
|
`PORT: 3000`만 Compose에서 고정한다.
|
||||||
|
|
||||||
|
### 17.2 현재 실제 기동 구조
|
||||||
|
|
||||||
|
현재 스택 기동 순서는 단순하다.
|
||||||
|
|
||||||
|
1. `backend` 기동
|
||||||
|
2. `frontend` 기동
|
||||||
|
3. backend는 외부 DB에 직접 접속
|
||||||
|
4. frontend는 `http://backend:3000`으로 프록시
|
||||||
|
|
||||||
|
즉, 현재는 DB 컨테이너 초기화 단계나 bootstrap 단계가 존재하지 않는다.
|
||||||
|
|
||||||
|
### 17.3 현재 기준 첫 실행 체크리스트
|
||||||
|
|
||||||
|
오늘 기준으로는 아래 순서가 맞다.
|
||||||
|
|
||||||
|
1. `.env`에 외부 DB 접속 정보 입력
|
||||||
|
2. `start_docker_wsl.ps1` 또는 `start_docker_wsl.bat` 실행
|
||||||
|
3. `http://localhost:3000/api/assets/master`가 200인지 확인
|
||||||
|
4. `http://localhost:8080/api/assets/master`가 200인지 확인
|
||||||
|
5. 브라우저에서 `http://localhost:8080` 접속 후 데이터 표시 확인
|
||||||
|
|
||||||
|
### 17.4 이 문서에서 현재 유효한 부분과 과거 이력 부분
|
||||||
|
|
||||||
|
현재도 그대로 유효한 내용은 아래다.
|
||||||
|
|
||||||
|
1. WSL2 기반 실행 방식
|
||||||
|
2. `start_docker_wsl.ps1` / `stop_docker_wsl.ps1` 사용 방식
|
||||||
|
3. `server.js`에서 Compose 환경변수가 `.env`보다 우선되도록 `dotenv.config()`를 유지해야 한다는 점
|
||||||
|
4. `vite.config.ts`에서 프록시 타깃을 환경변수화해야 한다는 점
|
||||||
|
|
||||||
|
현재는 과거 이력으로만 읽어야 하는 내용은 아래다.
|
||||||
|
|
||||||
|
1. 내부 `db` 서비스 설명
|
||||||
|
2. `db-bootstrap` 설명
|
||||||
|
3. `itam_mysql_data` 볼륨 설명
|
||||||
|
4. 내부 DB 재초기화 절차
|
||||||
|
5. 내부 테이블 확인 절차
|
||||||
|
|
||||||
|
### 17.5 현재 최종 한 줄 요약
|
||||||
|
|
||||||
|
오늘 날짜 기준 현재 저장소의 실사용 Compose 구조는 `frontend + backend + external DB`이며, 이전의 내부 DB/bootstrap 구조는 역사적으로 한 번 사용했던 임시 해결책으로만 남아 있다.
|
||||||
48
docker-compose.yaml
Normal file
48
docker-compose.yaml
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
services:
|
||||||
|
backend:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.backend
|
||||||
|
container_name: itam-backend
|
||||||
|
working_dir: /app
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
environment:
|
||||||
|
DB_HOST: ${DB_HOST}
|
||||||
|
DB_PORT: ${DB_PORT}
|
||||||
|
DB_USER: ${DB_USER}
|
||||||
|
DB_PASS: ${DB_PASS}
|
||||||
|
DB_NAME: ${DB_NAME}
|
||||||
|
PORT: 3000
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
volumes:
|
||||||
|
- ./:/app
|
||||||
|
- backend_node_modules:/app/node_modules
|
||||||
|
- ./uploads:/app/uploads
|
||||||
|
- ./map_config.json:/app/map_config.json
|
||||||
|
command: npm run server
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.frontend
|
||||||
|
container_name: itam-frontend
|
||||||
|
working_dir: /app
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
environment:
|
||||||
|
CHOKIDAR_USEPOLLING: "true"
|
||||||
|
VITE_DEV_PROXY_TARGET: http://backend:3000
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
volumes:
|
||||||
|
- ./:/app
|
||||||
|
- frontend_node_modules:/app/node_modules
|
||||||
|
command: npm run dev -- --host 0.0.0.0
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
backend_node_modules:
|
||||||
|
frontend_node_modules:
|
||||||
16
docker/mysql/init/README.md
Normal file
16
docker/mysql/init/README.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# MySQL init directory
|
||||||
|
|
||||||
|
This directory is kept as a legacy hook for file-based MySQL initialization.
|
||||||
|
|
||||||
|
Current production path in this repository is not file-based import.
|
||||||
|
The live Docker flow uses the `db-bootstrap` service in `docker-compose.yaml` to stream data from the external source DB into the internal `db` container.
|
||||||
|
|
||||||
|
Use this directory only if you intentionally switch back to `docker-entrypoint-initdb.d` style initialization.
|
||||||
|
|
||||||
|
If you do that, typical naming would be:
|
||||||
|
|
||||||
|
- `01_schema.sql`
|
||||||
|
- `02_seed.sql`
|
||||||
|
- or a single `01_itam_dump.sql`
|
||||||
|
|
||||||
|
Remember that files in this directory are executed automatically by the MySQL container only on the first initialization of the data volume.
|
||||||
330
docker_task_plan.md
Normal file
330
docker_task_plan.md
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
# ITAM 도커라이징 작업 태스크 정리
|
||||||
|
|
||||||
|
## 1. 문서 목적
|
||||||
|
|
||||||
|
이 문서는 ITAM 자산관리 시스템의 도커라이징 작업을 실제 실행 단위로 쪼개서 정리한 태스크 문서다.
|
||||||
|
|
||||||
|
이 문서의 목표는 아래와 같다.
|
||||||
|
|
||||||
|
1. 내일까지 보여줄 시연 범위를 기준으로 우선순위를 정한다.
|
||||||
|
2. 시연용 작업과 운영형 전환 작업을 분리한다.
|
||||||
|
3. 개발 담당자가 바로 실행할 수 있는 체크리스트를 제공한다.
|
||||||
|
|
||||||
|
관련 배경과 구조 분석은 [doc_readme.md](c:/Users/user/Desktop/안건%20파일/itam/doc_readme.md) 문서를 기준으로 한다.
|
||||||
|
|
||||||
|
현재 구현/검증 상태:
|
||||||
|
|
||||||
|
- `Dockerfile.frontend` 생성 완료
|
||||||
|
- `Dockerfile.backend` 생성 완료
|
||||||
|
- `docker-compose.yaml` 생성 완료
|
||||||
|
- `.dockerignore` 생성 완료
|
||||||
|
- WSL2 Ubuntu에서 `docker compose up --build -d` 검증 완료
|
||||||
|
- frontend 8080 응답 확인 완료
|
||||||
|
- backend `/api/assets/master` 응답 확인 완료
|
||||||
|
- 현재 DB는 external MySQL 기준이며, DB 컨테이너 추가 작업은 다음 단계로 남아 있음
|
||||||
|
|
||||||
|
## 2. 이번 작업의 최우선 목표
|
||||||
|
|
||||||
|
이번 도커라이징의 1차 목표는 "운영 배포 완료"가 아니라 아래 상태를 재현하는 것이다.
|
||||||
|
|
||||||
|
1. frontend 컨테이너가 정상 기동한다.
|
||||||
|
2. backend 컨테이너가 정상 기동한다.
|
||||||
|
3. backend가 기존 외부 MySQL 또는 MySQL 컨테이너에 정상 연결된다.
|
||||||
|
4. 브라우저에서 화면이 열린다.
|
||||||
|
5. 핵심 API 호출이 정상 동작한다.
|
||||||
|
6. 업로드 저장 경로가 유지된다.
|
||||||
|
7. 필요 시 DB까지 함께 포함된 재현 가능한 스택을 제공한다.
|
||||||
|
|
||||||
|
## 3. 작업 범위 구분
|
||||||
|
|
||||||
|
### 3.1 이번 시연 범위에 포함
|
||||||
|
|
||||||
|
- Dockerfile.frontend 초안 작성
|
||||||
|
- Dockerfile.backend 초안 작성
|
||||||
|
- docker-compose.yaml 작성
|
||||||
|
- `.dockerignore` 작성
|
||||||
|
- MySQL 컨테이너 추가 설계
|
||||||
|
- 초기 SQL dump 또는 init SQL 적재 방식 정의
|
||||||
|
- `uploads` 볼륨 처리
|
||||||
|
- `map_config.json` 영속성 처리 방식 반영
|
||||||
|
- 컨테이너 기동 및 접속 확인
|
||||||
|
- 핵심 API 및 화면 확인
|
||||||
|
|
||||||
|
### 3.2 이번 시연 범위에서 제외
|
||||||
|
|
||||||
|
- DB 전체 마이그레이션 자동화
|
||||||
|
- nginx 기반 운영 배포 구조
|
||||||
|
- 단일 이미지 운영 구조 전환
|
||||||
|
- CI/CD 연계
|
||||||
|
|
||||||
|
## 4. 선행 확인 태스크
|
||||||
|
|
||||||
|
아래 태스크는 실제 Docker 파일 작성 전에 먼저 확인해야 한다.
|
||||||
|
|
||||||
|
### Task 1. 외부 MySQL 접근 가능 여부 확인
|
||||||
|
|
||||||
|
- 목적: 컨테이너에서 외부 DB 접속이 가능한지 확인
|
||||||
|
- 확인 항목:
|
||||||
|
- DB_HOST 접근 가능 여부
|
||||||
|
- DB_PORT 3306 접속 가능 여부
|
||||||
|
- 계정 권한 정상 여부
|
||||||
|
- 완료 기준:
|
||||||
|
- backend 컨테이너 기준 DB 연결 에러가 발생하지 않음
|
||||||
|
|
||||||
|
### Task 2. 기준 스키마 상태 확인
|
||||||
|
|
||||||
|
- 목적: 현재 앱이 요구하는 테이블 구조가 실제 DB와 맞는지 확인
|
||||||
|
- 확인 항목:
|
||||||
|
- `asset_core`
|
||||||
|
- `asset_spec`
|
||||||
|
- `asset_location`
|
||||||
|
- `asset_remote`
|
||||||
|
- `asset_history`
|
||||||
|
- `hardware_components_master`
|
||||||
|
- `job_spec_standards`
|
||||||
|
- 완료 기준:
|
||||||
|
- `/api/assets/master` 호출 시 쿼리 에러가 발생하지 않음
|
||||||
|
|
||||||
|
### Task 3. 파일 영속성 대상 확인
|
||||||
|
|
||||||
|
- 목적: 컨테이너 재시작 이후에도 유지되어야 할 파일/폴더 식별
|
||||||
|
- 대상:
|
||||||
|
- `uploads`
|
||||||
|
- `map_config.json`
|
||||||
|
- 완료 기준:
|
||||||
|
- 볼륨 설계 대상이 명확하게 문서화됨
|
||||||
|
|
||||||
|
### Task 4. DB 기준 데이터 소스 확정
|
||||||
|
|
||||||
|
- 목적: MySQL 컨테이너 최초 기동 시 어떤 데이터로 초기화할지 결정
|
||||||
|
- 선택지:
|
||||||
|
- 기존 사내 DB에서 추출한 SQL dump 사용
|
||||||
|
- 정리된 스키마 SQL + seed SQL 사용
|
||||||
|
- 수동 import 절차 사용
|
||||||
|
- 완료 기준:
|
||||||
|
- `docker/mysql/init` 기준 적재 전략 또는 수동 복원 절차가 확정됨
|
||||||
|
|
||||||
|
## 5. 시연용 도커라이징 태스크
|
||||||
|
|
||||||
|
### Task 5. 프런트 Dockerfile 작성
|
||||||
|
|
||||||
|
- 목적: Vite 개발 서버를 컨테이너에서 구동
|
||||||
|
- 작업 내용:
|
||||||
|
- Node 20 계열 이미지 사용
|
||||||
|
- `package*.json` 복사 후 `npm install`
|
||||||
|
- 8080 포트 노출
|
||||||
|
- `npm run dev -- --host 0.0.0.0` 실행
|
||||||
|
- 산출물:
|
||||||
|
- `Dockerfile.frontend`
|
||||||
|
- 완료 기준:
|
||||||
|
- 컨테이너에서 8080 포트가 정상 listen 상태가 됨
|
||||||
|
|
||||||
|
### Task 6. 백엔드 Dockerfile 작성
|
||||||
|
|
||||||
|
- 목적: Express API 서버를 컨테이너에서 구동
|
||||||
|
- 작업 내용:
|
||||||
|
- Node 20 계열 이미지 사용
|
||||||
|
- `package*.json` 복사 후 `npm install`
|
||||||
|
- 3000 포트 노출
|
||||||
|
- `npm run server` 실행
|
||||||
|
- 산출물:
|
||||||
|
- `Dockerfile.backend`
|
||||||
|
- 완료 기준:
|
||||||
|
- 컨테이너에서 3000 포트가 정상 listen 상태가 됨
|
||||||
|
|
||||||
|
### Task 7. MySQL Docker 구성 추가
|
||||||
|
|
||||||
|
- 목적: DB까지 포함한 재현 가능한 스택 구성
|
||||||
|
- 작업 내용:
|
||||||
|
- `mysql:8.0` 서비스 정의
|
||||||
|
- `MYSQL_DATABASE`, `MYSQL_USER`, `MYSQL_PASSWORD` 설정
|
||||||
|
- utf8mb4 문자셋 옵션 반영
|
||||||
|
- MySQL 데이터 volume 연결
|
||||||
|
- 초기 SQL 적재용 `docker/mysql/init` 디렉터리 설계
|
||||||
|
- 산출물:
|
||||||
|
- `docker-compose.yaml` 내 `db` 서비스 또는 별도 DB compose 확장안
|
||||||
|
- 완료 기준:
|
||||||
|
- MySQL 컨테이너가 정상 기동하고 3306 포트에서 응답 가능
|
||||||
|
|
||||||
|
### Task 8. backend DB 연결 전환
|
||||||
|
|
||||||
|
- 목적: backend가 external MySQL 대신 DB 컨테이너를 바라보도록 변경
|
||||||
|
- 작업 내용:
|
||||||
|
- `DB_HOST`를 `db`로 전환
|
||||||
|
- 필요 시 `.env.docker` 또는 compose 내부 환경변수 사용
|
||||||
|
- backend `depends_on`에 db 추가
|
||||||
|
- 산출물:
|
||||||
|
- DB 컨테이너용 backend 환경 정의
|
||||||
|
- 완료 기준:
|
||||||
|
- backend 로그에서 DB 연결 성공 확인
|
||||||
|
|
||||||
|
### Task 9. docker-compose.yaml 확장
|
||||||
|
|
||||||
|
- 목적: frontend/backend를 함께 기동
|
||||||
|
- 작업 내용:
|
||||||
|
- frontend 서비스 정의
|
||||||
|
- backend 서비스 정의
|
||||||
|
- db 서비스 정의
|
||||||
|
- 포트 매핑 추가
|
||||||
|
- `.env` 또는 docker 전용 환경변수 연결
|
||||||
|
- MySQL 데이터 볼륨 연결
|
||||||
|
- `uploads` 볼륨 연결
|
||||||
|
- `map_config.json` 처리 방식 반영
|
||||||
|
- 산출물:
|
||||||
|
- `docker-compose.yaml`
|
||||||
|
- 완료 기준:
|
||||||
|
- `docker compose up --build` 한 번으로 세 서비스가 모두 올라옴
|
||||||
|
|
||||||
|
### Task 10. `.dockerignore` 작성
|
||||||
|
|
||||||
|
- 목적: 불필요한 빌드 컨텍스트 제외
|
||||||
|
- 제외 권장 항목:
|
||||||
|
- `node_modules`
|
||||||
|
- `dist`
|
||||||
|
- `build`
|
||||||
|
- `.git`
|
||||||
|
- `uploads`
|
||||||
|
- `*.xlsx`
|
||||||
|
- 산출물:
|
||||||
|
- `.dockerignore`
|
||||||
|
- 완료 기준:
|
||||||
|
- 이미지 빌드 컨텍스트가 과도하게 커지지 않음
|
||||||
|
|
||||||
|
## 6. 시연 검증 태스크
|
||||||
|
|
||||||
|
### Task 11. WSL 컨테이너 기동 검증
|
||||||
|
|
||||||
|
- 실행 명령:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
powershell -ExecutionPolicy Bypass -File .\start_docker_wsl.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
- 확인 항목:
|
||||||
|
- frontend 로그 에러 여부
|
||||||
|
- backend 로그 에러 여부
|
||||||
|
- db 로그 에러 여부
|
||||||
|
- backend와 db 연결 성공 여부
|
||||||
|
- 완료 기준:
|
||||||
|
- 세 컨테이너 모두 종료 없이 유지됨
|
||||||
|
|
||||||
|
### Task 12. 웹 접속 검증
|
||||||
|
|
||||||
|
- 확인 항목:
|
||||||
|
- `http://localhost:8080` 접속 가능 여부
|
||||||
|
- 첫 화면 로딩 여부
|
||||||
|
- 콘솔 에러 여부
|
||||||
|
- 완료 기준:
|
||||||
|
- 브라우저에서 초기 화면이 정상 표시됨
|
||||||
|
|
||||||
|
### Task 13. API 검증
|
||||||
|
|
||||||
|
- 확인 항목:
|
||||||
|
- `http://localhost:3000/api/assets/master`
|
||||||
|
- 프런트에서 `/api/assets/master` 호출 정상 여부
|
||||||
|
- 완료 기준:
|
||||||
|
- 200 응답 또는 정상 데이터 응답 확인
|
||||||
|
|
||||||
|
### Task 14. DB 초기 데이터 검증
|
||||||
|
|
||||||
|
- 확인 항목:
|
||||||
|
- MySQL 컨테이너 내부에 목표 DB가 생성되었는지
|
||||||
|
- 기준 테이블이 존재하는지
|
||||||
|
- 샘플 데이터 또는 실데이터가 적재되었는지
|
||||||
|
- 완료 기준:
|
||||||
|
- backend가 기대하는 최소 테이블과 데이터가 실제로 조회됨
|
||||||
|
|
||||||
|
### Task 15. 업로드/파일 저장 검증
|
||||||
|
|
||||||
|
- 확인 항목:
|
||||||
|
- `/api/upload` 호출 정상 여부
|
||||||
|
- 업로드 파일이 `uploads`에 실제 저장되는지
|
||||||
|
- `map_config.json` 수정 내용이 유지되는지
|
||||||
|
- 완료 기준:
|
||||||
|
- 컨테이너 재시작 후에도 저장 데이터가 유지됨
|
||||||
|
|
||||||
|
## 7. 시연 후 후속 태스크
|
||||||
|
|
||||||
|
### Task 16. 운영형 프런트 배포 구조 전환
|
||||||
|
|
||||||
|
- 목표: Vite dev server 대신 정적 빌드 기반 구조로 전환
|
||||||
|
- 후보:
|
||||||
|
- nginx 정적 서빙
|
||||||
|
- Express 정적 서빙
|
||||||
|
|
||||||
|
### Task 17. DB 초기화/마이그레이션 전략 통합
|
||||||
|
|
||||||
|
- 목표: 기준 스키마와 실행 순서를 단일 정책으로 통일
|
||||||
|
- 필요 작업:
|
||||||
|
- 기준 스키마 선정
|
||||||
|
- 초기화 스크립트 확정
|
||||||
|
- 마이그레이션 순서 정의
|
||||||
|
|
||||||
|
### Task 18. `.env.example` 및 배포 환경 분리
|
||||||
|
|
||||||
|
- 목표: 민감정보를 저장소에서 분리하고 배포별 설정 체계화
|
||||||
|
|
||||||
|
### Task 19. 운영 볼륨 및 백업 전략 정리
|
||||||
|
|
||||||
|
- 목표: 업로드 파일과 설정 파일, MySQL 데이터의 장기 보존 정책 정리
|
||||||
|
|
||||||
|
### Task 20. DB 백업/복원 절차 문서화
|
||||||
|
|
||||||
|
- 목표: 컨테이너 DB를 기준으로 dump/restore 절차를 문서화
|
||||||
|
|
||||||
|
## 8. 우선순위 정리
|
||||||
|
|
||||||
|
### P0: 내일까지 반드시 필요한 작업
|
||||||
|
|
||||||
|
1. Task 1. 외부 MySQL 접근 가능 여부 확인
|
||||||
|
2. Task 2. 기준 스키마 상태 확인
|
||||||
|
3. Task 4. DB 기준 데이터 소스 확정
|
||||||
|
4. Task 7. MySQL Docker 구성 추가
|
||||||
|
5. Task 8. backend DB 연결 전환
|
||||||
|
6. Task 9. docker-compose.yaml 확장
|
||||||
|
7. Task 11. WSL 컨테이너 기동 검증
|
||||||
|
8. Task 12. 웹 접속 검증
|
||||||
|
9. Task 13. API 검증
|
||||||
|
10. Task 14. DB 초기 데이터 검증
|
||||||
|
|
||||||
|
### P1: 시연 안정화를 위해 권장되는 작업
|
||||||
|
|
||||||
|
1. Task 3. 파일 영속성 대상 확인
|
||||||
|
2. Task 10. `.dockerignore` 작성
|
||||||
|
3. Task 15. 업로드/파일 저장 검증
|
||||||
|
|
||||||
|
### P2: 시연 이후 진행할 작업
|
||||||
|
|
||||||
|
1. Task 16. 운영형 프런트 배포 구조 전환
|
||||||
|
2. Task 17. DB 초기화/마이그레이션 전략 통합
|
||||||
|
3. Task 18. `.env.example` 및 배포 환경 분리
|
||||||
|
4. Task 19. 운영 볼륨 및 백업 전략 정리
|
||||||
|
5. Task 20. DB 백업/복원 절차 문서화
|
||||||
|
|
||||||
|
## 9. 개발자용 최종 작업 순서 제안
|
||||||
|
|
||||||
|
개발 담당자에게는 아래 순서로 진행하라고 전달하면 된다.
|
||||||
|
|
||||||
|
1. 외부 DB 연결 가능 여부부터 확인
|
||||||
|
2. 현재 DB 스키마가 앱 요구사항과 맞는지 확인
|
||||||
|
3. DB 기준 dump 또는 init SQL 확보
|
||||||
|
4. MySQL 컨테이너 구성 추가
|
||||||
|
5. backend의 DB 연결 대상을 `db`로 전환
|
||||||
|
6. WSL에서 `docker compose config` 확인
|
||||||
|
7. WSL에서 컨테이너 기동 테스트
|
||||||
|
8. 웹 접속 및 API 확인
|
||||||
|
9. 업로드 및 파일 영속성 확인
|
||||||
|
10. 시연 완료 후 운영형 구조로 분리 작업 진행
|
||||||
|
|
||||||
|
## 10. 완료 판단 기준
|
||||||
|
|
||||||
|
이번 도커라이징 1차 작업은 아래 조건을 만족하면 완료로 본다.
|
||||||
|
|
||||||
|
1. `docker compose up --build`로 프런트, 백엔드, DB가 모두 기동한다.
|
||||||
|
2. 브라우저에서 8080 화면이 열린다.
|
||||||
|
3. `/api/assets/master`가 정상 응답한다.
|
||||||
|
4. backend가 DB 컨테이너와 정상 연결된다.
|
||||||
|
5. DB 초기 테이블과 데이터가 기대 상태로 적재된다.
|
||||||
|
6. `uploads`, `map_config.json`, MySQL 데이터가 재시작 후에도 유지된다.
|
||||||
|
|
||||||
|
이 문서는 실제 구현 작업의 체크리스트로 사용한다.
|
||||||
47
server.js
47
server.js
@@ -4,7 +4,22 @@ import cors from 'cors';
|
|||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
|
||||||
dotenv.config({ override: true });
|
dotenv.config();
|
||||||
|
|
||||||
|
const dbConfig = {
|
||||||
|
host: process.env.DB_HOST,
|
||||||
|
user: process.env.DB_USER,
|
||||||
|
password: process.env.DB_PASS,
|
||||||
|
database: process.env.DB_NAME,
|
||||||
|
port: parseInt(process.env.DB_PORT || '3306')
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDbConnectionSummary = () => ({
|
||||||
|
host: dbConfig.host || '(missing)',
|
||||||
|
port: dbConfig.port,
|
||||||
|
user: dbConfig.user || '(missing)',
|
||||||
|
database: dbConfig.database || '(missing)'
|
||||||
|
});
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
app.use(cors());
|
app.use(cors());
|
||||||
@@ -18,11 +33,11 @@ if (!fs.existsSync('uploads')) {
|
|||||||
|
|
||||||
// MySQL Pool Configuration
|
// MySQL Pool Configuration
|
||||||
const pool = mysql.createPool({
|
const pool = mysql.createPool({
|
||||||
host: process.env.DB_HOST,
|
host: dbConfig.host,
|
||||||
user: process.env.DB_USER,
|
user: dbConfig.user,
|
||||||
password: process.env.DB_PASS,
|
password: dbConfig.password,
|
||||||
database: process.env.DB_NAME,
|
database: dbConfig.database,
|
||||||
port: parseInt(process.env.DB_PORT || '3306'),
|
port: dbConfig.port,
|
||||||
waitForConnections: true,
|
waitForConnections: true,
|
||||||
connectionLimit: 10,
|
connectionLimit: 10,
|
||||||
queueLimit: 0
|
queueLimit: 0
|
||||||
@@ -48,7 +63,15 @@ const pool = mysql.createPool({
|
|||||||
`);
|
`);
|
||||||
console.log('✅ job_spec_standards table verification completed.');
|
console.log('✅ job_spec_standards table verification completed.');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('❌ Failed to verify/create job_spec_standards table:', err);
|
console.error('❌ Failed to verify/create job_spec_standards table:', {
|
||||||
|
db: getDbConnectionSummary(),
|
||||||
|
code: err.code,
|
||||||
|
errno: err.errno,
|
||||||
|
syscall: err.syscall,
|
||||||
|
address: err.address,
|
||||||
|
port: err.port,
|
||||||
|
message: err.message
|
||||||
|
});
|
||||||
} finally {
|
} finally {
|
||||||
if (connection) connection.release();
|
if (connection) connection.release();
|
||||||
}
|
}
|
||||||
@@ -56,7 +79,15 @@ const pool = mysql.createPool({
|
|||||||
|
|
||||||
// Error Handler
|
// Error Handler
|
||||||
const handleError = (res, err, label) => {
|
const handleError = (res, err, label) => {
|
||||||
console.error(`❌ [${label}] Error:`, err);
|
console.error(`❌ [${label}] Error:`, {
|
||||||
|
db: getDbConnectionSummary(),
|
||||||
|
code: err.code,
|
||||||
|
errno: err.errno,
|
||||||
|
syscall: err.syscall,
|
||||||
|
address: err.address,
|
||||||
|
port: err.port,
|
||||||
|
message: err.message
|
||||||
|
});
|
||||||
res.status(500).json({ error: err.message });
|
res.status(500).json({ error: err.message });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
10
start_docker_wsl.bat
Normal file
10
start_docker_wsl.bat
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
@echo off
|
||||||
|
chcp 65001 >nul
|
||||||
|
cd /d "%~dp0"
|
||||||
|
powershell -ExecutionPolicy Bypass -File "%~dp0start_docker_wsl.ps1"
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo.
|
||||||
|
echo [ERROR] start_docker_wsl.ps1 failed.
|
||||||
|
pause
|
||||||
|
exit /b %errorlevel%
|
||||||
|
)
|
||||||
107
start_docker_wsl.ps1
Normal file
107
start_docker_wsl.ps1
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||||
|
|
||||||
|
$projectWindowsPath = $PSScriptRoot
|
||||||
|
$wslProjectPath = (wsl wslpath $projectWindowsPath).Trim()
|
||||||
|
$envFilePath = Join-Path $PSScriptRoot '.env'
|
||||||
|
|
||||||
|
function Get-EnvValue {
|
||||||
|
param(
|
||||||
|
[string]$FilePath,
|
||||||
|
[string]$Key
|
||||||
|
)
|
||||||
|
|
||||||
|
if (-not (Test-Path $FilePath)) {
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
$line = Get-Content $FilePath | Where-Object { $_ -match "^$Key=" } | Select-Object -First 1
|
||||||
|
if (-not $line) {
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($line -split '=', 2)[1].Trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-TcpPortFast {
|
||||||
|
param(
|
||||||
|
[string]$HostName,
|
||||||
|
[int]$Port,
|
||||||
|
[int]$TimeoutMs = 3000
|
||||||
|
)
|
||||||
|
|
||||||
|
$client = New-Object System.Net.Sockets.TcpClient
|
||||||
|
try {
|
||||||
|
$asyncResult = $client.BeginConnect($HostName, $Port, $null, $null)
|
||||||
|
if (-not $asyncResult.AsyncWaitHandle.WaitOne($TimeoutMs, $false)) {
|
||||||
|
$client.Close()
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
|
||||||
|
$client.EndConnect($asyncResult)
|
||||||
|
$client.Close()
|
||||||
|
return $true
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
$client.Close()
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "============================================" -ForegroundColor Cyan
|
||||||
|
Write-Host " HM ITAM WSL Docker Start" -ForegroundColor Cyan
|
||||||
|
Write-Host "============================================" -ForegroundColor Cyan
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
Write-Host "[INFO] Checking WSL..."
|
||||||
|
wsl -l -v
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Write-Host "[ERROR] WSL is not available." -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "[INFO] Checking Docker in WSL..."
|
||||||
|
wsl sh -lc "docker --version"
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Write-Host "[ERROR] Docker is not available inside WSL." -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
$dbHost = Get-EnvValue -FilePath $envFilePath -Key 'DB_HOST'
|
||||||
|
$dbPort = Get-EnvValue -FilePath $envFilePath -Key 'DB_PORT'
|
||||||
|
|
||||||
|
if (-not $dbPort) {
|
||||||
|
$dbPort = '3306'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $dbHost) {
|
||||||
|
Write-Host "[WARN] .env is missing DB_HOST. Containers will still start, but backend DB calls will fail until DB settings are fixed." -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($dbHost) {
|
||||||
|
Write-Host "[INFO] Checking external DB reachability..."
|
||||||
|
$dbReachable = Test-TcpPortFast -HostName $dbHost -Port ([int]$dbPort)
|
||||||
|
if (-not $dbReachable) {
|
||||||
|
Write-Host "[WARN] External DB is unreachable: $dbHost`:$dbPort" -ForegroundColor Yellow
|
||||||
|
Write-Host "[HINT] Containers will still start. Check VPN/private network connection, firewall rules, DB host/port in .env, or whether the DB server is running." -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "[INFO] Starting ITAM containers in WSL..."
|
||||||
|
wsl sh -lc "cd '$wslProjectPath' && docker compose up --build -d --remove-orphans"
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Write-Host "[WARN] Build-based startup failed. Retrying with cached images/containers..." -ForegroundColor Yellow
|
||||||
|
wsl sh -lc "cd '$wslProjectPath' && docker compose up -d --remove-orphans"
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Write-Host "[ERROR] Failed to start containers." -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "============================================" -ForegroundColor Green
|
||||||
|
Write-Host " [OK] WSL Docker stack started." -ForegroundColor Green
|
||||||
|
Write-Host " [INFO] Frontend: http://localhost:8080"
|
||||||
|
Write-Host " [INFO] Backend : http://localhost:3000/api/assets/master"
|
||||||
|
Write-Host "============================================" -ForegroundColor Green
|
||||||
|
|
||||||
|
Start-Process "http://localhost:8080"
|
||||||
@@ -1,6 +1,49 @@
|
|||||||
# HM ITAM Server Start Script
|
# HM ITAM Server Start Script
|
||||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||||
|
|
||||||
|
function Get-EnvValue {
|
||||||
|
param(
|
||||||
|
[string]$FilePath,
|
||||||
|
[string]$Key
|
||||||
|
)
|
||||||
|
|
||||||
|
if (-not (Test-Path $FilePath)) {
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
$line = Get-Content $FilePath | Where-Object { $_ -match "^$Key=" } | Select-Object -First 1
|
||||||
|
if (-not $line) {
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($line -split '=', 2)[1].Trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-TcpPortFast {
|
||||||
|
param(
|
||||||
|
[string]$HostName,
|
||||||
|
[int]$Port,
|
||||||
|
[int]$TimeoutMs = 3000
|
||||||
|
)
|
||||||
|
|
||||||
|
$client = New-Object System.Net.Sockets.TcpClient
|
||||||
|
try {
|
||||||
|
$asyncResult = $client.BeginConnect($HostName, $Port, $null, $null)
|
||||||
|
if (-not $asyncResult.AsyncWaitHandle.WaitOne($TimeoutMs, $false)) {
|
||||||
|
$client.Close()
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
|
||||||
|
$client.EndConnect($asyncResult)
|
||||||
|
$client.Close()
|
||||||
|
return $true
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
$client.Close()
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Write-Host "============================================" -ForegroundColor Cyan
|
Write-Host "============================================" -ForegroundColor Cyan
|
||||||
Write-Host " HM ITAM System Start" -ForegroundColor Cyan
|
Write-Host " HM ITAM System Start" -ForegroundColor Cyan
|
||||||
Write-Host "============================================" -ForegroundColor Cyan
|
Write-Host "============================================" -ForegroundColor Cyan
|
||||||
@@ -21,6 +64,13 @@ if (-not (Test-Path "node_modules")) {
|
|||||||
Write-Host "[INFO] Checking ports..."
|
Write-Host "[INFO] Checking ports..."
|
||||||
$backendPort = 3000
|
$backendPort = 3000
|
||||||
$frontendPort = 8080
|
$frontendPort = 8080
|
||||||
|
$envFilePath = Join-Path $PSScriptRoot '.env'
|
||||||
|
$dbHost = Get-EnvValue -FilePath $envFilePath -Key 'DB_HOST'
|
||||||
|
$dbPort = Get-EnvValue -FilePath $envFilePath -Key 'DB_PORT'
|
||||||
|
|
||||||
|
if (-not $dbPort) {
|
||||||
|
$dbPort = '3306'
|
||||||
|
}
|
||||||
|
|
||||||
if (Get-NetTCPConnection -LocalPort $backendPort -ErrorAction SilentlyContinue) {
|
if (Get-NetTCPConnection -LocalPort $backendPort -ErrorAction SilentlyContinue) {
|
||||||
Write-Host "[WARNING] Port $backendPort [Backend] is already in use." -ForegroundColor Yellow
|
Write-Host "[WARNING] Port $backendPort [Backend] is already in use." -ForegroundColor Yellow
|
||||||
@@ -30,6 +80,21 @@ if (Get-NetTCPConnection -LocalPort $frontendPort -ErrorAction SilentlyContinue)
|
|||||||
Write-Host "[WARNING] Port $frontendPort [Frontend] is already in use." -ForegroundColor Yellow
|
Write-Host "[WARNING] Port $frontendPort [Frontend] is already in use." -ForegroundColor Yellow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (-not $dbHost) {
|
||||||
|
Write-Host "[WARNING] .env is missing DB_HOST. Backend and frontend will still start, but DB calls will fail until DB settings are fixed." -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host "[INFO] Checking external DB reachability..."
|
||||||
|
$dbReachable = Test-TcpPortFast -HostName $dbHost -Port ([int]$dbPort)
|
||||||
|
if ($dbReachable) {
|
||||||
|
Write-Host "[INFO] External DB reachable: $dbHost`:$dbPort"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host "[WARNING] External DB is unreachable: $dbHost`:$dbPort" -ForegroundColor Yellow
|
||||||
|
Write-Host "[WARNING] Backend and frontend will still start, but DB-backed screens and APIs may fail." -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "[INFO] Starting Backend [Port: 3000]..."
|
Write-Host "[INFO] Starting Backend [Port: 3000]..."
|
||||||
Start-Process cmd -ArgumentList "/k npm run server"
|
Start-Process cmd -ArgumentList "/k npm run server"
|
||||||
|
|||||||
4
stop_docker_wsl.bat
Normal file
4
stop_docker_wsl.bat
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
@echo off
|
||||||
|
chcp 65001 >nul
|
||||||
|
cd /d "%~dp0"
|
||||||
|
powershell -ExecutionPolicy Bypass -File "%~dp0stop_docker_wsl.ps1"
|
||||||
13
stop_docker_wsl.ps1
Normal file
13
stop_docker_wsl.ps1
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||||
|
|
||||||
|
$projectWindowsPath = $PSScriptRoot
|
||||||
|
$wslProjectPath = (wsl wslpath $projectWindowsPath).Trim()
|
||||||
|
|
||||||
|
Write-Host "[INFO] Stopping ITAM WSL Docker stack..."
|
||||||
|
wsl sh -lc "cd '$wslProjectPath' && docker compose down --remove-orphans"
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Write-Host "[ERROR] Failed to stop containers." -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "[OK] WSL Docker stack stopped." -ForegroundColor Green
|
||||||
@@ -1,16 +1,18 @@
|
|||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
|
const proxyTarget = process.env.VITE_DEV_PROXY_TARGET || 'http://localhost:3000';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
server: {
|
server: {
|
||||||
port: 8080,
|
port: 8080,
|
||||||
host: true, // Listen on all local IPs
|
host: true, // Listen on all local IPs
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': {
|
'/api': {
|
||||||
target: 'http://localhost:3000',
|
target: proxyTarget,
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
},
|
},
|
||||||
'/uploads': {
|
'/uploads': {
|
||||||
target: 'http://localhost:3000',
|
target: proxyTarget,
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user