Skip to Content
Sunbeen's Blog
DocumentsDockerDocker 이미지 빌드하기

Docker 이미지 빌드하기

Node.js 애플리케이션을 실행하는 커스텀 이미지를 만드는 과정입니다

1. FROM – 베이스 이미지 설정

어떤 이미지를 기반으로 새 이미지를 만들 것인지”를 정하는 명령어입니다.

이미 존재하는 다른 이미지 위에 여러분의 커스텀 이미지를 쌓는다.

# "Node.js가 설치된 베이스 이미지 사용 FROM node
  • 도커는 이미지를 계층(layer) 구성
  • FROM은 가장 아래 “밑바탕 레이어”
  • 도커는 도커 허브(Docker Hub) 공개 이미지 저장소
    • 해당 이미지가 로컬에 있으면 사용
    • 없으면 도커 허브에서 다운로드
  • 다운로드는 딱 한 번만 하고, 그 후로는 로컬에 캐시된 이미지를 재사용한다.
  • 처음부터 OS설치, Node 설치도 하며 직접 만들 수도 있지만, 비효율적이기 때문에 하지않는다.

2. COPY – 로컬 파일 → 컨테이너 복사

  • 컨테이너는 호스트와 완전히 분리된 내부 파일 시스템을 가짐
  • 우리가 만든 앱 코드와 설정 파일을 컨테이너 내부로 복사
COPY . /app
  • 앞의 ‘.’은 호스트의 현재 디렉토리 (Dockerfile이 있는 위치)
  • 뒤의 /app은 컨테이너 안에 생성될 작업 디렉토리

3. 컨테이너에서 /app 폴더를 사용하는 이유?

컨테이너의 루트(/)에 바로 복사할 수도 있지만, 보통 **서브 디렉토리(/app)**를 사용

도커 컨테이너 내부에 숨겨져 있는 파일 시스템 존재합니다.

✅ 구조 정리

  • 루트에는 /bin, /etc 등 시스템 디렉터리가 존재 → 섞이면 혼란

✅ 권한 문제 방지

  • 루트는 쓰기 제한이 걸릴 수 있음
  • 사용자 정의 경로는 안전

✅ 표준화

  • 공식 이미지(Node, Python 등)들도 /app 또는 /usr/src/app을 사용
  • DevOps 자동화 툴들이 기대하는 구조

4. WORKDIR – 작업 디렉토리 설정

  • 작업 디렉토리의 폴더를 변경합니다.
  • 이후의 모든 COPY, RUN, CMD 명령은 /app 기준으로 동작
  • 존재하지 않는 경로여도 자동으로 생성
# WORKDIR /app 변경 # root DIR을 기준으로 파일 복사를 실행하여 # 동일한 결과물을 보인다. WORKDIR /app COPY . /app # 현재 WORKDIR이 /app인 상태에서 # 상대 폴더이기 때문에 정상 복사된다. WORKDIR /app COPY . ./

5. RUN – 이미지 빌드 중 실행할 명령

종속성 설치를 위해 다음 명령을 실행

RUN npm install
  • RUN이미지 빌드 시 한 번만 실행되며, 결과는 이미지에 저장됩니다.
  • 이 폴더가 존재하지 않는 경우에는 이미지와 컨테이너에 생성
  • WORKDIR을 수행하지 않았다면 root 에서 실행

6. CMD – 컨테이너 시작 시 실행할 명령

CMD ["node", "server.js"]
  • 이 명령은 컨테이너가 실행될 때 node server.js를 실행합니다.

  • ["명령", "인자"] 형태는 JSON 배열로, 실행 오류 가능성을 줄여줍니다.

  • 컨테이너를 실행할 때 시작하고싶다면

    • RUN node server.js는 틀렸다
    • RUN이미지를 만드는 시점에 실행
    • 서버는 컨테이너가 실행될 때 실행돼야 함

7. EXPOSE – 포트 열기

  • 도커 컨테이너는 기본적으로 외부에 포트를 노출하지 않습니다.
  • 외부에서 컨테이너에 접속하기 위해선 포트를 명시적으로 열어줘야 합니다.
EXPOSE 80

해당 컨테이너가 80번 포트를 사용한다는 의미

8. 최종 Dockerfile

FROM node WORKDIR /app COPY . /app RUN npm install EXPOSE 80 CMD ["node", "server.js"]
명령어실행 시점역할
FROM처음베이스 이미지 지정
COPY빌드 중로컬 파일 → 컨테이너 복사
WORKDIR빌드 중작업 디렉터리 설정
RUN빌드 중종속성 설치 등 실행
EXPOSE선언용열어줄 포트 정의
CMD컨테이너 실행 시실행할 서버/명령 지정

9.이미지 빌드 시작하기

  • 경로를 지정하여 컨테이너를 빌드합니다.
docker build .

10. 이미지로 컨테이너 실행하기

docker run <IMAGE_ID> # 호스트 컴퓨터와 컨테이너 포트 명시 docker run -p 3000:80 <IMAGE_ID>
  • 컨테이너가 실행되고, 내부의 Node 서버도 실행
  • 이 서버는 백그라운드에서 계속 작동하므로 컨테이너도 중단되지 않습니다.
  • Dockerfile에 EXPOSE 80을 적어도 실제로 포트를 열어주지는 않습니다. 이는 문서용 선언일 뿐입니다.
  • 컨테이너를 실행할 때 호스트와 ****연결할 포트를 명시적으로 지정해야 합니다

11. 컨테이너 상태 확인

# 현재 실행중인 컨테이너 리스트 표시 docker ps # 모든 컨테이너 상태보기 docker ps -a

12. 컨테이너 중지

docker stop <CONTAINER_NAME>

13. 코드 바꾸고 새로고침해도 변경 사항이 바로 적용 되지않는다.

이미지에 복사된 코드는 ‘스냅샷’으로 존재합니다.

docker build를 통해 이미지를 만들면, 그 순간의 코드 상태가 이미지 안에 복사됩니다.

그 이후에 소스 코드를 수정해도, 이미지는 그걸 알지 못하기 때문에, 즉각적으로 반영되지 않습니다.

우리가 다시 실행 해도 이전 스냅샷 기반으로 컨테이너가 실행됩니다.

docker build -t my-image . docker run -p 3000:3000 my-image

변경된 코드를 적용하려면 새롭게 빌드를 실행하여, 새로운 이미지를 생성하고, 그걸 바탕으로 새로운 컨테이너를 실행 해야합니다.

즉 코드를 바꿨다면 docker builddocker run 다시 해줘야 됩니다.

Docker 이미지의 레이어 구조

이미지는 레이어(layer)

Dockerfile의 한 줄 명령어가 곧 하나의 레이어입니다.

# layer 1 WORKDIR /app # layer 2 COPY . . # layer 3 RUN npm install

세 줄이 작성되어 있다면, 총 3개의 레이어가 만들어집니다. Docker는 이 레이어 각각의 결과를 **캐시(cache)**로 저장해두게 됩니다.

이미지를 다시 빌드할 때, 명령어 내용과 관련된 파일들이 이전과 동일하다면

Docker는 해당 명령어의 실행 결과를 다시 계산하지 않고 캐시된 결과를 재사용합니다.

이러한 구조를 레이어 기반 아키텍처라고 부릅니다.

캐시가 무효화되는 조건

한 레이어의 입력 또는 명령이 달라지면, 그 아래에 있는 모든 레이어는 다시 실행됩니다.

예를 들어 아래와 같이 Dockerfile을 작성했다면,

COPY . . RUN npm install

JS 파일 하나만 수정해도 COPY . . 레이어는 다시 실행되며,

그 이후의 RUN npm install도 함께 다시 실행됩니다.

그러나 실제로는 패키지 목록이 담긴 package.json이 바뀌지 않았다면

npm install을 다시 실행할 필요는 없습니다.

npm install 이전에 package.json만 복사하기

COPY package*.json ./ RUN npm install COPY . .

매번 npm install을 다시 실행하는 일을 피할 수 있고, 빌드 시간도 훨씬 단축됩니다.

본 문서는 Udemy 강의: Docker & Kubernetes : 실전 가이드의 내용을 바탕으로 학습한 내용을 정리한 것입니다.

Last updated on