Docker vs Podman — 같은 컨테이너, 다른 철학 (daemonless·rootless·Pod)

부제: Docker는 개발자 경험을, Podman은 리눅스 표준·보안·쿠버네티스 친화성을 앞세운다 — 같은 컨테이너를 다르게 바라보는 두 도구


앞선 A1편에서 "도커가 아니어도 컨테이너는 존재한다 — containerd, Podman도 같은 일을 한다"고 한 줄로 지나갔습니다. 그 문장을 쓰고 나서, 정작 저는 Podman이 Docker와 뭐가 다른지를 제대로 설명하지 못한다는 걸 깨달았습니다. 그래서 따로 찾아 정리했습니다.

결론부터 말하면, Podman은 흔히 "Docker의 대체재"로 소개되지만 실은 컨테이너를 바라보는 철학 자체가 조금 다릅니다.

  • Docker = 개발자 경험(DX)과 생태계를 최우선으로 둔 컨테이너 도구.
  • Podman = 리눅스 표준·보안·쿠버네티스 친화성을 최우선으로 둔 컨테이너 도구.

이미지 포맷(OCI)도 같고 CLI 사용감도 거의 같아서 "그놈이 그놈" 같지만, 그 아래에서 누가 컨테이너를 실행하느냐가 다릅니다. 이 한 축이 나머지 차이를 거의 다 만들어 냅니다.


한눈에 보는 비교

항목 Docker Podman
실행 방식 dockerd(데몬) 필요 데몬 없음(daemonless)
Rootless 지원(추가 설정) 기본 지원
기본 보안 모델 root 중심 일반 사용자 실행 권장
systemd 연동 제한적 매우 우수
쿠버네티스 연동 가능 매우 자연스러움(Pod 지원)
Pod 개념 없음 있음
Compose Docker Compose podman compose
OCI 표준 / 이미지 호환 지원 / OCI 지원 / OCI
CLI docker podman(거의 동일)
생태계 가장 큼 Red Hat 중심

표만 보면 차이가 흩어져 보이지만, 실제로는 세 개의 축 — daemonless, rootless, Pod — 으로 묶입니다.


그 전에 — containerd는 왜 이 비교에 안 끼나

여기서 이름 하나를 짚고 가야 합니다. Docker·Podman과 자주 같이 등장하는 containerd입니다. 결론부터 말하면, 셋은 같은 줄에 서 있지 않습니다. Docker와 Podman은 사람이 직접 명령을 내리는 상위 도구이고, containerd는 그 아래에서 실제로 컨테이너를 띄우고 관리하는 런타임 엔진입니다.

기술 한 줄 정의 서 있는 층
Docker 개발자가 가장 많이 쓰는 컨테이너 플랫폼(빌드·실행·배포를 한 도구로 감쌈) 상위 플랫폼
Podman Docker와 거의 같은 CLI를 주면서 데몬이 없는(daemonless) 컨테이너 엔진 상위 엔진
containerd 실제 컨테이너를 실행·관리하는 런타임 엔진(상위 도구가 내부에서 호출) 하위 런타임

그림으로 겹쳐 보면 이렇습니다.

[사람이 쓰는 도구]   docker CLI          podman CLI
                        │                    │
                        ▼                    ▼
[관리 계층]          dockerd              conmon
                        │                    │
                        ▼                    ▼
[런타임 관리 엔진]   containerd            (없음)
                        │                    │
                        ▼                    ▼
[OCI 런타임]           runc              crun / runc

핵심은 두 가지입니다.

  • Docker는 containerd를 품고 있습니다. docker run 을 누르면 dockerd가 그 아래 containerd를 호출해서 컨테이너를 띄웁니다. 그러니 "Docker vs containerd"는 애초에 성립하지 않는 비교입니다 — 하나가 다른 하나를 부품으로 씁니다.
  • Podman은 containerd를 거치지 않습니다. 데몬도 containerd도 없이 conmon + crun/runc 로 직접 띄웁니다. Podman에게 containerd는 "안 쓰는 다른 길"입니다.

그래서 실제로 층이 겹쳐 경쟁하는 건 Docker ↔ Podman(사람이 쓰는 상위 도구)과, 그보다 아래에서 containerd ↔ CRI-O(런타임 엔진)입니다. Docker와 containerd는 위아래로 붙어 있는 사이지 라이벌이 아닙니다.

쿠버네티스가 "도커를 버렸다"의 실체: 쿠버네티스는 예전에 dockershim이라는 어댑터로 dockerd를 거쳐 컨테이너를 띄웠는데, 이 어댑터를 걷어내고 containerd를 CRI로 직접 호출하도록 바꿨습니다. 즉 버린 건 상위 도구 Docker이고, 그 안에 들어 있던 런타임 containerd는 그대로 남아 일합니다. 이미지(OCI)는 손댈 필요가 없었습니다.

이 층 구분을 손에 쥐고 나면, 아래 세 축의 비교는 자연스럽게 "상위 도구 Docker와 Podman이 어떻게 다른가" 로 좁혀집니다.


축 1. 데몬(dockerd)이 없다

Docker는 CLI가 명령을 내리면, 그것을 항상 떠 있는 데몬 dockerd가 받아 실행합니다.

docker CLI
    │
    ▼
 dockerd          ← 항상 떠 있는 데몬(root)
    │
    ▼
containerd
    │
    ▼
  runc            ← 실제로 컨테이너를 띄우는 OCI 런타임

Podman은 이 데몬을 걷어냈습니다. CLI가 컨테이너를 직접 띄웁니다.

podman CLI
    │
    ▼
 conmon           ← 컨테이너 하나를 감시하는 가벼운 프로세스
    │
    ▼
crun / runc       ← 실제로 컨테이너를 띄우는 OCI 런타임

dockerd가 사라지면서 따라오는 것들:

  • 메모리 상주 비용이 없습니다. 컨테이너를 안 쓰는 동안 떠 있는 데몬이 없습니다.
  • 단일 장애점이 줍니다. 데몬 하나가 죽어서 그 아래 컨테이너 전체가 흔들리는 구도가 아닙니다. 컨테이너는 각자 자기 conmon 아래에서 돕니다.
  • 부모 프로세스가 명확합니다. bash → podman → container로 프로세스 계보가 이어져서, 리눅스의 프로세스 트리 관점과 결이 맞습니다.

축 2. rootless가 기본

Docker는 오랫동안 sudo docker run 형태가 사실상 표준이었습니다(현재는 rootless 모드를 지원하지만 별도 설정이 필요합니다). Podman은 그냥 podman run 이면 됩니다.

호스트 사용자 UID 1000
        │  (user namespace 매핑)
        ▼
   컨테이너 UID 0(root처럼 보임)
        │
        ▼
  실제로는 여전히 UID 1000의 권한

컨테이너 안에서는 root처럼 보여도, 호스트에서는 여전히 일반 사용자 권한입니다. 그래서:

  • root 권한을 최소화할 수 있고,
  • 컨테이너 탈출(escape) 공격이 성공해도 피해 범위가 일반 사용자 선에서 막힙니다.
  • SELinux/AppArmor 같은 리눅스 보안 모듈과의 궁합도 좋습니다. 특히 Red Hat 계열에서는 SELinux + Podman 조합이 사실상 표준으로 쓰입니다.

축 3. Pod — 쿠버네티스와 같은 언어

Docker의 실행 단위는 컨테이너 하나입니다. Podman은 이름 그대로 Pod라는 단위를 지원합니다.

Pod
├── nginx
├── redis
└── sidecar

하나의 Pod 안에 든 컨테이너들은 네트워크(localhost)·IPC를 공유합니다. 이 구조가 바로 쿠버네티스의 Pod와 같습니다. 그래서 Podman은 쿠버네티스와 언어가 거의 겹칩니다.

podman kube generate   →   deployment.yaml 생성
podman kube play       →   YAML을 그대로 로컬에서 실행

로컬에서 Podman으로 만든 구성을 그대로 YAML로 뽑아 클러스터에 올리거나, 반대로 쿠버네티스 매니페스트를 로컬에서 돌려 볼 수 있습니다. 쿠버네티스를 배우기 위한 로컬 환경으로도 자연스럽습니다. (쿠버네티스의 Pod·Service 개념은 쿠버네티스 개념 시리즈에서 따로 다뤘습니다.)

여기에 systemd 궁합이 하나 더 붙습니다. podman generate systemd 로 컨테이너를 .service 유닛으로 뽑아내면(최신 Podman은 Quadlet 방식을 권장), systemctl enable 한 줄로 컨테이너를 시스템 서비스처럼 관리할 수 있습니다. 리눅스 서버에서는 꽤 큰 장점입니다.


그래도 Docker가 나은 부분

방향이 다를 뿐, Docker가 여전히 앞서는 지점도 분명합니다.

  • 압도적인 생태계. 문서·예제·Stack Overflow·GitHub의 거의 모든 자료가 Docker 기준입니다. 막혔을 때 검색으로 풀리는 속도가 다릅니다.
  • Docker Desktop. Windows·macOS 사용자에게는 설치와 GUI 관리가 편합니다.
  • Compose 자료. docker compose 관련 예제가 압도적으로 많습니다.
  • CI/CD 기본값. GitHub Actions·GitLab·Jenkins 예제가 대부분 Docker입니다.
  • 클라우드 도입 사례. AWS·Azure·GCP 문서의 예제도 Docker 기반이 훨씬 많습니다.

즉 "새로 배우는 비용"과 "막혔을 때 빠져나오는 비용"은 아직 Docker 쪽이 쌉니다.


언제 Podman을 고르면 좋을까

정리해 보면, 아래에 해당할수록 Podman이 결에 맞습니다.

  • 리눅스 서버에서 상주 데몬 없이 컨테이너를 돌리고 싶을 때
  • rootless로 보안을 한 겹 더 올리고 싶을 때
  • K3s·OpenShift 등 쿠버네티스를 함께 쓸 계획일 때
  • systemd 기반으로 컨테이너를 서비스처럼 관리하고 싶을 때
  • Red Hat·Fedora·RHEL 계열 OS를 쓸 때

반대로 개발 초기 속도, 팀 온보딩, 풍부한 예제가 더 급하다면 Docker를 그대로 쓰는 게 합리적입니다. 둘 다 OCI 이미지를 공유하니, 이미지를 새로 만들 필요 없이 나중에 갈아탈 수도 있습니다.


곁다리 — Dockerd와 Linkerd는 무슨 관계일까?

찾다 보니 이름이 비슷해서 문득 궁금해졌습니다. dockerd와 Linkerd는 관계가 있을까요? 결론은 이름만 닮았을 뿐 완전히 다른 계층(layer)의 기술이었습니다.

  • dockerd = 컨테이너를 실행하는 프로그램(도커 데몬).
  • Linkerd = 이미 실행 중인 서비스들 사이의 네트워크를 관리하는 프로그램(서비스 메시).

한쪽은 컨테이너를 띄우는 아래층, 다른 쪽은 그렇게 뜬 서비스들이 서로 통신하는 위층을 다룹니다. Linkerd가 정확히 어디에 서 있는지는 관측 스택을 한 줄씩 정의한 글에서 서비스 메시로 따로 짚어 두었습니다.


정리

  • Docker와 Podman의 갈림길은 "누가 컨테이너를 실행하는가" 한 줄입니다.
  • Docker = dockerd 데몬이 실행. 개발자 경험·생태계가 강점.
  • Podman = 데몬 없이 CLI가 직접 실행. daemonless·rootless·Pod 세 축으로 리눅스 표준·보안·쿠버네티스 친화성이 강점.
  • containerd는 이 둘의 경쟁자가 아니라 아래층입니다. Docker는 그것을 품고 호출하고, Podman은 거치지 않으며, 쿠버네티스는 그것을 직접 부릅니다.
  • 이미지(OCI)는 셋이 모두 공유하므로, 철학의 차이일 뿐 이사 비용은 크지 않습니다.
  • 그리고 dockerd와 Linkerd는 이름만 닮은 남남입니다.

참고

답글 남기기

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