- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 들어가며 — 명령어는 같은데 철학이 다르다
- 내부 동작 — 데몬 vs fork-exec
- Rootless — 기본값의 차이
- 설정 파일 — 어디에 무엇이 있나
- GPU — CDI가 정답이다
- Compose — compose.yaml을 그대로 쓸 수 있는가?
- 전환 함정 모음 — 미리 알면 30분, 모르면 반나절
- 버전과 커뮤니티 — 누가 만들고 어디서 논의되나
- 마치며
- 참고 자료
들어가며 — 명령어는 같은데 철학이 다르다
Podman의 첫인상은 "docker를 podman으로 바꿔 치면 되는 도구"입니다. 실제로 alias docker=podman으로 대부분의 명령이 그대로 동작하고, 공식적으로도 Docker CLI 호환을 목표로 합니다. 하지만 그 표면 아래의 아키텍처는 정반대에 가깝습니다 — 그리고 전환에서 마주치는 모든 차이(설정 파일 위치, GPU 설정, compose, 권한 문제)는 이 아키텍처 차이에서 흘러나옵니다.
이 글은 그 차이를 뿌리부터 정리합니다. 참고로 이 글의 명령어는 Podman 5.x / Docker Engine 27+ 기준입니다.
내부 동작 — 데몬 vs fork-exec
Docker의 구조는 클라이언트-서버입니다. docker run을 치면 CLI는 REST 요청을 만들어 dockerd 데몬에 보내고, 데몬이 containerd에, containerd가 runc에 위임해 컨테이너를 만듭니다. 모든 컨테이너의 부모는 결국 데몬입니다.
Docker: docker CLI ──REST──▶ dockerd ──▶ containerd ──▶ runc ──▶ 컨테이너
Podman: podman CLI ──fork/exec──▶ conmon ──▶ crun(runc) ──▶ 컨테이너
Podman에는 데몬이 없습니다. podman run은 평범한 프로세스처럼 fork-exec으로 컨테이너를 직접 만듭니다. 컨테이너마다 작은 감시 프로세스인 conmon이 붙어 stdio와 exit code를 관리하고, 실제 생성은 OCI 런타임 crun(C로 작성, runc보다 가볍고 빠름)이 수행합니다. 이 구조의 함의:
- 단일 장애점이 없습니다. dockerd가 죽으면(또는 업그레이드하면) 모든 컨테이너 관리가 멈추지만, Podman은 애초에 중앙 프로세스가 없습니다.
- 루트 데몬 소켓이라는 공격면이 없습니다.
/var/run/docker.sock은 사실상 루트 권한 그 자체라서 이를 노리는 공격이 많았습니다. Podman은 그 소켓이 존재하지 않습니다(호환용 소켓은 원할 때만, 사용자 권한으로 켭니다). - systemd와 자연스럽게 결합합니다. 컨테이너가 평범한 자식 프로세스이므로 systemd 유닛으로 직접 관리할 수 있습니다. 최신 Podman의 권장 방식은 Quadlet —
.container파일을 쓰면 systemd 서비스가 생성됩니다(podman generate systemd는 구식이 됐습니다).
Rootless — 기본값의 차이
두 엔진 모두 rootless 모드를 지원하지만 무게중심이 다릅니다. Docker는 rootful이 기본이고 rootless가 옵트인, Podman은 rootless가 기본 경험입니다(Fedora/RHEL에서는 설치 직후 일반 사용자로 바로 씁니다).
rootless의 원리는 user namespace입니다. 컨테이너 안의 root(UID 0)는 밖에서는 내 계정의 UID로, 컨테이너 안의 다른 UID들은 /etc/subuid·/etc/subgid에 할당된 보조 UID 대역으로 매핑됩니다. 컨테이너가 탈옥해도 손에 쥐는 것은 일반 사용자 권한뿐입니다.
전환 시 알아야 할 rootless의 제약:
- 1024 미만 포트 바인딩 불가(기본값) —
sysctl net.ipv4.ip_unprivileged_port_start를 낮추거나 높은 포트를 쓰세요. - 네트워킹은 유저스페이스 스택(pasta/slirp4netns) 경유 — 대부분의 워크로드에선 충분하지만, 초고성능 네트워킹이 필요하면 rootful을 고려합니다.
- 저장 위치가 다릅니다 — 아래 설정 절 참조.
docker system df감각으로 디스크를 찾다가 당황하는 지점입니다. - 시작 오버헤드가 약간 있지만 장기 실행 서비스에서는 무의미한 수준입니다.
설정 파일 — 어디에 무엇이 있나
Docker의 설정이 데몬 중심(daemon.json)이라면, Podman은 라이브러리 중심의 분산 설정입니다. 시스템 전역은 /etc/containers/, 사용자별은 ~/.config/containers/가 우선합니다.
Docker Podman
────────────────────────────── ─────────────────────────────────────────
/etc/docker/daemon.json /etc/containers/containers.conf (엔진·런타임 옵션)
~/.config/containers/containers.conf
(레지스트리 미러 등도 daemon.json) /etc/containers/registries.conf (레지스트리·미러·차단)
/etc/containers/storage.conf (스토리지 드라이버·경로)
/etc/containers/policy.json (이미지 서명 정책)
~/.docker/config.json (인증) ~/.config/containers/auth.json (레지스트리 인증)
이미지·컨테이너 저장 위치
/var/lib/docker rootful: /var/lib/containers/storage
rootless: ~/.local/share/containers/storage
전환 시 가장 자주 손대는 것 두 가지: registries.conf에 unqualified 이미지 검색 레지스트리를 지정하는 것(Docker는 nginx를 자동으로 docker.io로 해석하지만 Podman은 기본적으로 어느 레지스트리인지 묻거나 설정을 따릅니다 — unqualified-search-registries = ["docker.io"]를 넣으면 Docker와 동일해집니다), 그리고 사내 미러/인증을 registries.conf + auth.json으로 옮기는 것입니다.
GPU — CDI가 정답이다
NVIDIA GPU를 Podman에서 쓰는 표준 경로는 CDI(Container Device Interface) 입니다. CDI는 "이 장치를 컨테이너에 넣으려면 어떤 디바이스 노드·라이브러리·환경변수가 필요한가"를 기술하는 벤더 중립 스펙으로, Docker의 --gpus 같은 런타임 훅 방식보다 투명하고 이식성이 높습니다(쿠버네티스의 GPU Operator도 내부적으로 CDI를 씁니다).
# 1) nvidia-container-toolkit 설치 후 CDI 스펙 생성
sudo nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml
# 2) 생성된 장치 이름 확인
nvidia-ctk cdi list
# nvidia.com/gpu=0, nvidia.com/gpu=all, (MIG면) nvidia.com/gpu=0:0 ...
# 3) 컨테이너에서 GPU 사용
podman run --rm --device nvidia.com/gpu=all \
nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi
- Docker의
docker run --gpus all에 대응하는 것이--device nvidia.com/gpu=all입니다(최신 Podman은--gpus도 호환 플래그로 받아주지만 CDI 표기가 정식입니다). - rootless에서도 GPU가 됩니다. GPU 드라이버는 커널 공간에서 동작하므로 컨테이너의 권한 수준과 성능은 무관합니다. 시스템 전역
/etc/cdi/nvidia.yaml을 읽을 수 있으면 그대로 쓰고, 안 되면 사용자 공간에 스펙을 생성해 그 디렉터리를 Podman에 지정하면 됩니다. - 드라이버 업데이트 후 GPU가 안 잡히면 십중팔구 CDI 스펙 재생성(
nvidia-ctk cdi generate)을 잊은 것입니다.
Compose — compose.yaml을 그대로 쓸 수 있는가?
결론부터: 대부분 그대로 쓸 수 있고, 방법이 두 가지입니다.
방법 1 — Docker Compose 바이너리를 Podman 소켓에 연결(권장). Podman은 Docker API 호환 소켓을 제공할 수 있습니다. 이 소켓을 켜면 표준 docker compose가 백엔드만 Podman인 채로 그대로 동작합니다 — compose.yaml 재작성이 필요 없습니다.
# 사용자 소켓 활성화 (rootless)
systemctl --user enable --now podman.socket
# docker compose가 Podman 소켓을 보도록 지정
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock
docker compose up -d # 백엔드는 Podman
Go로 구현된 정식 Compose 스펙 구현체를 그대로 쓰므로 호환성이 가장 높습니다. podman compose 명령 자체도 외부 컴포즈 프로바이더(설치되어 있으면 docker-compose)를 호출하는 래퍼입니다.
방법 2 — podman-compose. 파이썬으로 재구현된 별도 프로젝트입니다. 데몬/소켓 없이 podman 명령을 직접 호출하는 순수 구현이라는 장점이 있지만, Compose 스펙의 구석(일부 네트워크 옵션, profiles, 고급 depends_on 조건 등)에서 정식 구현과 미묘한 차이가 날 수 있습니다. 간단한 스택에는 충분하고, 복잡한 compose 파일이라면 방법 1이 안전합니다.
전환 시 compose 관련 주의점:
restart: always는 데몬이 없는 Podman에서는 "부팅 시 자동 시작"을 의미하지 않습니다 — 부팅 자동화는 Quadlet/systemd로 옮기는 것이 Podman식 정답입니다.- 프로덕션 지향이라면 compose 대신
podman kube play(쿠버네티스 YAML을 직접 실행)도 고려하세요. 로컬과 쿠버네티스의 매니페스트를 통일할 수 있습니다.
전환 함정 모음 — 미리 알면 30분, 모르면 반나절
- SELinux 볼륨 라벨: Fedora/RHEL에서 볼륨 마운트가 Permission denied라면 십중팔구 SELinux입니다.
-v ./data:/data:Z(전용) 또는:z(공유) 라벨을 붙이세요. Ubuntu에서 넘어온 compose 파일이 가장 자주 걸리는 함정입니다. - unqualified 이미지 이름: 위 설정 절의
unqualified-search-registries를 지정하지 않으면podman pull nginx가 Docker와 다르게 동작합니다. CI 스크립트라면 아예docker.io/library/nginx처럼 전체 경로를 쓰는 것이 가장 견고합니다. - rootless 저장 공간: 이미지가 홈 디렉터리(
~/.local/share/containers)에 쌓입니다. 홈이 작은 서버라면storage.conf의graphroot를 옮기세요. - Docker 소켓에 의존하는 도구들(Testcontainers, 일부 CI): 방법 1의 Podman 소켓 +
DOCKER_HOST로 대부분 해결됩니다. podman-docker패키지:docker명령을 podman으로 연결해 주는 심 패키지입니다. 스크립트 호환에 유용하지만, 팀원에게 "이 서버의 docker는 사실 podman"임을 반드시 공지하세요.- 점진 전환 가능: 두 엔진은 스토리지가 분리되어 있어 한 머신에 공존할 수 있습니다. 서비스 단위로 하나씩 옮기면 됩니다.
버전과 커뮤니티 — 누가 만들고 어디서 논의되나
버전 감각(2026년 기준): Podman은 5.x 세대로, 4.x에서 5.0으로 넘어오며 네트워킹 기본값이 pasta로 바뀌고 CDI 지원이 성숙했습니다. RHEL 9/10에 깊이 통합되어 있고 Fedora는 여러 릴리스째 Podman이 기본 컨테이너 도구입니다. Docker Engine은 27+ 세대이며 여전히 가장 큰 생태계와 문서량을 가집니다.
거버넌스와 커뮤니티:
- Docker — Docker, Inc.가 주도하는 상용 제품 + 오픈소스(moby/moby)의 이중 구조입니다. Docker Desktop은 일정 규모 이상 기업에서 유료 구독이 필요합니다(엔진 자체는 오픈소스). 방대한 튜토리얼·Stack Overflow 축적이 최대 자산입니다.
- Podman — Red Hat이 주도하는 containers GitHub 조직의 일원으로, Buildah(이미지 빌드)·Skopeo(이미지 검사/복사)와 한 가족을 이룹니다. 전부 Apache-2.0 오픈소스이고 Podman Desktop도 무료입니다. 논의는 GitHub(containers/podman)와 Podman 메일링리스트, 매트릭스 채널에서 활발하며, RHEL 계열 엔터프라이즈 환경에서의 채택이 특히 강합니다.
어느 쪽을 쓸까의 실용적 기준: 팀이 RHEL/Fedora 계열이거나, rootless 보안이 요구사항이거나, systemd 기반 운영을 선호한다면 Podman이 자연스럽습니다. Docker Desktop 의존 도구가 많거나 생태계 문서량이 중요하다면 Docker가 여전히 무난합니다. 그리고 둘은 같은 OCI 표준 위에 있으므로, 이미지는 어느 쪽에서 빌드해도 어느 쪽에서든 돌아갑니다 — 표준이 있다는 것의 축복입니다.
마치며
Docker에서 Podman으로의 전환은 명령어 교체가 아니라 운영 모델의 교체입니다 — 데몬에서 fork-exec으로, rootful에서 rootless로, daemon.json에서 containers.conf 가족으로, --gpus에서 CDI로, compose 데몬 의존에서 소켓 호환 또는 systemd/Quadlet으로. 다행히 OCI 표준 덕에 이미지와 compose.yaml 같은 산출물은 거의 그대로 넘어가고, 함정은 위에 정리한 몇 가지(SELinux 라벨, unqualified 이미지, 저장 경로)로 수렴합니다. 컨테이너 기초를 손으로 다지고 싶다면 이 사이트의 컨테이너 실습실과 리눅스 터미널도 활용해 보세요.