Dockerfile로 내 프로그램을 이미지로 만드는 방법
앞서 Node.js로 간단한 웹 서버를 만들었다면, 이제 그 프로그램을 실제로 배포 가능한 형태로 만들어볼 차례다.
Docker의 핵심은 “내가 만든 프로그램을 그대로 복제 가능한 이미지로 만드는 것”에 있다.
이번 포스트에서는 Dockerfile을 직접 작성하고, 이를 이용해 Node.js 서버를 Docker 이미지로 만드는 전체 과정을 정리한다.
내 프로그램을 Docker 이미지로 만들기 위해 필요한 과정은 매우 단순하다.
- 소스 코드가 있는 디렉터리에 Dockerfile을 생성한다.
- 이미지에 어떤 환경과 파일이 필요한지 Dockerfile에 작성한다.
- 터미널에서 docker build 명령어를 실행한다.
- 이미지가 생성된다.
Dockerfile이란?
Dockerfile은 이미지 생성을 위한 레시피 파일이다.
여기에는 다음과 같은 내용을 모두 기술할 수 있다.
- 어떤 운영체제를 사용할지
- 어떤 프로그램과 라이브러리를 설치할지
- 어떤 명령어를 실행할지
- 어떤 파일을 이미지 안으로 복사할지
즉, “이 프로그램을 실행하려면 어떤 과정을 거쳐야 하는가”를 그대로 문서화한 파일이다.
이전에 서버를 만들 때 다음과 같은 작업을 했다.
- Node.js 설치
- npm install express 실행
- server.js 작성
- node server.js로 서버 실행
Dockerfile에는 위의 과정을 그대로 옮기면 된다.
단, Dockerfile 문법으로 작성해야 한다는 점만 다르다.
Dockerfile의 문법
FROM: 어떤 이미지에서 시작할 것인가
Dockerfile은 항상 FROM으로 시작한다.
FROM에는 “기반이 될 이미지”를 작성한다.
이미 존재하는 다른 이미지를 기반으로 새 이미지를 만드는 방식이다.
보통은 다음 중 하나를 선택한다.


이 이미지는 DockerHub에서 찾을 수 있다.
- 순수 OS 이미지 (ubuntu, debian, alpine 등)
- OS + 언어 런타임이 포함된 이미지 (node, python 등)
서버 비용과 이미지 크기를 고려하면 Linux가 서버비가 덜 들기 때문에 Linux 기반 이미지를 사용하는 것이 일반적이다.
Node.js 공식 이미지 사용하기
Node.js 서버를 만들었기 때문에 Node.js가 설치된 공식 이미지를 사용하는 것이 가장 합리적이다.
이런 이미지는 Docker Hub에서 제공된다.

예를 들어 다음과 같은 이미지가 있다.
- node:20-alpine
- node:20-slim
이는 각각 Node.js 20 버전이 Alpine Linux 혹은 Slim Linux 위에 설치된 이미지다.
slim은 필요 없는 내용을 전부 지운 Debian Linux이고, alpine은 용량이 가장 작은 Linux라고 보면 된다.
여기서는 다음을 사용한다.
FROM node:20-slim
로컬에서 사용하던 Node.js 버전과 동일한 버전을 명시하는 것이 안정적이다.
latest 태그를 쓰는 것도 가능하지만, 예기치 않은 버전 변경으로 문제가 발생할 수 있다.
만약 이 이미지가 이미 내 로컬에 저장되어 있다면 그걸 가져다 쓰고, 없다면 DockerHub에서 다운로드 받아서 불러오게 된다.
여기까지 우리는 OS와 Node.js를 설치한 것이다.
라이브러리 설치하기
로컬 환경에서는 다음과 같은 방식으로 라이브러리를 설치했다.
npm install express
Docker 이미지에서도 이 과정을 그대로 재현하기 위해 “라이브러리를 설치하라”는 명령을 Dockerfile에 작성해야 한다.
하지만 여기서 한 가지 문제가 생긴다.
만약 설치해야 할 라이브러리가 하나뿐이라면 문제가 크지 않다.
그러나 실제 프로젝트에서는 라이브러리가 수십 개, 많게는 수백 개가 된다.
이때 Dockerfile에 다음과 같이 작성하면 문제가 발생할 수 있다.
RUN npm install express
이 방식은 항상 최신 버전의 express를 설치한다.
로컬 환경에서 사용하던 버전과 이미지 안에서 설치되는 버전이 달라질 수 있고,
이로 인해 “내 컴퓨터에서는 되는데 서버에서는 안 되는” 상황이 발생할 수 있다.
package.json을 기준으로 설치해야 하는 이유

Node.js 프로젝트에서는 사용하는 라이브러리와 버전 정보가 package.json 파일에 정확히 기록되어 있다.
따라서 가장 안전한 방식은 다음과 같다.
- package.json 파일을 다른 환경으로 복사한다.
- npm install 명령어를 실행한다.
- package.json에 기록된 버전 그대로 라이브러리를 설치한다.
이 방식은 환경이 달라져도 항상 동일한 라이브러리 조합을 보장한다.
package.json을 이미지로 복사하기
Dockerfile에서 로컬 파일을 이미지 안으로 복사할 때는 COPY 명령어를 사용한다.
COPY . .
이 명령은 현재 디렉터리에 있는 모든 파일을 이미지의 현재 작업 디렉터리로 복사한다.
즉, 로컬에 있는 package.json도 함께 이미지로 들어간다.
.dockerignore로 복사 대상에서 제외하기
하지만 모든 파일을 이미지에 복사하는 것은 바람직하지 않다.
다음 파일과 디렉터리는 이미지에 포함할 필요가 없다.
- node_modules
- Dockerfile
- .git 디렉터리
이 파일들은 용량만 차지하고, 이미지 실행에는 필요하지 않다.

복사에서 제외할 파일은 .dockerignore 파일로 지정할 수 있다.
예를 들면 다음과 같이 작성한다.
node_modules
Dockerfile
.git
이렇게 하면 COPY 명령어를 실행할 때 해당 파일과 디렉터리는 자동으로 제외된다.
그 결과, 소스 코드와 package.json만 깔끔하게 이미지로 복사된다.
WORKDIR: 작업 디렉터리 정리하기
COPY를 하기 전에 작업 디렉터리를 먼저 설정하는 것이 좋다.
WORKDIR /app
이 명령은 이미지 안에 /app 디렉터리를 생성하고,
이후 모든 명령을 해당 디렉터리 기준으로 실행하도록 만든다.
그 다음 COPY를 실행하면, 모든 파일이 /app 디렉터리 안으로 복사된다.
소스 코드가 한 폴더에 정리되므로 구조가 훨씬 깔끔해진다.
package.json을 기준으로 라이브러리 설치하기
이제 라이브러리를 설치한다.
RUN npm install
이 명령은 package.json에 기록된 모든 라이브러리를 해당 버전 그대로 설치한다.
이렇게 하면 로컬 환경과 이미지 환경의 라이브러리 구성이 완전히 동일해진다.
이때 RUN 명령어는 다음과 같이 작성할 수도 있다.
RUN ["npm", "install"]
이 방식은 shell을 거치지 않고 명령어를 직접 실행한다.
OS마다 shell 환경이 다른 경우 발생할 수 있는 호환성 문제를 줄일 수 있기 때문에,
일반적으로 이 방식을 더 권장한다.
서버 실행 명령은 RUN이 아닌 CMD
서버를 실행할 때 다음과 같이 작성하면 안 된다.
RUN ["node", "server.js"]
RUN은 이미지를 빌드하는 시점에 실행되는 명령이다.
서버 실행은 컨테이너가 시작될 때 실행되어야 한다.
따라서 Dockerfile의 마지막에는 CMD를 사용한다.
CMD ["node", "server.js"]
ENTRYPOINT를 사용해도 동일하게 동작한다.
CMD와 ENTRYPOINT의 차이는 있지만, 이 단계에서는 큰 차이가 없다.
EXPOSE로 포트 정보 명시하기
FROM node:20-slim
WORKDIR /app
COPY . .
RUN ["npm", "install"]
EXPOSE 8080
CMD ["node", "server.js]
마지막으로 EXPOSE 명령어를 추가할 수 있다.
EXPOSE는 이 컨테이너가 어떤 포트를 사용하고 있는지를 명시하는 문서화용 설정이다.
실제로 포트를 외부에 열어주는 기능은 없다.
현재 서버 코드에서는 8080 포트를 사용하고 있으므로,
이를 Dockerfile에 명시해두면 이후 컨테이너 실행 시 이해하기가 쉬워진다.
필수는 아니며, 삭제해도 기능적으로 문제는 없다.
이미지 빌드하기
Dockerfile 작성이 끝났다면 이미지를 생성한다.

터미널에서 다음 명령어를 실행한다.
docker build -t nodeserver:v1 .
- -t는 이미지 이름과 태그를 지정한다.
- 마지막의 .은 Dockerfile이 현재 디렉터리에 있다는 의미다.
빌드가 완료되면 이미지가 하나 생성된다.

Docker Desktop을 열어보면 nodeserver:v1 이미지가 목록에 나타난다.
이를 실행하면 컨테이너가 생성된다.
포트 설정에서 다음과 같이 매핑한다.

- 로컬 8080 → 컨테이너 8080

이제 브라우저에서 해당 주소로 접속하면,
로컬에서 실행했던 것과 동일한 서버가 동작하는 것을 확인할 수 있다.

'Tool 활용법 > Docker 활용법' 카테고리의 다른 글
| [Docker 기초 4] Dockerfile 성능 최적화 방법 (Cache, Multi-Stage build) (0) | 2026.02.06 |
|---|---|
| [Docker 기초 3] Docker Container 필수 명령어 정리 (0) | 2026.02.06 |
| [Docker 기초 1] Docker로 띄울 간단한 웹서버 만드는 방법 (0) | 2026.02.05 |
| Docker와 Container 기술 구체적으로 살펴보기 (0) | 2026.02.05 |
| Docker 설치방법 및 기본 이미지 실행하기 (Image) (0) | 2026.02.05 |