🐳 Docker 배포 시 JSON 파일이 누락된 문제 해결기
NestJS 에서 개발을 완료하고 Docker Container 위에 배포를 시도했습니다.
그런데 컨테이너가 실행되자마자 바로 종료되어버리는 문제가 생겼습니다.
컨테이너 로그를 살펴보니, 소스코드에서 참조하고 있는 특정 파일을 "No such file or directory" 라며 찾지 못하고 있었고, 저는 분명히 그 파일도 함께 넣었다고 생각했기 때문에 조속히 해결하기 어려웠습니다.
그래서 직접 Docker 컨테이너 내부 파일을 확인하고자 했는데, 평소 실행중인 docker exec 명령어로만 파일 시스템을 보러 갔었기에, 실행중이지 않은 컨테이너 안을 어떻게 봐야 할까? 하다가 그 과정에서 배운 점들을 정리하고자 합니다.
📌 이 글에서 다루는 내용
- NestJS 에서 .json 등 TypeScript 외 리소스 파일을 dist/ 에 포함시키는 방법
- Docker 로 배포한 컨테이너 내부에 파일이 잘 들어갔는지 확인하는 방법
- 실행 중이지 않은 Docker 컨테이너의 파일 시스템을 확인하는 방법
🚨 문제 개요
NestJS 에서 아래와 같은 폴더 구조를 사용하고 있다고 가정해보겠습니다:
src/
├── contract/
│ └── abi.json ← 문제의 핵심
├── module/
├── app.module.ts
├── main.ts
여기서 src/contract/abi.json 은 TypeScript 가 아닌 JSON 파일이므로, 기본적으로 NestJS Build 에 포함되지 않게 됩니다.
하지만 NestJS 코드에서는 이 파일을 경로 기반으로 불러오고 있습니다:
import * as path from 'path';
import * as fs from 'fs';
const abi = JSON.parse(fs.readFileSync(path.join(__dirname, "contract/abi.json"), "utf-8"));
직접 아래 명령어를 통해 NestJS 프로젝트를 빌드해보면:
yarn build
빌드 후에 dist/ 폴더를 봤을 때, abi.json 파일이 포함되지 않았습니다.
이 상태로 Docker 로 배포했더니 앱 실행 시 해당 파일을 찾지 못해 애플리케이션 에러가 발생하여 실행되지 않으니, 컨테이너가 바로 죽는 상황이 발생했습니다.
🛠 nest-cli.json으로 외부 파일 포함시키기
NestJS에서는 nest-cli.json 파일을 통해 컴파일 시 추가적으로 복사할 파일(assets) 을 지정할 수 있습니다.
아래와 같이 파일을 수정합니다:
{
"compilerOptions": {
"assets": [
{
"include": "contract/**/*.json",
"outDir": "dist/contract"
}
]
}
}
이렇게 설정하면, src/contract/*.json 파일들이 dist/contract/ 경로로 복사됩니다.
다시 아래 명령어로 빌드하여 확인합니다:
yarn build
실행 후, dist/contract/abi.json 파일이 제대로 생성되었는지 직접 확인해 보시기 바랍니다. 이제 런타임에서도 해당 JSON 을 제대로 읽어올 수 있게 되었습니다.
🐳 Dockerfile 설정 예시
이제 Docker 위에 NestJS 프로젝트를 띄워볼 차례입니다.
✅ 예시 Dockerfile
# 1. Node 이미지를 기반으로 시작
FROM node:20.12.2
# 2. 앱 디렉토리 생성
WORKDIR /app
# 3. 코드 복사 및 설치
COPY . .
RUN yarn install
# 4. NestJS 빌드
RUN yarn build
# 5. 앱 실행
CMD ["yarn", "start:prod"]
✅ Docker 빌드 및 실행
docker build -t my-nest-app .
docker run --name nest-prod -p 3000:3000 my-nest-app
`my-nest-app` 대신 원하는 이미지 이름을 지정해도 좋고, `nest-prod` 대신 원하는 컨테이너 이름을 지정해도 좋습니다.
❗ 컨테이너 실행이 안 되었다면?
컨테이너가 실행된 직후 아래 명령어를 통해 상태를 확인하고 로그를 확인할 수 있습니다.
# Docker 컨테이너 목록 확인법
docker ps
# 목록에 안 보이면, 전체 목록 (꺼진 것까지 포함)
docker ps -a
# 해당 컨테이너의 로그 확인
docker logs nest-prod
🔍 실행되지 않은 Docker 컨테이너 내부를 보는 방법
✅ 방법 1: `docker start` + `docker exec` - 일시적으로 켜고 내부 진입
컨테이너가 조금만 살아있을 수 있다면 (또는 잘 실행된 경우), 아래 명령어로 내부 Bash Shell 로 접속할 수 있습니다:
docker start nest-prod
docker exec -it nest-prod /bin/bash
`docker exec` 명령어는 해당 컨테이너에 대해 명령어를 주입하는 것으로, Bash 를 실행하는 명령어가 됩니다.
✅ 방법 2: `docker cp` - 파일만 복사하기
컨테이너가 종료되어 있더라도, 내부 파일을 꺼낼 수 있습니다!
docker cp nest-prod:/app/dist/contract/abi.json ./abi.json
`nest-prod` 컨테이너의 해당 경로 `/app/*` 에서 파일을 찾아 복사해올 수 있습니다. 만약 파일 복사가 제대로 되지 않는다면, 해당 위치에 파일이 없는 것입니다.
✅ 방법 3: Docker Volume 을 사용하는 경우
만약 컨테이너 실행 시 `-v` 옵션으로 볼륨을 따로 지정했다면, 해당 volume 을 다른 컨테이너로 마운트해서 탐색할 수 있습니다:
docker run -it --rm -v your_volume_name:/app alpine sh
✅ 마무리
NesJS 에서 `.json`, `.txt`, `.graphql` 등 TypeScript 외의 리소스들은 자동으로 build 결과에 포함되지 않습니다.
반드시 `nest-cli.json` 의 `assets` 항목을 설정해줘야 하고, 만약 서버 실행과 밀접한 관련성이 있으나, Docker 빌드 후 컨테이너가 올바르게 실행되지 않는다면, 실제로 해당 파일이 컨테이너 내부에 존재하는지 확인하도록 합니다.
'개발 💻 > NestJS' 카테고리의 다른 글
[초보자의 눈으로 보는 NestJS] 7. 데이터베이스 연동 (TypeORM) (1) | 2025.03.19 |
---|---|
[Swagger] BasicAuth 문서 접근 보안 (0) | 2025.01.08 |
[초보자의 눈으로 보는 NestJS] 6. DTO와 Validation (1) | 2024.05.31 |
class-validator 의 @IsBoolean 데코레이터와 enableImplicitConversion 설정된 Transform 의 문제 (0) | 2024.02.29 |
[초보자의 눈으로 보는 NestJS] 5. 유저 서비스의 구현 (1) | 2024.02.24 |