포스트

Docker #2 - 이미지, 컨테이너, Dockerfile, 읽기 전용 레이어

Docker 이미지와 컨테이너의 동작 원리, Dockerfile 작성법, 이미지 레이어와 캐싱 전략

Docker #2 - 이미지, 컨테이너, Dockerfile, 읽기 전용 레이어

이미지 (Image)

설계도만 있다면 어디서든 동일한 결과물(컨테이너)를 만들어 낼 수 있다.

  • 재사용성: 한번만 잘 만들어 두면 이미지를 팀원과 공유하거나 여러 서버에 배포하여 동일한 환경을 수십, 수백 개 복제할 수 있다.

  • 불변성 (Immutable): 이미지는 한 번 빌드되면 내용이 변하지 않는다.

    • 만약 프로젝트를 진행하다가 코드에 변경 사항이 생기는 경우, 변경된 코드를 포함하여 새로운 이미지를 다시 빌드해야 한다.

컨테이너 (Container)

이미지의 실행 가능한 인스턴스(Instance)이다.

  • 격리된 실행 공간: 실제 애플리케이션이 실행되는 격리된 공간이다.
  • 독립성: 컨테이너는 호스트 시스템이나 다른 컨테이너와 완전히 분리되어 독립적으로 작동한다.
  • 멀티 애플리케이션 지원: 덕분에 하나의 서버에서 여러 애플리케이션을 충돌 없이 실행할 수 있다.

  • 1:N 관계: 하나의 이미지로 여러 개의 컨테이너를 생성하고 실행할 수 있으며, 각 컨테이너는 서로 영향을 주지 않는 독립적인 환경이기 때문에 충돌이 발생하지 않는다.

Dockerfile 작성법

Dockerfile은 이미지를 어떻게 만들지 도커에게 알려주는 텍스트 파일이다.

1
2
3
4
5
6
7
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 80
CMD ["node", "server.js"]

주요 명령어 설명

  • FROM node:18-alpine
    • 어떤 베이스 이미지에서 시작할지 지정한다.
    • 이미 검증된 Node.js 공식 이미지를 기반으로 우리만의 설정을 추가하겠다는 의미이다.
  • WORKDIR /app
    • 컨테이너 내부의 작업 디렉터리를 /app으로 설정한다.
    • 이후의 COPY, RUN 등의 명령어는 이 디렉터리를 기준으로 실행된다.
    • 컨테이너 파일 시스템의 루트를 어지럽히지 않고 깔끔하게 관리할 수 있다.
  • COPY package*.json ./
    • 의존성 설정 파일을 먼저 복사한다.
  • RUN npm install
    • 이미지를 빌드하는 과정에서 실행할 명령이다.
    • 필요한 모든 의존성 패키지를 이미지 내부에 설치한다.
  • COPY . .
    • 현재 디렉터리의 모든 파일과 폴더를 컨테이너의 /app 디렉터리로 복사한다.
  • EXPOSE 80
    • 이 컨테이너가 80번 포트를 사용할 것임을 문서화하는 역할을 한다.
    • 실제로 포트를 외부에 노출시키지는 않지만, 이 이미지를 사용하는 다른 사람에게 어떤 포트를 열어야 하는지 알려주는 중요한 정보이다.
  • CMD [“node”, “server.js”]
    • 이 이미지로부터 컨테이너가 시작될 때 실행될 기본 명령이다.
    • RUN과의 결정적인 차이점이다.

이미지 레이어와 캐싱 전략

도커 이미지는 여러 개의 읽기 전용 레이어가 겹쳐진 구조로 되어 있다.

레이어 구조의 이해

  • 레이어 생성: Dockerfile의 각 명령어는 새로운 레이어를 생성한다.
  • 레이어 스택: 여러 레이어가 겹쳐져서 최종 이미지를 만든다.
  • 읽기 전용: 각 레이어는 한 번 생성되면 변경되지 않는다.

캐싱 메커니즘

  • 캐시 저장: docker build를 실행할 때, 도커는 각 명령어(레이어)의 결과를 캐시에 저장한다.
  • 캐시 재사용: 다음 번에 빌드할 때는 Dockerfile의 내용이나 COPY할 파일의 내용이 바뀌지 않았다면, 도커는 명령을 다시 실행하지 않는다.
  • 레이어 무효화: 한 레이어가 변경되면 그 이후의 모든 레이어가 무효화된다.

빌드 최적화 전략

문제 상황:

1
2
3
# 비효율적인 순서
COPY . .           # 소스코드 변경 시 이 레이어가 무효화됨
RUN npm install    # 매번 다시 실행됨

해결 방법:

1
2
3
4
# 효율적인 순서
COPY package*.json ./  # 의존성 파일만 먼저 복사
RUN npm install        # package.json이 동일하면 캐시 사용
COPY . .              # 나머지 소스코드 복사

최적화 효과:

  • 소스코드가 변경되어도 package.json이 동일하면 npm install은 캐시를 사용
  • 빌드 시간이 크게 단축됨
  • 불필요한 의존성 재설치 방지

주요 도커 명령어

이미지 관련 명령어

1
2
3
4
5
6
7
8
9
10
11
# 이미지 빌드
docker build -t my-app .

# 이미지 목록 확인
docker images

# 이미지 삭제
docker rmi <image_id>

# 이미지 상세 정보 확인
docker inspect <image_id>

컨테이너 관련 명령어

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 컨테이너 실행
docker run -p 3000:3000 my-app

# 백그라운드에서 컨테이너 실행
docker run -d -p 3000:3000 my-app

# 실행 중인 컨테이너 확인
docker ps

# 모든 컨테이너 확인 (중지된 것 포함)
docker ps -a

# 컨테이너 중지
docker stop <container_id>

# 컨테이너 삭제
docker rm <container_id>

# 컨테이너 로그 확인
docker logs <container_id>

# 실행 중인 컨테이너에 접속
docker exec -it <container_id> /bin/bash

유용한 옵션들

1
2
3
4
5
6
7
8
9
10
11
# 포트 매핑
docker run -p 8080:3000 my-app

# 환경 변수 설정
docker run -e NODE_ENV=production my-app

# 볼륨 마운트
docker run -v /host/path:/container/path my-app

# 컨테이너 이름 지정
docker run --name my-container my-app
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.