ใช้ Podman รัน container แบบ rootless บน VPS

ใช้ Podman แทน Docker บน VPS (Rootless Container)

มิถุนายน 2026 · อ่าน 7 นาที

Podman คือ container engine ที่ใช้คำสั่งเข้ากันได้กับ Docker แทบ 100% แต่ต่างกันที่จุดสำคัญ — ไม่มี daemon ที่รันด้วย root ตลอดเวลา และรันแบบ rootless ได้ ทำให้ลด attack surface บน VPS ที่เปิดสู่อินเทอร์เน็ต ถ้า container ถูกเจาะ ผู้โจมตีจะได้แค่สิทธิ์ user ธรรมดา ไม่ใช่ root ทั้งเครื่อง บทความนี้สอนติดตั้งและใช้งานจริงตั้งแต่แทนที่ docker ไปจนถึงรัน container เป็น systemd service

ติดตั้ง Podman

# Ubuntu / Debian
sudo apt update && sudo apt install -y podman

# CentOS / RHEL / Rocky
sudo dnf install -y podman

# ตรวจเวอร์ชัน
podman --version
podman info | grep -i rootless

ทำให้ใช้คำสั่ง docker ได้เลยโดยไม่ต้องแก้สคริปต์เดิม ด้วยการตั้ง alias หรือติดตั้ง package podman-docker:

sudo apt install -y podman-docker   # สร้าง /usr/bin/docker ชี้ไป podman
# หรือ
echo 'alias docker=podman' >> ~/.bashrc && source ~/.bashrc

รัน Container แบบ Rootless

ไม่ต้องใช้ sudo — รันด้วย user ธรรมดาได้เลย Podman จะใช้ user namespace แมป UID ภายใน container กับ subuid ของ host:

# รัน nginx โดยไม่ใช้ root
podman run -d --name web -p 8080:80 docker.io/library/nginx:alpine

# ดู container ที่รันอยู่
podman ps

# ดู subuid/subgid ที่ระบบจัดให้ user
cat /etc/subuid /etc/subgid | grep $USER
หมายเหตุ: rootless ผูก port ต่ำกว่า 1024 ไม่ได้โดยตรง (เช่น 80/443) จึงต้อง map เป็น port สูง เช่น 8080 แล้ววาง reverse proxy ไว้หน้า หรือปรับ net.ipv4.ip_unprivileged_port_start=80 ใน sysctl ถ้าจำเป็น

ใช้ podman-compose แทน docker-compose

# ติดตั้ง podman-compose
sudo apt install -y podman-compose      # หรือ: pip3 install podman-compose

# ใช้ docker-compose.yml ไฟล์เดิมได้เลย
podman-compose up -d
podman-compose ps
podman-compose down

Podman รุ่นใหม่ยังรองรับ podman compose (เรียก external provider) และ Kubernetes YAML ผ่าน podman kube play ทำให้ย้ายไป k8s ในอนาคตได้ลื่นกว่า

รัน Container เป็น systemd Service (Quadlet)

จุดแข็งของ Podman คือ integration กับ systemd — container จะ start หลัง reboot, restart เมื่อ crash และอยู่ใน journald เหมือน service ปกติ วิธีใหม่ที่แนะนำคือ Quadlet:

# ~/.config/containers/systemd/web.container
[Container]
Image=docker.io/library/nginx:alpine
PublishPort=8080:80
Volume=%h/site:/usr/share/nginx/html:ro,Z

[Service]
Restart=always

[Install]
WantedBy=default.target

# โหลดและ start
systemctl --user daemon-reload
systemctl --user start web.service

# ให้รันต่อแม้ logout (lingering)
sudo loginctl enable-linger $USER
Tip: ใช้ enable-linger เสมอสำหรับ rootless service ที่ต้องรันตลอด ไม่งั้น container จะถูกหยุดเมื่อ user logout — เป็นกับดักที่ทำให้คนคิดว่า "Podman ไม่ restart หลัง reboot"

ตรวจสอบว่า Podman ทำงานถูกต้อง

ยืนยันว่า rootless ทำงานจริง container ขึ้น และ systemd คุม service ได้:

# 1. ยืนยันว่ารันแบบ rootless (ต้องเห็น rootless: true)
podman info --format '{{.Host.Security.Rootless}}'

# 2. container ทำงานและ health ok
podman ps --format 'table {{.Names}} {{.Status}} {{.Ports}}'

# 3. ทดสอบ service ตอบจริง
curl -I http://localhost:8080

# 4. ตรวจ systemd user service
systemctl --user status web.service

# 5. ดู log ผ่าน journald
journalctl --user -u web.service --since "10 min ago"
Tip: ถ้า podman ps ว่างหลัง reboot ทั้งที่ตั้ง service แล้ว ให้เช็ก loginctl show-user $USER | grep Linger ต้องเป็น Linger=yes — นี่คือสาเหตุอันดับหนึ่งของ rootless container ที่ "หาย" หลังรีบูต

แก้ปัญหาที่พบบ่อย

Error: "short-name did not resolve to an alias"

Podman ไม่เดา registry ให้เหมือน Docker ต้องระบุ registry เต็มหรือใช้ชื่อเต็ม:

# แทนที่จะใช้ nginx ให้ใส่เต็ม
podman pull docker.io/library/nginx:alpine
# หรือแก้ /etc/containers/registries.conf ให้มี unqualified-search-registries = ["docker.io"]

Error: "rootlessport cannot expose privileged port"

rootless ผูก port < 1024 ไม่ได้ ใช้ port สูงแล้ว proxy หน้า หรือเปิด unprivileged port:

echo 'net.ipv4.ip_unprivileged_port_start=80' | sudo tee /etc/sysctl.d/99-podman.conf
sudo sysctl --system

Container หยุดทำงานหลัง logout

ยังไม่ได้เปิด lingering ให้ user — สั่ง sudo loginctl enable-linger $USER แล้ว container จะรันต่อแม้ปิด SSH

Volume permission denied (SELinux)

บน RHEL/Rocky ที่เปิด SELinux ต้องเติม :Z ท้าย volume mount เพื่อให้ relabel ไฟล์:

podman run -v /data:/app/data:Z ...

คำถามที่พบบ่อย

Podman ใช้แทน Docker ได้ทุกกรณีไหม?

เกือบทั้งหมด คำสั่ง run/build/pull/ps/exec เหมือนกัน และอ่าน Dockerfile/compose เดิมได้ ข้อต่างหลักคือไม่มี daemon และ rootless จึงต้องปรับเรื่อง privileged port กับ socket ที่บางเครื่องมือ (เช่น Traefik) คาดหวัง docker.sock — ซึ่ง Podman มี socket จำลองให้เปิดได้

Podman เร็วกว่าหรือช้ากว่า Docker?

ประสิทธิภาพ runtime ใกล้เคียงกันมากเพราะใช้ runc/crun เหมือนกัน rootless อาจมี overhead เรื่อง network (slirp4netns/pasta) เล็กน้อย แต่ไม่กระทบงานทั่วไป และประหยัด RAM เพราะไม่มี daemon ค้างตลอด

ย้ายจาก Docker มา Podman ต้องทำอะไรบ้าง?

ส่วนใหญ่แค่เปลี่ยนคำสั่ง ติดตั้ง podman-docker เพื่อ map คำสั่ง docker และย้าย container ที่เคยรันด้วย --restart ไปเป็น Quadlet/systemd แทน image ทั้งหมดดึงจาก registry เดิมได้โดยตรง