로컬 환경에서 개발한 애플리케이션을 컨테이너화하고, 이를 쿠버네티스 클러스터 위에서 실행시키는 것은 클라우드 네이티브 개발의 기초가 되는 과정이다.
이번에는 NestJS 프레임워크로 간단한 백엔드 서버를 만들고, 이를 도커 이미지로 빌드한 뒤 쿠버네티스 파드(Pod)로 배포하여 접속하는 전체 워크플로우를 정리해보자.
1. NestJS 프로젝트 생성 및 로컬 테스트
가장 먼저 컨테이너에 담을 앱이 필요하다.
Node.js 기반의 프레임워크인 NestJS를 사용하여 기본 서버를 생성한다.
프로젝트 생성
NestJS CLI를 전역으로 설치하고 새로운 프로젝트(nest-server)를 생성한다.
# NestJS CLI 설치
sudo npm i -g @nestjs/cli
# 프로젝트 생성
cd ./Documents
nest new nest-server
로컬 구동 확인
IntelliJ 등의 IDE로 프로젝트를 열고 의존성 패키지를 설치한 뒤, 서버가 정상적으로 뜨는지 확인한다.
서버가 정상적으로 실행될 때 "Hello world!"를 화면에 출력하는 코드가 기본적으로 작성되어 있다.
# package.json의 모든 패키지 설치 및 실행
npm i (= npm install)
npm run start
localhost:3000번 포트로 정상 작동 되는 것("Hello world!" 출력)을 확인한다.
2. Dockerfile 작성 (Containerization)
애플리케이션을 컨테이너 이미지로 만들기 위해 Dockerfile을 작성한다.
이 파일은 이미지를 어떻게 빌드할지에 대한 명세서다.
Dockerfile
프로젝트 루트 경로에 Dockerfile을 생성하고 다음과 같이 작성한다.
FROM node
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build
EXPOSE 3000
ENTRYPOINT ["node", "dist/main.js"]
- FROM node: 베이스 이미지를 Node.js 공식 이미지로 지정한다.
- WORKDIR /app: 컨테이너 내부의 작업 디렉토리를 /app으로 설정한다. 이후 명령어는 이 경로에서 실행된다.
- COPY . .: 호스트의 현재 디렉토리 파일들을 컨테이너의 /app으로 복사한다.
- RUN: 이미지를 빌드하는 시점에 실행되는 명령어다. 의존성을 설치(npm install)하고 TypeScript를 빌드(npm run build)한다.
- ENTRYPOINT: 컨테이너가 시작될 때(Runtime) 실행될 명령어를 지정한다. 빌드된 main.js를 실행하게 된다.
.dockerignore 설정
이미지 빌드 시 불필요한 파일이 복사되는 것을 막기 위해 .dockerignore 파일을 생성한다.
node_modules
node_modules는 호스트 OS 기준의 바이너리가 포함될 수 있고 용량이 크기 때문에, 이미지를 빌드할 때 복사하지 않고 컨테이너 내부에서 npm install을 통해 새로 설치하는 것이 정석이다.
3. 도커 이미지 빌드 (Docker Build)
작성한 Dockerfile을 바탕으로 실제 이미지를 생성한다.
이 때 Docker Desktop 등을 실행하여 도커 데몬을 활성화하고 빌드해야만 정상적으로 빌드가 진행된다.
docker build -t nest-server .
4. 쿠버네티스 Pod 배포
이제 빌드된 이미지를 바탕으로 쿠버네티스 상에 파드(Pod)를 생성한다. 파드는 쿠버네티스에서 생성하고 관리할 수 있는 배포 가능한 가장 작은 컴퓨팅 단위다.
Pod Manifest 파일 작성 (YAML)
nest-pod.yaml 파일을 생성하여 파드의 스펙을 정의한다.
apiVersion: v1
kind: Pod
metadata:
name: nest-pod
spec:
containers:
- name: nest-container
image: nest-server:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3000
- imagePullPolicy: 기본적으로 쿠버네티스는 이미지를 원격 레지스트리(Docker Hub 등)에서 가져오려 한다. 여기서는 로컬에서 빌드한 이미지를 사용할 것이므로 Never 혹은 IfNotPresent로 설정해야 한다.
Pod 생성 (Declarative 방식)
작성한 YAML 파일을 이용해 클러스터에 파드 생성을 요청한다.
kubectl apply -f nest-pod.yaml
pod/nest-pod created라는 메시지와 함께 파드가 생성된다. apply 명령어는 원하는 상태를 선언적으로 쿠버네티스 API 서버에 전달하는 역할을 한다.
kubectl get pods
결과: nest-pod 1/1 Running STATUS가 Running이면 정상적으로 컨테이너가 기동 된 것이다.
5. Port Forwarding
파드는 클러스터 내부의 고유 IP를 가지지만, 이는 클러스터 외부(내 로컬 PC)에서 직접 접근할 수 없다.
외부로부터의 접속을 위해 포트 포워딩을 사용한다.
포트 포워딩 (Port-Forwarding)
kubectl port-forward nest-pod 3000:3000
이 명령어는 로컬 머신의 3000번 포트로 들어오는 트래픽을 쿠버네티스 클러스터 내부의 nest-pod 3000번 포트로 터널링해준다.
이제 브라우저나 Postman에서 localhost:3000으로 접속하면 NestJS 서버의 응답을 받을 수 있다.
리소스 정리
테스트가 끝나면 리소스를 삭제하여 클러스터를 정리한다.
kubectl delete pod nest-pod
kubectl get pods 명령어로 조회 시 No resources found가 출력되면 정상적으로 삭제된 것이다.
삭제한 파드를 다시 띄우려면 다시 kubectl apply -f nest-pod.yaml 로 파드를 생성하면 된다.
지금까지 '소스 코드 작성 -> Docker 이미지 빌드 -> Kubernetes Manifest 작성 -> Pod 배포'로 이어지는 애플리케이션 배포 사이클을 살펴보았다.
여기서 핵심 포인트는 애플리케이션이 호스트 환경에 종속되지 않고 컨테이너라는 격리된 환경에서 실행된다는 점, 그리고 쿠버네티스라는 오케스트레이션 도구를 통해 그 컨테이너(Pod)의 생명주기를 관리한다는 점이다.
6. 전체 시퀀스 흐름

'AI Journey > 클라우드' 카테고리의 다른 글
| [Docker] 도커 환경에서 FTP 서버 구축하기 (Pure-FTPd) (0) | 2026.01.13 |
|---|---|
| [Docker] Nginx 로그를 Fluentd를 통해 MongoDB에 저장하기 (중앙 집중형 로그 관리) (0) | 2026.01.12 |
| [Docker] 리소스 모니터링 도구 - events, stats, system, cAdvisor (0) | 2026.01.08 |
| [Docker] 파이썬 코드로 도커 제어하기: Docker SDK 활용 기초 (0) | 2026.01.08 |
| [Docker] 이미지 커밋(commit)과 Docker Hub 공유(push) (0) | 2026.01.07 |