Vấn đề khi quản lý nhiều container rời rạc
Khi mới dùng Podman, mình hay chạy từng container một: database riêng, backend riêng, frontend riêng. Cách này ổn khi test nhanh, nhưng chỉ sau vài ngày đã thấy ngay mấy vấn đề đau đầu: container nào phải start trước? Database chưa lên mà backend đã khởi động thì crash ngay. Muốn stop hết một lúc phải stop từng cái. Network giữa các container phải tự cấu hình bridge riêng và nhớ tên DNS internal.
Sau khi đọc tài liệu Kubernetes, mình mới hiểu tại sao họ dùng khái niệm Pod — nhóm các container liên quan thành một đơn vị duy nhất. Podman hỗ trợ Pod ngay từ đầu, không cần plugin hay daemon thêm. Đây cũng là lý do nhiều người chuyển từ Docker sang Podman khi bắt đầu học Kubernetes trên môi trường local.
Tại sao Pod giải quyết được vấn đề này?
Trong kiến trúc Kubernetes, Pod là đơn vị nhỏ nhất để deploy — không phải container đơn lẻ. Các container trong cùng một Pod chia sẻ với nhau:
- Cùng network namespace — cùng IP, cùng loopback interface
- Giao tiếp qua
localhostmà không cần expose port ra ngoài - Start và stop cùng nhau như một khối thống nhất
- Một
infra container(container tạm dừng) giữ namespace — y hệt Kubernetes
Docker Compose ghép container qua virtual network và DNS nội bộ — cách đó hoạt động ổn, nhưng là abstraction riêng của Compose, không phải model của Kubernetes. Podman Pod dùng đúng cơ chế mà K8s dùng, nên khi bạn đọc tài liệu Kubernetes sau này, phần network và Pod lifecycle sẽ không còn là khái niệm lạ nữa.
Kiểm tra Podman đã sẵn sàng chưa
Mình dùng Fedora làm máy development chính đã 2 năm và khá hài lòng với tốc độ cập nhật package — Podman thường có bản mới nhất ngay khi vừa release upstream. Kiểm tra version hiện tại:
podman --version
podman info | grep -E "version|rootless"
Nếu chưa cài hoặc cần update:
sudo dnf install -y podman
Bài này áp dụng cho Podman 4.x trở lên. Fedora 38+ thường đã có sẵn Podman 4.x hoặc 5.x trong repo mặc định.
Ví dụ thực tế: WordPress + MariaDB trong một Pod
Lý thuyết vậy đủ rồi. Mình dùng luôn ví dụ cụ thể: chạy WordPress và MariaDB trong cùng một Pod. Use case này đủ đơn giản để setup trong vài phút, nhưng cũng đủ để thấy rõ Pod giải quyết được vấn đề gì so với container đơn lẻ.
Bước 1 — Tạo Pod và khai báo port
podman pod create \
--name wordpress-pod \
--publish 8080:80
Lưu ý: Port mapping phải khai báo lúc tạo Pod, không phải lúc tạo container. Vì các container trong Pod chia sẻ network namespace với Pod, chỉ Pod mới là điểm expose port ra ngoài — container riêng lẻ không expose được.
Bước 2 — Thêm MariaDB vào Pod
podman run -d \
--pod wordpress-pod \
--name mariadb \
-e MYSQL_ROOT_PASSWORD=rootpass \
-e MYSQL_DATABASE=wordpress \
-e MYSQL_USER=wpuser \
-e MYSQL_PASSWORD=wppass \
-v mariadb-data:/var/lib/mysql \
docker.io/library/mariadb:10.11
Bước 3 — Thêm WordPress vào Pod
podman run -d \
--pod wordpress-pod \
--name wordpress \
-e WORDPRESS_DB_HOST=127.0.0.1:3306 \
-e WORDPRESS_DB_USER=wpuser \
-e WORDPRESS_DB_PASSWORD=wppass \
-e WORDPRESS_DB_NAME=wordpress \
-v wordpress-data:/var/www/html \
docker.io/library/wordpress:6.5
Để ý WORDPRESS_DB_HOST=127.0.0.1 — vì WordPress và MariaDB cùng Pod, chúng giao tiếp qua localhost hoàn toàn tự nhiên, không cần service discovery hay DNS internal như khi dùng Docker network riêng biệt.
Bước 4 — Kiểm tra và quản lý Pod
# Xem danh sách Pod
podman pod ps
# Xem container kèm Pod
podman ps --pod
# Xem logs từng container
podman logs wordpress
podman logs mariadb
Mở browser vào http://localhost:8080 — màn hình setup WordPress hiện ra là thành công. Bây giờ thử quản lý Pod như một khối duy nhất:
# Stop toàn bộ Pod
podman pod stop wordpress-pod
# Start lại
podman pod start wordpress-pod
# Restart
podman pod restart wordpress-pod
# Xóa Pod và tất cả container bên trong
podman pod rm -f wordpress-pod
Đây là điểm mình thích nhất: một lệnh duy nhất control toàn bộ stack, không cần nhớ tên từng container hay thứ tự stop.
Tự động hóa với podman generate systemd
Chạy Pod thủ công ổn khi test, nhưng khi cần service tự restart sau reboot thì phải dùng systemd. podman generate systemd tạo unit file sẵn cho bạn — không cần viết tay.
Tạo systemd unit files từ Pod hiện tại
# Đứng ở thư mục muốn lưu unit files
mkdir -p ~/.config/systemd/user/
cd ~/.config/systemd/user/
# Generate unit files
podman generate systemd \
--name \
--files \
--new \
wordpress-pod
Giải thích các flag:
--name: dùng tên container/pod thay vì ID (dễ đọc hơn trong log)--files: ghi ra file thay vì print ra stdout--new: mỗi lần start sẽpodman runlại từ đầu thay vì attach vào container cũ — quan trọng để cập nhật image mới
Lệnh này tạo ra 3 file:
pod-wordpress-pod.service— quản lý Pod và orchestrate các containercontainer-mariadb.service— chạy sau khi Pod đã sẵn sàngcontainer-wordpress.service— chạy sau mariadb
Kích hoạt service rootless (chạy dưới user thường)
# Reload systemd để nhận unit files mới
systemctl --user daemon-reload
# Enable service tự start
systemctl --user enable pod-wordpress-pod.service
# Start ngay
systemctl --user start pod-wordpress-pod.service
# Kiểm tra status
systemctl --user status pod-wordpress-pod.service
Cho phép service chạy dù chưa login (Linger)
Mặc định, user systemd service chỉ chạy khi bạn đang đăng nhập. Để Pod tự start ngay sau boot mà không cần SSH vào trước:
sudo loginctl enable-linger $USER
# Kiểm tra
loginctl show-user $USER | grep Linger
Sau lệnh này, Pod sẽ hoạt động như một system service thật sự nhưng vẫn chạy dưới quyền user thường — bảo mật hơn nhiều so với chạy root.
Cách tốt nhất: Rootless Pod + Linger + Volume persistent
Sau nhiều lần thử nghiệm, đây là workflow mình dùng ổn định nhất cho project development trên Fedora:
- Tạo named volumes trước để data persist kể cả khi Pod bị xóa và tạo lại
- Generate systemd với
--new— đảm bảo container được recreate từ image mới nhất mỗi lần restart - Bật linger — không phụ thuộc vào session đăng nhập
- Rootless hoàn toàn — không cần
sudocho bất kỳ lệnh podman nào
Ví dụ khi có phiên bản WordPress mới cần update:
# Pull image mới
podman pull docker.io/library/wordpress:6.5
# Restart — với --new, systemd sẽ recreate container từ image mới tự động
systemctl --user restart pod-wordpress-pod.service
Lưu ý nếu bạn dùng Fedora 40+ và Podman 5.x
Từ Podman 4.4, lệnh podman generate systemd đã bị đánh dấu deprecated — trên Fedora 40+ với Podman 5.x, warning này xuất hiện rõ hơn. Thay thế chính thức là Quadlet: bạn viết file .container hoặc .pod, rồi podman-system-generator tự convert sang systemd unit. Quadlet ít verbose hơn, dễ version control hơn, và là cách Podman officially recommend về lâu dài.
Tuy nhiên, podman generate systemd vẫn hoạt động tốt và là cách nhanh nhất để hiểu cơ chế bên dưới trước khi chuyển sang Quadlet. Nắm được generate systemd trước sẽ giúp bạn đọc file Quadlet dễ hơn nhiều — về bản chất logic tương tự nhau.
Kết
Ban đầu mình dùng Pod chỉ để giải quyết một bài toán nhỏ: stop tất cả container cùng lúc. Nhưng lợi ích thực sự nằm ở chỗ khác — giao tiếp qua localhost không cần cấu hình gì thêm, lifecycle tự đồng bộ, và podman generate systemd xử lý luôn phần auto-restart sau reboot. Chạy rootless, không cần sudo, không cần daemon. Trên Fedora, đây là workflow container gọn và bảo mật nhất mình dùng đến giờ.
