18 KiB
ITAM 도커라이징 실전 가이드
1. 문서 목적
이 문서는 Gitea에 올라가 있는 현재 저장소를 기준으로, 개발 PC에 WSL2와 Ubuntu만 설치되어 있는 상태에서 지금의 Docker 실행 구조를 재현하는 방법을 처음부터 끝까지 설명하는 실전 가이드다.
이 문서는 아래 상황을 가정한다.
- 소스 코드는 아직 로컬에 없거나, Gitea에서 막 받아올 예정이다.
- Windows에는 WSL2와 Ubuntu는 설치되어 있다.
- 그 외 Docker 관련 세팅은 아직 안 되어 있을 수 있다.
- 최종 목표는 현재 저장소 기준
frontend + backend + external DB구조를 Docker로 재현하는 것이다.
이 문서의 목적은 아래 네 가지다.
- 현재 시스템 구조와 Docker 구조를 먼저 이해하게 한다.
- 기존 파일 중 무엇이 새로 추가되었고 무엇이 수정되었는지 정리한다.
- 각 단계별로 정확히 어디에서 명령을 실행해야 하는지 명시한다.
- Gitea 소스만 받은 상태에서 지금과 같은 Docker 실행 상태까지 도달하게 한다.
2. 현재 시스템 구조 개요
2.1 애플리케이션 원래 구조
현재 저장소의 본래 실행 구조는 다음과 같다.
- 프런트엔드: Vite 기반 TypeScript 앱
- 백엔드: Express 기반 Node.js API 서버
- 데이터베이스: 외부 MySQL 서버
즉, 원래부터 MySQL이 Docker 안에 들어 있던 구조가 아니다.
프런트와 백엔드는 각각 별도 프로세스로 실행되며, 프런트는 /api 상대 경로로 백엔드 API를 호출한다.
2.2 현재 Docker 구조
현재 최종 Docker 구조는 아래와 같다.
frontend컨테이너backend컨테이너- 외부 MySQL DB
즉, 지금은 내부 db 컨테이너가 없고, 내부 db-bootstrap 컨테이너도 없다.
현재 구조를 문장으로 풀면 다음과 같다.
- 브라우저는
http://localhost:8080으로frontend컨테이너에 접속한다. frontend는/api요청을backend:3000으로 프록시한다.backend는.env에 적힌 외부 DB 정보로 외부 MySQL에 직접 접속한다.- 조회 결과 JSON을 프런트가 받아 화면에 렌더링한다.
간단한 흐름은 아래와 같다.
Browser
-> frontend container :8080
-> Vite proxy (/api)
-> backend container :3000
-> external MySQL (.env)
2.3 왜 이 구조가 맞는가
현재 구조가 적절한 이유는 다음과 같다.
- 원래 시스템도 외부 MySQL을 쓰는 구조였다.
- 지금 목표는 운영형 단일 배포가 아니라 현재 개발형 구조를 Docker로 재현하는 것이다.
- 프런트는 Vite dev server 기반이라 운영형 nginx 정적 배포 구조로 억지로 바꾸는 것보다, 현 구조를 유지하는 편이 안전하다.
- 실무 표준 관점에서도 앱 컨테이너는 무상태로 유지하고, DB는 외부 인프라를 사용하는 구성이 더 일반적이다.
3. 이번 도커라이징에서 추가되거나 수정된 파일 정리
아래 파일들은 이번 Docker 재현 구조를 위해 새로 추가되었거나 수정된 핵심 파일이다.
3.1 새로 추가된 파일
Dockerfile.frontendDockerfile.backend.dockerignoredocker-compose.yamlstart_docker_wsl.ps1stop_docker_wsl.ps1start_docker_wsl.batstop_docker_wsl.batdocker/mysql/init/README.mddocker_task_plan.mddoc_readme2.md
3.2 기존 파일 중 수정된 핵심 파일
server.jsvite.config.tsdoc_readme.md
3.3 각 파일의 역할
Dockerfile.frontend
역할:
- 프런트 Vite 개발 서버 이미지를 만든다.
- 컨테이너 내부에서
npm run dev -- --host 0.0.0.0를 실행한다.
Dockerfile.backend
역할:
- 백엔드 Express 서버 이미지를 만든다.
- 컨테이너 내부에서
npm run server를 실행한다.
.dockerignore
역할:
node_modules,build,.git,.env,uploads같은 불필요한 파일을 Docker build context에서 제외한다.
docker-compose.yaml
역할:
frontend,backend두 컨테이너를 동시에 띄운다.backend는.env의 외부 DB를 사용한다.frontend는backend:3000으로 프록시한다.
start_docker_wsl.ps1
역할:
- Windows 경로를 WSL 경로로 안전하게 바꾼다.
- WSL 내부 Docker를 사용해
docker compose up --build -d를 실행한다. - 한글 경로와 공백 경로에서도 안정적으로 실행되게 한다.
stop_docker_wsl.ps1
역할:
- 같은 방식으로 WSL 내부에서
docker compose down을 실행한다.
start_docker_wsl.bat, stop_docker_wsl.bat
역할:
- PowerShell 스크립트를 쉽게 실행하는 래퍼 역할을 한다.
server.js
중요 수정 사항:
dotenv.config({ override: true })가 아니라dotenv.config()를 사용한다.
이유:
- Compose나 실행 환경이 주는 환경변수를
.env가 덮어써 버리면 안 된다. - 외부 DB 정보와 포트 설정 등 실행 환경 우선 구조를 유지해야 한다.
vite.config.ts
중요 수정 사항:
- 프록시 타깃을 고정
localhost:3000이 아니라 환경변수 기반으로 받도록 바꿨다.
현재 구조:
const proxyTarget = process.env.VITE_DEV_PROXY_TARGET || 'http://localhost:3000';
이유:
- 로컬에서 직접 프런트를 띄울 때는
localhost:3000이 맞다. - Docker 안에서는
frontend컨테이너에서 보는localhost가 백엔드가 아니므로backend:3000을 써야 한다.
4. 현재 docker-compose.yaml 기준 실제 동작 구조
현재 docker-compose.yaml은 아래 구조다.
backend
Dockerfile.backend로 이미지를 빌드한다..env를 읽는다.- DB 관련 변수는
${DB_HOST},${DB_PORT},${DB_USER},${DB_PASS},${DB_NAME}를 그대로 사용한다. - 포트
3000:3000으로 노출한다. uploads,map_config.json을 마운트한다.
frontend
Dockerfile.frontend로 이미지를 빌드한다.VITE_DEV_PROXY_TARGET: http://backend:3000환경변수를 사용한다.- 포트
8080:8080으로 노출한다. - 브라우저의
/api요청을backend로 프록시한다.
즉, 현재 Compose는 DB를 띄우지 않고 앱 두 개만 띄운다.
5. 사전 준비 사항
이 섹션은 Gitea에서 코드를 받기 전 또는 받은 직후에 확인해야 한다.
5.1 가정하는 기본 상태
이미 설치되어 있다고 가정하는 것:
- Windows
- WSL2
- Ubuntu 배포판
아직 없을 수 있는 것:
- Docker Desktop 또는 WSL 내부 Docker 사용 환경
- Git 클라이언트
- 프로젝트
.env
5.2 권장 Docker 실행 방식
현재 저장소 구조상 가장 권장하는 방식은 다음이다.
- Windows에 Docker Desktop 설치
- Docker Desktop에서 WSL2 통합 활성화
- Ubuntu WSL 내부에서
docker명령을 사용할 수 있게 한다.
이유:
- 현재
start_docker_wsl.ps1가 WSL 내부의docker를 호출하는 구조다. - 실제 검증도 WSL 내부 Docker 기준으로 이루어졌다.
5.3 외부 DB 정보 준비
현재 구조는 외부 MySQL을 사용하므로 .env 파일이 반드시 필요하다.
최소한 아래 값이 필요하다.
DB_HOST=<외부 MySQL 호스트>
DB_PORT=3306
DB_USER=<외부 MySQL 계정>
DB_PASS=<외부 MySQL 비밀번호>
DB_NAME=itam
필요 시 추가 환경변수는 현재 백엔드 코드 기준으로 함께 넣을 수 있다.
6. Gitea에서 소스 받기
6.1 작업 실행 위치
이 단계는 Windows PowerShell 또는 Windows 터미널의 PowerShell에서 수행한다.
실행 위치 이유:
- 이후
start_docker_wsl.ps1도 Windows PowerShell에서 실행하는 것이 가장 자연스럽다. - 로컬 작업 폴더를 Windows 경로 기준으로 준비할 수 있다.
6.2 소스 클론
예시:
git clone <Gitea 저장소 URL>
cd <클론된 저장소 경로>
현재 프로젝트처럼 한글 경로를 사용할 수도 있지만, 가능하면 너무 복잡한 경로는 피하는 것이 좋다.
현재 실제 프로젝트 경로 예시는 아래였다.
c:\Users\user\Desktop\안건 파일\itam
이 경로도 현재 스크립트로는 동작 가능하다.
7. Docker 환경 준비
7.1 작업 실행 위치
이 단계는 Windows PowerShell과 WSL Ubuntu 터미널을 둘 다 사용한다.
- 설치 확인은 Windows PowerShell에서 시작
- 실제 Docker 동작 확인은 WSL Ubuntu에서 수행
7.2 Docker Desktop 설치 여부 확인
실행 위치: Windows PowerShell
docker version
만약 여기서 바로 안 잡혀도 현재 프로젝트는 WSL 내부 Docker를 쓰므로, 다음 단계로 넘어가 WSL 내부 확인을 한다.
7.3 WSL 내부 Docker 확인
실행 위치: Windows PowerShell
wsl -l -v
wsl sh -lc "docker --version"
정상 기대 결과:
- Ubuntu가 Running 상태
docker --version이 정상 출력
만약 docker --version이 실패하면, Docker Desktop 설치 및 WSL 통합을 먼저 완료해야 한다.
8. .env 파일 준비
8.1 작업 실행 위치
이 단계는 Windows PowerShell, VS Code, 또는 아무 텍스트 편집기**에서 수행한다.
즉, 프로젝트 루트에 .env 파일을 만드는 작업이다.
8.2 .env 작성
프로젝트 루트에 .env를 만든다.
예시:
DB_HOST=your-external-db-host
DB_PORT=3306
DB_USER=your-db-user
DB_PASS=your-db-password
DB_NAME=itam
주의:
- 현재 Compose는 내부 DB를 만들지 않는다.
- 따라서 이 값이 곧 실제 운영/개발 외부 DB 연결 정보다.
- 이 정보가 틀리면
backend는 기동해도 API에서 DB 오류가 난다.
9. 현재 Docker 파일이 어떻게 동작하는지 이해하기
9.1 Dockerfile.frontend
확인 위치: 프로젝트 루트 / VS Code
현재 내용 핵심:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 8080
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
의미:
- Node 20 Alpine 기반
- 의존성 설치 후 전체 소스 복사
- Vite 개발 서버 실행
9.2 Dockerfile.backend
확인 위치: 프로젝트 루트 / VS Code
현재 내용 핵심:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["npm", "run", "server"]
의미:
- Node 20 Alpine 기반
- Express 서버 실행
9.3 vite.config.ts
확인 위치: 프로젝트 루트 / VS Code
현재 핵심:
const proxyTarget = process.env.VITE_DEV_PROXY_TARGET || 'http://localhost:3000';
그리고 /api, /uploads가 모두 proxyTarget으로 프록시된다.
의미:
- 로컬 실행 시 기본값은
localhost:3000 - Docker 실행 시 Compose가
http://backend:3000을 주입
이 수정이 있어야 Docker 안에서도 화면에 데이터가 표시된다.
10. Docker Compose 기동
10.1 작업 실행 위치
이 단계는 반드시 Windows PowerShell에서 수행하는 것을 권장한다.
이유:
start_docker_wsl.ps1가 Windows 경로를 받아 WSL 경로로 바꾸는 구조다.- 한글/공백 경로에서 가장 안전하다.
10.2 권장 기동 방법
실행 위치: 프로젝트 루트의 Windows PowerShell
.\start_docker_wsl.ps1
또는
.\start_docker_wsl.bat
이 스크립트는 내부적으로 아래를 수행한다.
- PowerShell 출력 인코딩을 UTF-8로 설정
- 현재 Windows 경로를 WSL 경로로 변환
- WSL 동작 확인
- WSL 내부 Docker 동작 확인
docker compose up --build -d수행
10.3 직접 기동이 필요할 때
실행 위치: WSL Ubuntu 터미널
직접 실행 예시는 아래와 같다.
cd /mnt/c/Users/user/Desktop/안건\ 파일/itam
docker compose up --build -d
하지만 현재 프로젝트는 한글 경로 이슈가 있었기 때문에, 특별한 이유가 없으면 start_docker_wsl.ps1를 우선 사용한다.
11. 컨테이너 기동 후 검증
11.1 컨테이너 상태 확인
실행 위치: Windows PowerShell
wsl sh -lc "docker ps -a --format 'table {{.Names}}\t{{.Status}}' | grep itam"
정상 기대 상태:
itam-backend->Upitam-frontend->Up
현재는 itam-db, itam-db-bootstrap가 없어야 정상이다.
11.2 백엔드 API 확인
실행 위치: Windows PowerShell
Invoke-WebRequest -Uri http://localhost:3000/api/assets/master -UseBasicParsing | Select-Object -ExpandProperty StatusCode
정상 기대값:
200
이 검사는 backend가 외부 DB에 정상 연결됐는지 보는 가장 직접적인 검사다.
11.3 프런트 경유 API 확인
실행 위치: Windows PowerShell
Invoke-WebRequest -Uri http://localhost:8080/api/assets/master -UseBasicParsing | Select-Object -ExpandProperty StatusCode
정상 기대값:
200
이 검사는 프런트 프록시가 정상인지 확인한다.
예전에 화면에 데이터가 안 보였던 것은 외부 DB 자체가 아니라, 이 프록시 경로가 잘못돼 있었기 때문이다.
11.4 브라우저 화면 확인
실행 위치: 브라우저
http://localhost:8080
확인 포인트:
- 화면이 열리는지
- 목록/대시보드/테이블 데이터가 비어 있지 않은지
- 모달 진입 시 데이터가 정상적으로 보이는지
12. 지금 데이터가 표시되는 원리
현재는 내부 DB로 데이터를 옮겨 담지 않는다.
현재 실제 동작 원리는 다음과 같다.
- 브라우저가
frontend에 접속한다. - 프런트가
/api/...로 요청한다. - Vite 프록시가
backend:3000으로 요청을 넘긴다. backend가.env의 외부 MySQL에 직접 접속한다.- 조회 결과 JSON을 프런트가 받아 화면에 렌더링한다.
즉, 현재는 아래 구조다.
Browser -> frontend -> backend -> external MySQL
예전 외부 DB 구조에서 화면에 데이터가 안 보였던 이유는 외부 DB 때문이 아니라, 프런트 컨테이너가 localhost:3000을 잘못 바라보고 있었기 때문이다.
지금은 VITE_DEV_PROXY_TARGET: http://backend:3000으로 수정되어 있기 때문에 정상 표시된다.
13. 자주 헷갈리는 포인트
13.1 현재는 내부 DB 컨테이너가 없다
현재 docker-compose.yaml에는 아래가 없다.
db서비스db-bootstrap서비스itam_mysql_data볼륨
즉, DB는 Docker 스택 밖에 있다.
13.2 현재는 .env가 곧 실제 DB 연결 정보다
현재 backend는 아래처럼 Compose에서 그대로 받는다.
DB_HOST: ${DB_HOST}DB_PORT: ${DB_PORT}DB_USER: ${DB_USER}DB_PASS: ${DB_PASS}DB_NAME: ${DB_NAME}
즉, .env를 틀리게 적으면 화면도 데이터가 안 뜬다.
13.3 server.js는 여전히 중요하게 수정된 상태다
현재 server.js는 dotenv.config()를 사용한다.
이 구조는 이후 Compose나 실행 환경에서 변수를 주입할 때, 애플리케이션이 그 값을 받아들일 수 있게 하기 위해 유지해야 한다.
14. 스택 중지 방법
14.1 작업 실행 위치
Windows PowerShell / 프로젝트 루트
14.2 권장 종료 명령
.\stop_docker_wsl.ps1
또는
.\stop_docker_wsl.bat
이 스크립트는 내부적으로 WSL 경로 변환 후 docker compose down을 수행한다.
15. 장애 발생 시 점검 순서
15.1 frontend 화면은 뜨는데 데이터가 없을 때
실행 위치: Windows PowerShell
먼저 아래 두 API를 분리해서 본다.
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
판단 기준:
3000은 200이고8080만 실패 -> 프런트 프록시 문제- 둘 다 실패 -> 백엔드 또는 외부 DB 연결 문제
15.2 백엔드가 외부 DB에 연결되지 않을 때
실행 위치: Windows PowerShell
wsl sh -lc "docker logs --tail=200 itam-backend"
점검 항목:
.env의 DB 정보가 정확한지- 외부 DB 서버 접근이 가능한지
- 계정/비밀번호가 맞는지
- 방화벽 또는 네트워크 이슈가 없는지
15.3 프런트 프록시가 의심될 때
확인 위치: vite.config.ts, docker-compose.yaml
다음 두 설정이 유지되는지 확인한다.
vite.config.ts
const proxyTarget = process.env.VITE_DEV_PROXY_TARGET || 'http://localhost:3000';
docker-compose.yaml
VITE_DEV_PROXY_TARGET: http://backend:3000
이 둘 중 하나라도 바뀌면 Docker 안에서 화면 데이터가 다시 안 보일 수 있다.
16. 현재 기준 재현 절차 요약
가장 짧게 정리하면 아래 순서다.
- Gitea에서 소스를 클론한다.
- Windows PowerShell에서 프로젝트 루트로 이동한다.
.env에 외부 MySQL 정보를 작성한다.- Docker Desktop + WSL 통합 또는 WSL 내부 Docker 사용 가능 상태를 만든다.
start_docker_wsl.ps1를 실행한다.http://localhost:3000/api/assets/master가 200인지 확인한다.http://localhost:8080/api/assets/master가 200인지 확인한다.- 브라우저에서
http://localhost:8080을 열어 실제 데이터 표시를 확인한다.
17. 현재 최종 결론
현재 저장소의 도커라이징 구조는 실무 표준에 맞는 무상태 앱 컨테이너 + 외부 DB 구조다.
현재 핵심은 아래 세 가지다.
backend는 외부 MySQL에 직접 연결한다.frontend는backend:3000으로 API 프록시한다.- WSL 경로 변환 스크립트를 통해 Windows 한글 경로에서도 안정적으로 실행한다.
즉, 이 문서대로 진행하면 Gitea 소스만 받은 상태에서 지금과 같은 Docker 실행 구조를 재현할 수 있다.