VPS Docker Linux DevOps 容器 Podman

Docker 跑在 root daemon 上讓你不安?Podman 用 rootless 架構從根本解決這件事

Podman 是無 daemon、預設 rootless 的容器引擎,與 Docker CLI 幾乎完全相容。本文從架構差異、安裝、Quadlet 整合 systemd、Compose 遷移到生產部署,完整解析為什麼 2026 年新專案該優先考慮 Podman。

Docker 改變了軟體部署的方式,但它的架構有一個從第一天就存在的問題:所有容器操作都通過一支以 root 身分執行的常駐 daemon。這支 dockerd 一旦被攻破,攻擊者等於拿到整台主機的最高權限。Docker 後來加了 rootless mode,但那是外掛上去的,不是預設行為。

Podman 從設計階段就走了不同的路。沒有 daemon、預設 rootless、CLI 語法和 Docker 幾乎完全相容。對已經熟悉 Docker 的人來說,遷移成本低到可以忽略。

架構差異:daemon 與 fork-exec 的根本分歧

Docker 的運作模型是 client-server:你下的每一條 docker run 指令都是透過 REST API 送給 dockerd,由 daemon 去呼叫 containerd 和 runc 來建立容器。這代表 daemon 是單點故障——它 crash 了,所有容器的管理介面就斷了。

Podman 用的是 fork-exec 模型。每次執行 podman run,Podman 直接 fork 出 conmon(container monitor)程序來管理容器的生命週期,不需要任何背景 daemon。容器程序是你的 shell 的子程序,用 ps 就能看到完整的程序樹。

這個設計帶來一個附帶好處:systemd 可以直接管理容器。Docker 需要額外的 wrapper script 才能被 systemd 正確追蹤,Podman 天生就跟 systemd 合得來。

安裝與基本使用

在 Ubuntu 24.04 LTS 和 Debian 12 上:

1
sudo apt update && sudo apt install -y podman

RHEL 系列(AlmaLinux、Rocky Linux)預設就有 Podman,不需要額外安裝。

裝完之後,試試看:

1
podman run --rm docker.io/library/alpine echo "hello from podman"

注意 Podman 預設需要完整的 image reference(docker.io/library/alpine 而不只是 alpine)。如果你不想每次都打完整路徑,編輯 /etc/containers/registries.conf

1
unqualified-search-registries = ["docker.io"]

加了這行之後 podman run alpine 就跟 Docker 一樣的行為。

對於已經習慣打 docker 的人,設定一個 alias 就能無痛過渡:

1
echo 'alias docker=podman' >> ~/.bashrc

這不是開玩笑——Podman 的 CLI 介面就是照著 Docker 做的,超過 95% 的指令和參數都完全相同。

Rootless 容器到底改變了什麼

Docker 的 rootless mode 要另外設定,而且有不少限制。Podman 的 rootless 是預設值,不需要任何額外設定。

在 rootless 模式下,容器程序映射到你的使用者 UID namespace 裡。即使容器內部的程序以 root(UID 0)執行,在宿主機上它對應的是一個無特權的 UID。這表示就算容器被攻破、攻擊者拿到容器內的 root,他在宿主機上什麼都做不了。

1
2
3
4
5
6
# 以一般使用者執行
podman run -d --name web -p 8080:80 docker.io/library/nginx

# 檢查宿主機上的程序
ps aux | grep nginx
# 你會看到 nginx 程序跑在你的使用者帳號下,不是 root

有一個實務上要注意的地方:rootless 模式下,bind mount 的檔案權限可能跟你預期的不同。容器內的 root(UID 0)對應到宿主機上的 subuid 範圍,所以直接掛載的目錄可能出現權限被拒。解決方式是在 volume 掛載時加上 :Z 標籤(SELinux 環境)或使用 --userns=keep-id 把容器的 UID 對應回宿主機使用者:

1
podman run -v ./data:/app/data:Z --userns=keep-id myapp

Quadlet:用 systemd 管理容器的正確方式

Podman 4.4 之後引入的 Quadlet 是目前在單機上管理容器最優雅的方式。你寫一個類似 INI 格式的 .container 檔案,systemd 會在 daemon-reload 時自動把它轉成標準的 service unit。

以跑一個 Nginx 容器為例,建立 ~/.config/containers/systemd/web.container

1
2
3
4
5
6
7
8
9
10
[Container]
Image=docker.io/library/nginx:1.27-alpine
PublishPort=8080:80
Volume=./html:/usr/share/nginx/html:ro,Z

[Service]
Restart=always

[Install]
WantedBy=default.target

然後:

1
2
3
systemctl --user daemon-reload
systemctl --user start web
systemctl --user enable web

就這樣。你的 Nginx 容器現在是一個標準的 systemd service,可以用 systemctl statusjournalctl 來查看狀態和日誌,機器重開後自動啟動,crash 後自動重啟。

Quadlet 也支援 .volume.network.pod 檔案類型,可以把完整的多容器架構用純宣告式的方式管理。如果是系統級的服務(需要 root),把檔案放到 /etc/containers/systemd/ 就好。

跟 Docker Compose 比起來,Quadlet 的優勢是跟作業系統的服務管理完全整合。你不需要記住 docker compose up -d 之後還要確認服務有沒有正確啟動,systemd 會處理所有的生命週期管理,包含開機啟動、失敗重試、資源限制和日誌收集。

從 Docker Compose 遷移

已經有一堆 docker-compose.yml 的專案怎麼辦?兩條路可以選。

用 podman-compose(低門檻):

1
2
pip install podman-compose
podman-compose up -d

podman-compose 能直接讀取既有的 docker-compose.yml。大部分簡單到中等複雜度的 Compose 檔案可以直接跑,不需要修改。

用原生 Docker Compose + Podman socket(高相容性):

Podman 可以啟動一個 Docker 相容的 API socket,讓 Docker Compose v2 直接對接:

1
2
3
systemctl --user enable --now podman.socket
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock
docker compose up -d # 這裡用的是原生 Docker Compose,但後端是 Podman

這種方式的相容性更高,因為你用的是正式的 Docker Compose binary,只是底層執行引擎換成了 Podman。複雜的 Compose 功能(build、healthcheck、depends_on condition)都能正常運作。

遷移時最常遇到的三個問題:

  1. Image 名稱:Podman 預設要求完整的 registry 路徑,image: nginx 要改成 image: docker.io/library/nginx(或設定 unqualified-search-registries
  2. Volume 權限:rootless 模式下的 UID 映射可能導致檔案權限問題,加 :Zuserns_mode: keep-id 處理
  3. 特權 port:rootless 模式下無法綁定 1024 以下的 port,需要調整 sysctl net.ipv4.ip_unprivileged_port_start=80 或改用 rootful 模式

什麼場景該用 Podman,什麼場景留在 Docker

建議直接用 Podman 的情境:全新的 Linux 伺服器部署、對安全有嚴格要求的環境(金融、醫療、政府)、RHEL/CentOS Stream 生態系(Podman 是原生工具)、以及跑在資源有限的 VPS 上的單機服務(少一支 daemon 就是少一份記憶體開銷)。

留在 Docker 比較合理的情境:團隊已經重度依賴 Docker Desktop 的 GUI 工作流、CI/CD pipeline 綁定了 Docker-in-Docker(DinD)、或者使用了 Docker Swarm(Podman 沒有對應的 orchestration 功能,不過這個需求通常該往 Kubernetes 走)。

兩者建出來的 image 完全相容——都是 OCI 標準格式。在開發機用 Docker 建 image,在生產伺服器用 Podman 跑,完全沒問題。


在 VPS 上部署容器化服務,底層硬體的穩定性直接影響運行品質。NCSE Network 提供搭載 Intel Gold CPU 與 NVMe SSD 的臺灣本地 VPS,機房位於是方電訊,適合需要低延遲、穩定網路的容器部署場景。更多資訊可到 ncse.tw 了解。

需要穩定的雲端主機?

NCSE Network 提供企業級 VPS,7 天免費試用,臺灣是方電訊機房,99% SLA 保證。

查看 VPS 方案 →