포스트

Docker 이미지는 정말 OS일까?

Docker 이미지는 정말 OS일까?

들어가면서

이전 포스트들에서 VM과 컨테이너의 근본적인 차이컨테이너가 어떻게 격리되는지 살펴보았다. 컨테이너는 호스트 OS의 커널을 공유하며 가볍게 동작한다고 했는데, 그렇다면 우리가 흔히 사용하는 ubuntualpine 같은 Docker 이미지는 정말 운영체제(OS)일까?

많은 개발자가 Docker 이미지를 “작은 VM”이나 “OS가 통째로 들어있는 것”으로 오해하곤 한다. 이번 글에서는 이러한 오해를 풀고, Docker 이미지의 본질이 무엇인지, 그리고 이미지와 컨테이너의 관계를 명확히 이해하고자 한다.

이 글의 목표

  • Docker 이미지의 본질을 이해한다.
  • 이미지와 컨테이너 차이를 설명할 수 있다.

Docker 이미지 구조와 RootFS

1. 문제 제기: Docker 이미지는 OS인가?

우리는 docker run ubuntu와 같은 명령어로 컨테이너를 실행한다. 이때 사용되는 ubuntu 이미지는 정말 Ubuntu OS 전체를 담고 있을까? 만약 그렇다면, 컨테이너가 호스트 OS의 커널을 공유한다는 말과 모순되지 않을까?

이 질문에 답하기 위해 Docker 이미지의 구성 요소와 작동 방식을 깊이 있게 들여다볼 필요가 있다.


2. Docker Image란?

Docker 이미지는 컨테이너를 실행하기 위한 모든 것을 담고 있는 읽기 전용(Read-Only) 템플릿이다. 여기에는 애플리케이션 코드, 런타임, 시스템 도구, 시스템 라이브러리, 설정 파일 등이 포함된다.

  • 읽기 전용 레이어: Docker 이미지는 여러 개의 읽기 전용 레이어로 구성된다. 각 레이어는 Dockerfile의 명령(예: RUN, COPY)에 의해 생성되며, 이전 레이어 위에 쌓이는 방식으로 변경 사항을 기록한다. 이는 이미지의 효율적인 저장 및 재사용을 가능하게 한다.
  • 실행 가능한 패키지: 이미지는 특정 애플리케이션을 실행하는 데 필요한 모든 종속성을 포함하는 독립적인 실행 가능한 패키지이다.

3. RootFS(Root File System)의 정체

Docker 이미지가 OS가 아니라고 한다면, ubuntu 이미지 안에는 무엇이 들어있을까? 바로 RootFS(Root File System)이다. RootFS는 컨테이너가 시작될 때 / 디렉토리에 마운트되는 파일 시스템으로, 컨테이너 내부에서 애플리케이션이 동작하는 데 필요한 모든 파일과 디렉토리를 포함한다.

  • /bin: 실행 가능한 바이너리 파일 (예: ls, cat)
  • /lib: 공유 라이브러리 파일
  • /usr: 사용자 프로그램 및 라이브러리
  • package files: 애플리케이션 및 그 종속성 파일

이 RootFS는 마치 리눅스 배포판의 파일 시스템 구조와 유사하지만, 커널은 포함하지 않는다. 컨테이너는 이 RootFS를 기반으로 호스트 OS의 커널 위에서 동작한다.


4. 왜 커널은 포함되지 않을까?

Docker 이미지가 커널을 포함하지 않는 가장 큰 이유는 컨테이너가 호스트 OS의 커널을 공유하기 때문이다.

  • Host kernel 공유: 컨테이너는 호스트 OS의 커널을 직접 사용하여 시스템 콜을 처리한다. 이는 VM과 컨테이너는 무엇이 다를까?에서 설명했듯이, 컨테이너가 VM보다 가볍고 빠르게 동작하는 핵심 원리이다.
  • 시스템 콜 흐름: 컨테이너 내부의 애플리케이션이 시스템 콜을 호출하면, 이 요청은 컨테이너의 RootFS를 거쳐 호스트 OS의 커널로 직접 전달된다. 별도의 Guest OS 커널을 거치지 않으므로 이미지에 커널을 포함할 필요가 없다.

5. Image vs Container: 설계도와 실행 중인 프로세스

Docker에서 이미지(Image)와 컨테이너(Container)는 밀접하게 관련되어 있지만, 명확히 다른 개념이다.

구분Image (이미지)Container (컨테이너)
정의애플리케이션 실행에 필요한 모든 것을 담은 읽기 전용 템플릿 (설계도)이미지의 실행 가능한 인스턴스 (실행 중인 프로세스)
상태정적(Static), 불변(Immutable)동적(Dynamic), 가변(Mutable)
생성Dockerfile을 통해 빌드docker run 명령어로 이미지로부터 생성
구성여러 개의 읽기 전용 레이어 + RootFS이미지 레이어 + 쓰기 가능한 컨테이너 레이어
커널포함하지 않음호스트 OS의 커널 공유

6. Dockerfile 이해하기: 이미지 빌드의 청사진

Dockerfile은 Docker 이미지를 빌드하기 위한 명령어들의 집합이다. 각 명령어는 이미지의 한 레이어를 생성하며, 이를 통해 애플리케이션 환경을 단계적으로 구성한다.

  • FROM <base_image>: 베이스 이미지를 지정한다. (예: FROM ubuntu:22.04)
  • COPY <src> <dest>: 호스트의 파일을 이미지로 복사한다.
  • WORKDIR <path>: 작업 디렉토리를 설정한다.
  • RUN <command>: 이미지를 빌드하는 동안 실행될 명령어를 지정한다. (예: 패키지 설치)
  • ENTRYPOINT <command>: 컨테이너가 시작될 때 실행될 기본 명령어를 지정한다.

7. JAR 배포와 이미지 배포 비교: 환경 차이 문제 해결

Docker 이미지를 통한 배포는 전통적인 JAR 파일 배포 방식이 겪었던 “내 컴퓨터에서는 되는데 서버에서는 안 돼요”와 같은 환경 차이 문제를 해결하는 데 큰 도움을 준다.

  • 환경 차이 문제: JAR 파일만 배포할 경우, 서버 환경에 Java 런타임, 특정 라이브러리, OS 설정 등이 제대로 갖춰져 있지 않으면 애플리케이션이 정상적으로 동작하지 않을 수 있다.
  • Java 버전 문제: 개발 환경과 운영 환경의 Java 버전이 다를 경우 호환성 문제가 발생할 수 있다.
  • 실행 방식 포함: Docker 이미지는 애플리케이션 코드뿐만 아니라 런타임(예: OpenJDK), 필요한 라이브러리, 환경 변수, 심지어 애플리케이션 실행 명령어까지 모두 포함한다. 이는 어떤 환경에서든 동일하게 동작하는 “이식성(Portability)”을 제공한다.

8. 자주 하는 오해

“Docker 이미지는 작은 VM이다?”

아니다. Docker 이미지는 VM처럼 OS 전체를 포함하지 않는다. 단지 애플리케이션 실행에 필요한 RootFS와 메타데이터를 담고 있을 뿐이다. VM은 하드웨어 가상화를 통해 Guest OS를 포함하지만, Docker 이미지는 호스트 OS의 커널을 공유한다.

“Ubuntu 이미지면 Ubuntu OS 전체인가?”

아니다. ubuntu Docker 이미지는 Ubuntu 배포판의 RootFS, 즉 /bin, /lib, /usr 등 핵심 파일 시스템만 포함한다. Ubuntu OS의 커널은 포함되어 있지 않으며, 컨테이너는 호스트의 리눅스 커널을 사용한다. 따라서 ubuntu 이미지는 “Ubuntu 사용자 공간(Userland) 환경”을 제공하는 것이지, 완전한 Ubuntu OS를 제공하는 것이 아니다.


마무리 정리

Docker 이미지는 컨테이너 기술의 핵심 요소이며, 그 본질은 “커널 없는 실행 환경 패키지”에 가깝다.

  • Docker 이미지는 읽기 전용의 RootFS와 메타데이터로 구성된 실행 가능한 패키지이다.
  • 커널은 포함하지 않으며, 호스트 OS의 커널을 공유한다.
  • 이미지는 컨테이너의 설계도이며, 컨테이너는 그 설계도에 따라 실행되는 프로세스이다.

이러한 이해를 바탕으로 Docker를 더욱 효과적으로 활용하고, “내 컴퓨터에서는 되는데 서버에서는 안 돼요”와 같은 환경 문제를 해결하는 데 기여할 수 있을 것이다.


References

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.