Docker란 무엇인가 — 컨테이너 입문 핵심 개념 정리

“내 컴퓨터에서는 분명히 잘 돌았는데, 서버에 올리니 안 됩니다.” 개발 현장에서 가장 오래되고 흔한 하소연이다. 운영체제 버전이 다르고, 설치된 라이브러리가 다르고, 환경 변수 하나가 빠져 있어서 생기는 문제다. Docker는 바로 이 “환경 차이”를 통째로 봉인해 어디서든 똑같이 실행하게 만드는 도구다. 2013년 처음 공개된 뒤 컨테이너 기술의 사실상 표준이 됐고, 오늘날 클라우드·DevOps를 이야기할 때 빠지지 않는 이름이 됐다. 이 글은 Docker가 정확히 무엇이고, 가상머신과 무엇이 다르며, 입문자가 가장 먼저 잡아야 할 개념이 무엇인지 정리한다.

Docker란 무엇인가

Docker 공식 문서는 Docker를 “애플리케이션을 개발·배포·실행하기 위한 오픈 플랫폼(an open platform for developing, shipping, and running applications)”이라고 정의한다. 핵심은 애플리케이션을 그것이 의존하는 모든 것과 함께 하나의 표준 단위로 묶어, 인프라에서 분리한다는 점이다.

조금 더 일상적인 비유로 보자. 국제 무역에서 화물 컨테이너가 등장하기 전에는 짐의 모양과 크기가 제각각이라 배·기차·트럭마다 싣는 방식을 새로 고민해야 했다. 규격화된 철제 컨테이너가 나오자 안에 무엇이 들었든 항만 크레인은 똑같은 방식으로 옮길 수 있게 됐다. Docker가 소프트웨어에 한 일이 정확히 이것이다. 안에 든 것이 Node.js 앱이든 파이썬 머신러닝 모델이든, 컨테이너로 포장하면 노트북·테스트 서버·클라우드가 전부 동일한 방식으로 실행한다.

그래서 “내 컴퓨터에서는 됐는데” 문제가 구조적으로 사라진다. 코드뿐 아니라 런타임, 시스템 라이브러리, 설정까지 한 이미지 안에 함께 들어가기 때문이다.

컨테이너와 가상머신은 무엇이 다른가

입문자가 가장 헷갈리는 지점이 “컨테이너가 결국 가벼운 가상머신 아니냐”는 오해다. 둘 다 격리된 실행 환경을 제공하지만, 격리하는 계층이 다르다.

가상머신(VM)은 하이퍼바이저 위에서 게스트 운영체제(OS)를 통째로 부팅한다. VM 하나하나가 자기만의 커널을 가진다. 반면 컨테이너는 호스트 OS의 커널을 공유하면서 프로세스 수준에서만 격리된다. AWS는 이 차이를 “Docker는 운영체제를 가상화하고, VM은 하드웨어를 가상화한다”고 요약한다.

이 구조 차이가 그대로 성능 차이로 이어진다.

비교 항목 가상머신(VM) Docker 컨테이너
격리 단위 하드웨어 + 게스트 OS 전체 OS 커널 공유, 프로세스 격리
용량 보통 수 GB~수십 GB 보통 수십 MB 수준
시작 속도 수십 초~수 분(OS 부팅) 1초 미만
자원 효율 OS가 중복되어 무거움 커널 공유로 가벼움
격리 강도 강함(커널 분리) 상대적으로 약함(커널 공유)

정리하면 컨테이너는 더 가볍고 빠른 대신, 격리 강도는 VM보다 약하다. 그래서 실무에서는 둘을 대립이 아니라 보완 관계로 본다. Atlassian 등 여러 기술 문서는 클라우드 환경의 일반적인 구성으로 “VM 위에서 컨테이너를 띄우는” 방식을 든다. VM이 강한 격리와 전용 자원을 제공하고, 그 안에서 Docker가 효율적인 애플리케이션 패키징을 담당하는 식이다.

여기서 독자 입장에서 한 번 던져볼 질문. “그렇다면 우리 서비스는 VM이 필요할까, 컨테이너로 충분할까?” 답은 보안 격리 요구 수준과 멀티테넌시 여부에 따라 갈린다. 외부에서 받은 신뢰할 수 없는 코드를 돌려야 한다면 커널을 공유하는 컨테이너만으로는 부족할 수 있다.

Docker의 핵심 구성요소

Docker를 처음 다룰 때 알아야 할 부품은 생각보다 단순하다. 공식 문서가 설명하는 아키텍처는 크게 세 덩어리로 나뉜다.

  • Docker 데몬(dockerd) — 실제로 일하는 백그라운드 프로세스. 이미지·컨테이너·네트워크·볼륨 같은 객체를 관리하고, API 요청을 받아 처리한다.
  • Docker 클라이언트(docker) — 사용자가 터미널에 입력하는 docker run, docker build 같은 명령. 이 명령이 데몬에 전달된다.
  • 레지스트리(Registry) — 이미지를 저장하고 공유하는 창고. 공개 기본 레지스트리가 바로 Docker Hub다.

그리고 그 위에서 실제로 다루는 두 가지 핵심 개념이 이미지(image)컨테이너(container) 다. 공식 문서의 정의가 명료하다. “이미지는 컨테이너를 만들기 위한 명령이 담긴 읽기 전용 템플릿”이고, “컨테이너는 이미지의 실행 가능한 인스턴스”다.

클래스와 객체에 비유하면 이해가 빠르다. 이미지는 설계도(클래스), 컨테이너는 그 설계도로 찍어낸 실제 실행체(인스턴스)다. 같은 이미지 하나로 컨테이너를 수십 개 동시에 띄울 수 있다.

도커 이미지와 레이어, 그리고 Dockerfile

도커 이미지가 특별한 이유는 레이어(layer) 구조에 있다. 이미지는 한 덩어리가 아니라, 변경 사항이 켜켜이 쌓인 읽기 전용 레이어들의 묶음이다. 베이스 OS 레이어 위에 라이브러리 설치 레이어, 그 위에 애플리케이션 코드 레이어가 얹히는 식이다.

이 구조 덕분에 두 가지 이점이 생긴다. 첫째, 여러 이미지가 공통 레이어를 공유하므로 저장 공간과 전송량이 줄어든다. 둘째, 코드 한 줄만 바뀌면 그 위쪽 레이어만 다시 빌드하면 되므로 빌드가 빠르다.

이 레이어들을 어떻게 쌓을지 적어 두는 설계서가 바로 Dockerfile이다. 텍스트 파일 한 장에 “어떤 베이스 이미지에서 출발해, 무엇을 설치하고, 어떤 명령으로 실행하라”를 순서대로 적는다. 간단한 Node.js 앱의 예시는 다음과 같다.

# 1. 베이스 이미지 지정
FROM node:20-alpine

# 2. 작업 디렉터리 설정
WORKDIR /app

# 3. 의존성 정의 파일 먼저 복사 (레이어 캐시 활용)
COPY package*.json ./
RUN npm install

# 4. 나머지 소스 복사
COPY . .

# 5. 컨테이너가 열어둘 포트
EXPOSE 3000

# 6. 컨테이너 시작 시 실행할 명령
CMD ["node", "server.js"]

이 Dockerfile을 가지고 이미지를 만들고 실행하는 흐름은 명령 두세 줄이면 끝난다.

# 이미지 빌드 (myapp이라는 이름과 태그를 붙임)
docker build -t myapp:1.0 .

# 컨테이너 실행 (호스트 8080 포트를 컨테이너 3000 포트에 연결)
docker run -d -p 8080:3000 myapp:1.0

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

package.json을 소스 코드보다 먼저 복사하는 작은 순서 하나가 빌드 속도를 크게 좌우한다. 소스만 바뀌고 의존성이 그대로일 때, npm install 레이어가 캐시에서 재사용되기 때문이다. 이런 사소해 보이는 패턴이 모여 실무 빌드 시간을 줄인다.

볼륨과 네트워크 — 데이터와 통신 다루기

컨테이너는 기본적으로 일회용(ephemeral) 이다. 컨테이너를 지우면 그 안에서 만든 데이터도 함께 사라진다. 데이터베이스처럼 데이터를 보존해야 하는 경우엔 문제가 된다. 그래서 등장하는 개념이 볼륨(volume) 이다.

볼륨은 컨테이너의 생명주기와 분리된 별도 저장소다. 컨테이너를 삭제하고 다시 만들어도 볼륨에 담긴 데이터는 그대로 남는다. 호스트 디렉터리를 직접 연결하는 바인드 마운트 방식도 있지만, 일반적으로는 Docker가 관리하는 볼륨을 권장한다.

# pgdata라는 볼륨을 컨테이너의 데이터 디렉터리에 연결
docker run -d -v pgdata:/var/lib/postgresql/data postgres:16

네트워크도 마찬가지다. 컨테이너는 기본적으로 격리돼 있어서, 여러 컨테이너가 서로 통신하려면 같은 Docker 네트워크에 묶어 줘야 한다. 같은 네트워크 안에서는 컨테이너 이름을 호스트명처럼 써서 서로를 찾는다. 웹 앱 컨테이너가 db라는 이름의 데이터베이스 컨테이너에 db:5432로 접속하는 식이다.

Docker Compose — 여러 컨테이너를 한 번에

실제 서비스는 웹 서버, 데이터베이스, 캐시 등 여러 컨테이너가 함께 돌아간다. 이것들을 매번 docker run 명령으로 하나씩 띄우고 네트워크로 연결하는 일은 번거롭고 실수가 잦다. Docker Compose는 이 구성을 compose.yaml(또는 docker-compose.yml) 파일 한 장에 선언적으로 적어 두고, 명령 하나로 전체를 띄우게 해 준다.

services:
  web:
    build: .
    ports:
      - "8080:3000"
    depends_on:
      - db
  db:
    image: postgres:16
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: example

volumes:
  pgdata:

이 파일이 있으면 docker compose up -d 한 줄로 웹과 DB가 같은 네트워크에 올라가고, docker compose down 한 줄로 정리된다. 로컬 개발 환경을 팀원 누구나 동일하게 재현할 수 있다는 점에서 Compose는 입문 단계에서 체감 효용이 가장 큰 도구 중 하나다.

2026년 Docker, 그리고 오케스트레이션으로 가는 길

Docker는 여전히 활발히 발전 중이다. Docker 공식 블로그에 따르면 메이저 버전인 Docker Engine v29가 2025년 11월 11일 출시됐고, 2026년 6월 기준 최신 패치는 29.6.0이다. v29의 가장 눈에 띄는 변화는 새 설치 환경의 기본 이미지 저장소가 containerd 기반으로 전환됐다는 점이다. 레거시 graph driver는 deprecated 상태로 밀려났다. 방화벽 규칙도 기존 iptables 대신 nftables를 쓰는 옵션이 실험적으로 추가됐다.

여기서 입문자가 알아야 할 큰 그림이 있다. 컨테이너 한두 개를 노트북에서 띄우는 것과, 수십·수백 개를 여러 서버에 걸쳐 안정적으로 운영하는 것은 전혀 다른 문제다. 컨테이너가 죽으면 자동으로 되살리고, 트래픽에 따라 개수를 늘리고 줄이고, 무중단 배포를 하는 일은 Docker 단독으로는 버겁다. 이 영역을 책임지는 것이 컨테이너 오케스트레이션이고, 그 사실상 표준이 쿠버네티스다.

즉 Docker는 컨테이너를 만들고 실행하는 출발점이고, 규모가 커지면 그 위에 오케스트레이션 계층이 얹힌다. Docker로 기본기를 다진 뒤 다음 단계가 궁금하다면 쿠버네티스 입문: 컨테이너 오케스트레이션 핵심 개념 정리 글에서 클러스터·노드·파드 구조를 이어서 살펴보는 흐름을 권한다.

Docker의 한계와 주의점

장점만 나열하는 글은 신뢰하기 어렵다. Docker에도 분명한 한계가 있다.

첫째, 앞서 말한 격리 강도다. 컨테이너는 호스트 커널을 공유하므로, 커널 수준 취약점이 뚫리면 격리가 무력화될 수 있다. 신뢰할 수 없는 워크로드를 다룰 때는 gVisor, Kata Containers, MicroVM 같은 추가 격리 기술이나 VM 병행을 검토해야 한다.

둘째, 상태가 있는(stateful) 워크로드는 여전히 까다롭다. 컨테이너의 일회용 특성과 데이터 영속성은 본질적으로 충돌하는 면이 있어, 데이터베이스를 컨테이너로 운영할 때는 볼륨·백업 전략을 신중히 설계해야 한다.

셋째, 이미지 보안 관리 부담이다. 공개 레지스트리에서 받은 이미지에 취약한 라이브러리나 악성 코드가 섞여 있을 수 있어, 신뢰할 수 있는 베이스 이미지 선택과 정기적인 취약점 스캔이 필요하다.

이런 한계는 Docker를 쓰지 말라는 이유가 아니라, “어디까지 Docker로 하고 어디서부터 다른 도구를 붙일지” 판단의 기준이 된다.

정리하며

Docker는 애플리케이션과 그 실행 환경을 하나의 컨테이너로 묶어 어디서든 동일하게 실행하게 해 주는 도구다. 가상머신보다 가볍고 빠른 대신 격리는 상대적으로 약하며, 이미지·컨테이너·Dockerfile·볼륨·네트워크·Compose라는 몇 가지 개념만 잡으면 입문 단계는 충분히 넘어선다. 핵심은 명령어 암기가 아니라 “환경을 코드로 고정한다”는 사고방식 자체에 있다.

다음으로 직접 손에 익히고 싶다면, 간단한 웹 앱 하나를 Dockerfile로 이미지화하고 Compose로 데이터베이스와 함께 띄워 보는 것이 가장 빠른 학습 경로다. 그 경험이 쌓이면 자연스럽게 다음 질문이 떠오를 것이다. “이걸 수십 대 서버에 어떻게 펼치지?” 그 답을 찾는 여정이 곧 클라우드 네이티브 인프라의 시작이다.


참고 자료

댓글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다