941 lines
27 KiB
Markdown
941 lines
27 KiB
Markdown
# 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. 방화벽 또는 네트워크 이슈가 없는지
|
|
|
|
---
|
|
|
|
## 16. 운영 수동 배포 플로우
|
|
|
|
이 섹션은 현재 ITAM 저장소 기준으로 운영 서버에 반영할 때의 전체 흐름을 설명한다.
|
|
|
|
중요한 전제는 아래와 같다.
|
|
|
|
1. 로컬 수정본을 서버에 직접 복사하지 않는다.
|
|
2. 반드시 Gitea에 올라간 커밋을 기준으로 배포한다.
|
|
3. 운영 반영은 자동 푸시 배포가 아니라 Gitea workflow 수동 실행으로 진행한다.
|
|
4. 현재 기준 운영 배포 workflow는 `.gitea/workflows/itam_production_deploy.yml`이다.
|
|
|
|
---
|
|
|
|
## 16.1 전체 운영/배포 분기 흐름
|
|
|
|
운영 반영은 크게 세 상황으로 나뉜다.
|
|
|
|
1. 최초 운영 서버 구축 후 첫 배포
|
|
2. 코드 수정 후 일반 재배포
|
|
3. 검증 실패 또는 배포 실패 후 수정 재배포
|
|
|
|
아래 분기 구조로 이해하면 된다.
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
START["배포 필요 발생"] --> CASE{"어떤 상황인가?"}
|
|
|
|
CASE -->|초기 구축| INIT["초기 운영 배포 준비"]
|
|
CASE -->|수정 반영| CHANGE["수정 후 재배포 준비"]
|
|
CASE -->|실패 후 재시도| RETRY["실패 원인 분석 후 재배포 준비"]
|
|
|
|
INIT --> INIT1["운영 서버 Docker / compose 확인"]
|
|
INIT1 --> INIT2["Gitea Variables / Secrets 등록"]
|
|
INIT2 --> INIT3["map_config.json / uploads 초기 데이터 준비"]
|
|
INIT3 --> MANUAL["Gitea에서 수동 배포 workflow 실행"]
|
|
|
|
CHANGE --> CHANGE1["로컬 수정 및 테스트"]
|
|
CHANGE1 --> CHANGE2["Gitea 커밋 / push"]
|
|
CHANGE2 --> CHANGE3["Code Check / Docker Build Check 통과"]
|
|
CHANGE3 --> MANUAL
|
|
|
|
RETRY --> RETRY1{"어디서 실패했는가?"}
|
|
RETRY1 -->|코드 체크 실패| FIX1["코드 또는 설정 수정"]
|
|
RETRY1 -->|배포 단계 실패| FIX2["서버 / 변수 / 권한 / 네트워크 수정"]
|
|
RETRY1 -->|Smoke Check 실패| FIX3["앱 기동 상태 / 프록시 / DB 상태 수정"]
|
|
FIX1 --> CHANGE2
|
|
FIX2 --> MANUAL
|
|
FIX3 --> MANUAL
|
|
|
|
MANUAL --> DEPLOY["운영 서버 반영 수행"]
|
|
DEPLOY --> RESULT{"최종 검증 통과?"}
|
|
RESULT -->|예| DONE["운영 반영 완료"]
|
|
RESULT -->|아니오| RETRY
|
|
linkStyle default stroke:#d32f2f,stroke-width:2px;
|
|
```
|
|
|
|
핵심은 아래와 같다.
|
|
|
|
1. 초기 구축은 서버와 운영 데이터 준비가 먼저다.
|
|
2. 수정 반영은 반드시 커밋과 push가 먼저다.
|
|
3. 실패 후 재배포는 실패 지점에 따라 수정 위치가 달라진다.
|
|
|
|
---
|
|
|
|
## 16.2 최초 운영 배포 플로우
|
|
|
|
최초 배포에서는 코드보다 운영 환경 준비가 더 중요하다.
|
|
|
|
순서는 아래와 같다.
|
|
|
|
1. 운영 서버에 Docker Engine과 `docker compose`를 설치한다.
|
|
2. 운영 서버에서 Gitea 저장소에 접근 가능한 SSH 키를 준비한다.
|
|
3. Gitea repository Variables / Secrets를 등록한다.
|
|
4. `PROD_DEPLOY_PATH` 경로를 정한다.
|
|
5. `map_config.json`, `uploads/` 초기 데이터를 준비한다.
|
|
6. Gitea에서 `itam_production_deploy.yml`을 수동 실행한다.
|
|
7. 배포 후 `ps`, `/health`, `/`, `/ready`를 확인한다.
|
|
|
|
즉 최초 배포는 아래 조건이 먼저 충족되어야 한다.
|
|
|
|
```text
|
|
서버 준비 완료
|
|
-> Gitea 변수 / 시크릿 등록 완료
|
|
-> 초기 데이터 준비 완료
|
|
-> 수동 배포 실행
|
|
```
|
|
|
|
---
|
|
|
|
## 16.3 수정 후 일반 재배포 플로우
|
|
|
|
일반적인 수정 반영은 아래 흐름이다.
|
|
|
|
1. 개발자가 로컬에서 코드 또는 설정을 수정한다.
|
|
2. 로컬에서 필요한 테스트를 수행한다.
|
|
3. 변경사항을 Gitea에 커밋 후 push 한다.
|
|
4. `itam_code_check.yml`이 빌드와 compose 문법을 검사한다.
|
|
5. `itam_docker_build_check.yml`이 운영용 이미지 빌드 가능 여부를 검사한다.
|
|
6. 두 검증이 통과하면 운영자가 Gitea에서 `itam_production_deploy.yml`을 수동 실행한다.
|
|
7. 운영 서버가 최신 커밋으로 동기화되고 컨테이너가 다시 올라온다.
|
|
8. smoke check 통과 여부를 확인한다.
|
|
|
|
아래 다이어그램은 이 일반 재배포 흐름을 보여준다.
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
DEV["로컬 수정"] --> TEST["로컬 확인"]
|
|
TEST --> PUSH["커밋 / push"]
|
|
PUSH --> CODE["ITAM Code Check"]
|
|
CODE --> BUILD["ITAM Docker Build Check"]
|
|
BUILD --> GATE{"검증 통과?"}
|
|
GATE -->|예| RUN["Gitea에서 수동 배포 실행"]
|
|
GATE -->|아니오| FIX["로컬 수정 후 재커밋"]
|
|
FIX --> PUSH
|
|
RUN --> PROD["운영 서버 배포"]
|
|
PROD --> SMOKE{"Smoke Check 통과?"}
|
|
SMOKE -->|예| OK["배포 완료"]
|
|
SMOKE -->|아니오| FIXDEPLOY["원인 수정 후 재배포"]
|
|
FIXDEPLOY --> RUN
|
|
linkStyle default stroke:#d32f2f,stroke-width:2px;
|
|
```
|
|
|
|
---
|
|
|
|
## 16.4 수동 배포 workflow 내부 실행 순서
|
|
|
|
Gitea에서 `itam_production_deploy.yml`을 수동 실행하면 내부적으로는 아래 순서로 진행된다.
|
|
|
|
1. SSH agent를 설정한다.
|
|
2. 필수 Variables / Secrets가 모두 있는지 확인한다.
|
|
3. 운영용 `.env.deploy` 파일을 생성한다.
|
|
4. 운영 서버에 접속한다.
|
|
5. `PROD_DEPLOY_PATH`를 생성한다.
|
|
6. 저장소를 clone 또는 fetch 한다.
|
|
7. 선택한 브랜치의 최신 커밋으로 checkout, reset, clean 한다.
|
|
8. `uploads`, `logs/nginx` 디렉토리를 준비한다.
|
|
9. `.env.deploy`를 서버의 `.env`로 복사한다.
|
|
10. `docker compose -f docker-compose.prod.yaml config`를 수행한다.
|
|
11. `docker compose -f docker-compose.prod.yaml up -d --build`를 수행한다.
|
|
12. `docker compose ps`를 확인한다.
|
|
13. `/health`, `/`, backend `/ready` smoke check를 수행한다.
|
|
|
|
아래 다이어그램은 workflow 내부 실행 순서다.
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
A["수동 배포 시작"] --> B["SSH agent 설정"]
|
|
B --> C["Variables / Secrets 검증"]
|
|
C --> D{"필수 값 누락 여부"}
|
|
D -->|예| E["즉시 실패 후 설정 보완"]
|
|
D -->|아니오| F[".env.deploy 생성"]
|
|
F --> G["운영 서버 SSH 접속"]
|
|
G --> H["배포 경로 생성"]
|
|
H --> I["git clone 또는 fetch"]
|
|
I --> J["지정 브랜치 checkout / reset / clean"]
|
|
J --> K["uploads / logs/nginx 준비"]
|
|
K --> L[".env 업로드 및 권한 설정"]
|
|
L --> M["compose config 검증"]
|
|
M --> N{"compose config 성공?"}
|
|
N -->|아니오| O["설정 수정 후 재실행"]
|
|
N -->|예| P["compose up -d --build"]
|
|
P --> Q["docker compose ps 확인"]
|
|
Q --> R["/health, /, /ready smoke check"]
|
|
R --> S{"smoke check 성공?"}
|
|
S -->|예| T["운영 배포 완료"]
|
|
S -->|아니오| U["원인 분석 후 재배포"]
|
|
linkStyle default stroke:#d32f2f,stroke-width:2px;
|
|
```
|
|
|
|
---
|
|
|
|
## 16.5 실패 후 검증 및 재배포 플로우
|
|
|
|
실패가 났다고 해서 항상 같은 방식으로 다시 배포하면 안 된다.
|
|
|
|
실패 지점별 판단은 아래처럼 나눈다.
|
|
|
|
1. Code Check 실패: TypeScript, build, compose 문법 문제를 먼저 수정한다.
|
|
2. Docker Build Check 실패: Dockerfile, 정적 자산 복사, 운영 빌드 컨텍스트 문제를 수정한다.
|
|
3. Deploy 단계 실패: SSH, Gitea 변수, 서버 권한, 경로, git 접근, Docker 권한을 수정한다.
|
|
4. Smoke Check 실패: Nginx 프록시, backend readiness, 외부 DB 연결, 앱 런타임 오류를 수정한다.
|
|
|
|
즉 재배포 전 판단 기준은 아래와 같다.
|
|
|
|
```text
|
|
CI 실패 -> 로컬 코드 / 설정 수정 후 재커밋
|
|
배포 실패 -> 서버 환경 또는 배포 설정 수정 후 수동 재실행
|
|
Smoke Check 실패 -> 앱 / 프록시 / DB 상태 수정 후 수동 재실행
|
|
```
|
|
|
|
운영 관점에서는 아래 순서를 지키는 것이 안전하다.
|
|
|
|
1. 실패 지점 확인
|
|
2. 원인 수정
|
|
3. 같은 실패가 다시 나는지 좁은 범위로 재검증
|
|
4. 그 다음에만 수동 배포 재실행
|
|
|
|
---
|
|
|
|
## 16.6 문서 기준 요약
|
|
|
|
현재 ITAM 운영 배포는 아래 원칙으로 이해하면 된다.
|
|
|
|
1. 수정은 로컬에서 한다.
|
|
2. 배포 기준점은 Gitea에 올라간 커밋이다.
|
|
3. 운영 반영은 Gitea 수동 workflow 실행으로 한다.
|
|
4. 초기 배포, 일반 재배포, 실패 후 재배포는 분기 기준이 다르다.
|
|
5. 최종 성공 여부는 컨테이너 상태가 아니라 smoke check까지 통과했는지로 판단한다.
|
|
|
|
---
|
|
|
|
## 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 안에서 화면 데이터가 다시 안 보일 수 있다.
|
|
|
|
---
|
|
|
|
## 17. 현재 기준 재현 절차 요약
|
|
|
|
가장 짧게 정리하면 아래 순서다.
|
|
|
|
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`을 열어 실제 데이터 표시를 확인한다.
|
|
|
|
---
|
|
|
|
## 18. 현재 최종 결론
|
|
|
|
현재 저장소의 도커라이징 구조는 실무 표준에 맞는 `무상태 앱 컨테이너 + 외부 DB` 구조다.
|
|
|
|
현재 핵심은 아래 세 가지다.
|
|
|
|
1. `backend`는 외부 MySQL에 직접 연결한다.
|
|
2. `frontend`는 `backend:3000`으로 API 프록시한다.
|
|
3. WSL 경로 변환 스크립트를 통해 Windows 한글 경로에서도 안정적으로 실행한다.
|
|
|
|
즉, 이 문서대로 진행하면 Gitea 소스만 받은 상태에서 지금과 같은 Docker 실행 구조를 재현할 수 있다.
|