컨테이너 용어 사전
이미지image · 레이어 · OCI

이미지

읽기 전용 템플릿. 겹겹이 쌓인 레이어로 이뤄지고, 같은 레이어는 한 벌만 저장된다.

컨테이너를 만드는 읽기 전용 템플릿. 통짜 파일이 아니라 겹겹이 쌓인 레이어다.

FROM alpine:3.20              # 레이어 1 — 베이스
RUN apk add --no-cache curl   # 레이어 2 — 설치로 바뀐 파일들
COPY app /app                 # 레이어 3 — 추가된 파일

각 레이어는 '이전 상태 대비 무엇이 바뀌었나' 만 담는다

  • 추가된 파일
  • 수정된 파일 (통째로 다시 담긴다)
  • 삭제된 파일 (whiteout 이라는 표식으로 기록된다)

레이어는 읽기 전용이고, 내용이 정해지면 그 해시가 곧 식별자다

이미지와 컨테이너는 다른 것이다

  • 이미지 — 읽기 전용 템플릿
  • 컨테이너 — 그 위에 쓰기 가능한 얇은 레이어를 하나 얹은 실행 인스턴스

클래스와 인스턴스의 관계와 같다 이미지 하나로 컨테이너를 100개 만들어도 이미지는 한 벌만 저장된다

공유가 배포 속도를 만든다

같은 베이스를 쓰는 이미지 10개

  • 베이스 레이어는 디스크에 한 벌만 있다

레지스트리에서 받을 때도 이미 가진 레이어는 건너뛴다

  • "이미지가 2GB 인데 배포는 금방 끝난다" 의 이유

그래서 베이스 이미지를 팀 안에서 통일하는 것이 실제 이득이 된다 제각각이면 노드마다 레이어가 중복 저장되고 pull 시간도 늘어난다

지운다고 작아지지 않는다

RUN wget big-file.tar.gz && tar xf big-file.tar.gz
RUN rm big-file.tar.gz        # ← 크기가 안 줄어든다
  • 레이어는 추가만 된다. 삭제는 '지웠다는 표식' 을 추가하는 것이다
  • 앞 레이어의 실제 데이터는 이미지 안에 그대로 남아 있다

같은 이유로

  • 앞 레이어에 넣은 비밀 파일은 지워도 꺼낼 수 있다
  • ARG 로 넘긴 토큰이 RUN 명령에 찍히면 docker history 에 남는다

정리는 반드시 '같은 RUN' 안에서 한다

OCI 표준

이미지 스펙 · 런타임 스펙 · 배포 스펙이 표준화돼 있다

덕분에 도구를 갈아 끼울 수 있다
  빌드       Buildx/BuildKit · Buildah · Kaniko
  런타임     containerd · CRI-O
  레지스트리 Docker Hub · ECR · GHCR · Harbor

"도커로 만든 이미지" 라는 말은 정확하지 않다 — OCI 이미지다

레지스트리와 주고받는 방식

  • push — 레이어를 하나씩 올린다. 이미 있는 레이어는 건너뛴다

  • pull — 매니페스트를 먼저 받아 필요한 레이어만 내려받는다

  • 매니페스트 — 이 이미지가 어떤 레이어들로 이뤄졌는지의 목록

      • 설정(config) 객체의 다이제스트
  • 그래서 태그를 바꿔 다시 올려도 레이어는 재전송되지 않는다

이미지를 들여다보는 법

docker history --no-trunc myapp:1.0     # 레이어별 크기와 만든 명령
docker image inspect myapp:1.0          # 설정 · 환경변수 · 엔트리포인트
docker save myapp:1.0 | tar -tv | head  # 레이어 tar 목록

docker history 로 '어느 명령이 몇 MB 를 더했는지' 가 바로 보인다 크기 문제를 잡을 때 가장 먼저 여는 명령이다

inspect 의 Config.User 가 비어 있으면 root 로 도는 이미지다

면접 함정

  • "이미지를 지우면 용량이 준다" → 다른 이미지와 공유하는 레이어는 남는다.
  • "파일을 지운 레이어를 추가하면 작아진다" → 앞 레이어에 그대로 남는다.

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — 이미지와 레이어 — 빌드가 빨랐다 느렸다 하는 이유