Quadlet: Chạy container Podman bằng systemd
(mo8it.com)- Vì Podman không có daemon, cần có một chủ thể thực thi để khởi chạy container ổn định sau khi máy chủ boot; Quadlet giải quyết việc này theo kiểu file service của systemd
- Cách
podman generate systemdtrước đây phải xử lý riêng việc tạo container và tạo file service, và mỗi khi thay đổi file sinh ra lại phát sinh gánh nặng chỉnh sửa thủ công - Quadlet đặt chung cấu hình
[Container],[Service],[Install]trong file.containerở~/.config/containers/systemd, giúp quản lý tùy chọn Podman và hành vi systemd tại một nơi - Với rootless Podman, để tự động khởi động khi boot cần
WantedBy=default.targetvà bật linger;multi-user.targetkhông được định nghĩa trong chế độ user - Khi tận dụng
AutoUpdate=registry, dependency của systemd, gom nhóm file theo thư mục, và cả công cụ chuyển đổipodlet, Quadlet rất phù hợp để vận hành Podman rootless·daemonless
Vì sao cần Quadlet
- Quadlet là cách cho phép chạy container Podman như một service systemd
- Có thể chạy container ở nền
- Có thể tự động khởi động container sau khi máy chủ reboot
- Bản thân cách chạy container Podman dưới systemd không phải là mới
- Trước đây dùng lệnh
podman generate systemd - Lệnh này hiện hiển thị cảnh báo ngừng dùng khuyến nghị migrate sang Quadlet
- Trước đây dùng lệnh
- Vì Podman có kiến trúc daemonless, cần một chủ thể thực thi để khởi động container mà không cần daemon
Bất tiện của cách podman generate systemd cũ
- Cách cũ trước tiên phải tạo container bằng
podman create- Container ví dụ dùng image
docker.io/library/postgres:16 - Bao gồm
-p 5432:5432, mount volume, biến môi trườngPOSTGRES_PASSWORD, và labelio.containers.autoupdate=registry
- Container ví dụ dùng image
- Sau đó chạy
podman generate systemd test-db -fn --newđể tạo filecontainer-test-db.service - File service được tạo sẽ đặt trong
~/.config/systemd/user, rồi kích hoạt và khởi động bằng lệnh sausystemctl --user enable --now container-test-db
- Luồng này khiến bạn phải lặp lại việc tạo container, tạo file service, di chuyển file khi cần, và kích hoạt service
- Khi lệnh tạo container trở nên dài, về sau để chạy lại cần quản lý riêng một shell script
- Nếu muốn tùy biến file service systemd đã sinh ra, mỗi lần đều phải sửa thủ công lại
Cấu trúc file Quadlet
- Với cách Quadlet, tạo thư mục
~/.config/containers/systemdvà đặt file.containerbên trong - File
test-db.containerví dụ bao gồm các thành phần sau[Container]Image=docker.io/library/postgres:16AutoUpdate=registryPublishPort=5432:5432Volume=%h/volumes/test-db:/var/lib/postgresql/data:ZEnvironment=POSTGRES_PASSWORD=CHANGE_ME
[Service]Restart=always
[Install]WantedBy=default.target
- File
.containerlà file service systemd thông thường, nhưng có thêm section đặc biệt[Container] - Nhiều tùy chọn trong
[Container]tương ứng với các tùy chọn dòng lệnh dùng trongpodman createImage: image và tag sẽ dùngAutoUpdate=registry: tương ứng với--label "io.containers.autoupdate=registry"PublishPort: tương ứng với-pVolume: tương ứng với-vEnvironment: tương ứng với-e
- Với thư mục home của user, cần dùng định danh systemd
%hthay vì~ Restart=alwaystrong[Service]khiến container luôn được khởi động lại trừ khi bị dừng thủ côngWantedBy=default.targettrong[Install]khiến container tự động khởi động khi boot
Cấu hình systemd cần thiết với rootless Podman
- Với container rootless, cần dùng
default.targetthay vìmulti-user.targetmulti-user.targetkhông được định nghĩa trong chế độ user của systemd- Có thể kiểm tra bằng
systemctl --user status multi-user.target - Ở chế độ system, có thể kiểm tra bằng
systemctl status multi-user.target
- Vì container chạy dưới dạng systemd user service, để container khởi động ngay cả khi user chưa đăng nhập, cần bật linger
loginctl enable-linger
- Nếu cần tự động khởi động sau khi máy chủ reboot, bắt buộc phải bật linger
- Để systemd phát hiện file service mới, chạy lệnh sau
systemctl --user daemon-reload
- Có thể khởi động container và kiểm tra trạng thái từ cả systemd lẫn Podman
systemctl --user start test-dbsystemctl --user status test-dbpodman ps
- Tên container mặc định có dạng thêm
systemd-vào trước tên file service- Tên container mặc định của
test-db.containerlàsystemd-test-db - Đây là quy tắc đặt tên để tránh xung đột
- Có thể chỉ định trực tiếp bằng tùy chọn
ContainerNametrong section[Container]
- Tên container mặc định của
Lợi ích vận hành của Quadlet
- Quadlet cho phép quản lý cấu hình service container bằng một file duy nhất
- Không cần quản lý riêng script tạo file service và file service đã sinh ra như cách cũ
- Có thể dùng các tùy chọn có trong section
[Unit]và[Service]của systemd- Ví dụ có thể chỉ định lệnh chạy trước khi khởi động container bằng
StartExecPre - Giảm bớt quy trình sửa thủ công file đã sinh ra về sau
- Ví dụ có thể chỉ định lệnh chạy trước khi khởi động container bằng
- Thay vì viết và debug shell script, có thể vận hành container xoay quanh file cấu hình
- Dễ biểu diễn dependency giữa các container theo kiểu systemd
Biểu diễn dependency giữa các container
- Nếu container ứng dụng phụ thuộc vào container cơ sở dữ liệu, có thể chỉ định quan hệ bằng section
[Unit]của systemd - Container OxiTraffic là ví dụ phụ thuộc vào container
test-db- Đặt
Requires=test-db.servicetrong[Unit]để ứng dụng chỉ khởi động khi cơ sở dữ liệu được khởi động - Đặt
After=test-db.serviceđể hai container không khởi động song song
- Đặt
- Khi tham chiếu, dùng tên service chứ không phải tên file
.containertest-db.container: tên filetest-db.service: tên servicesystemd-test-db: tên container mặc định
- Để ứng dụng giao tiếp với cơ sở dữ liệu, cả hai container đều cần thêm tùy chọn
Networktrong section[Container], nhưng bài này không bàn về networking
Nhiều file và gom nhóm
- Quadlet có thể được cấu hình theo cách mỗi container có một file
.containerriêng - So với cách đưa toàn bộ ứng dụng multi-container vào một file Docker Compose, các file riêng theo từng container có thể giảm gánh nặng nhận thức
- Nếu file Docker Compose dài hàng trăm dòng và chứa hàng chục container, việc bảo trì có thể trở nên khó khăn
- File Docker Compose của Mailcow là ví dụ về một file Compose lớn
- Docker Compose cũng hỗ trợ chức năng chia thành nhiều file
- Quadlet có thể đặt unit file trong các thư mục bên trong
~/.config/containers/systemd- Trong ví dụ có thể tạo thư mục
oxitrafficrồi đặt chung file của ứng dụng và cơ sở dữ liệu
- Trong ví dụ có thể tạo thư mục
Cập nhật image
- Khi đặt
AutoUpdate=registry, có thể kiểm tra cập nhật image bằngpodman auto-update - Nếu registry có image mới tương thích với tag đang dùng, Podman sẽ pull image và khởi động lại container
- Trong Docker, có thể cần công cụ như Watchtower cho mục đích này, nhưng Podman cung cấp sẵn chức năng đó
- Các tag như
latestcó thể nguy hiểm- Trong OxiTraffic,
latestcó thể bao gồm breaking change của phiên bản tiếp theo - Nếu dùng
latestvới PostgreSQL, có thể bị nâng lên major version mới, mà major upgrade của PostgreSQL luôn cần migration thủ công
- Trong OxiTraffic,
- Trong môi trường vận hành, cần dùng tag không dẫn đến breaking change
- Cũng có thể chạy thủ công
podman auto-updatevài ngày một lần để xem những gì đã được cập nhật, sau đó kiểm tra container có hoạt động bình thường hay không
podman-compose và công cụ migration
podman-composelà một Python script chạy file Compose bằng Podman- Các lý do khiến nó khó được xem là giải pháp thay thế Docker Compose dài hạn như sau
- Đây là tầng dịch giữa đặc tả Compose với Podman·systemd, và không cho phép dùng toàn bộ chức năng của systemd
- Dự án Podman chính thức được viết bằng ngôn ngữ biên dịch như Rust hoặc Go
- Commit cuối cùng cách đây 5 tháng, nên không được bảo trì tích cực
- Quadlet phù hợp hơn với thiết kế rootless·daemonless của Podman
- Nếu muốn thử Quadlet từ file Compose, có thể dùng podlet
- Đây là công cụ Rust có thể tạo file Quadlet từ lệnh Podman hoặc file Docker Compose
Tài liệu đọc thêm
- Để hiểu sâu hơn về Quadlet, man page
podman-systemd.unitrất hữu ích - Quadlet không chỉ quản lý container mà còn quản lý cả pod, network, volume
- Nếu chưa quen viết systemd unit file, có thể xem man page
systemd.unitvàsystemd.service - Có thể xem một góc nhìn khác và ví dụ thứ hai trong bài viết tương tự của blog.while-true-do
1 bình luận
Các ý kiến trên Hacker News
Quadlet gần như là thứ tốt nhất xuất phát từ Podman, và tôi rất khuyến nghị cho những ai tò mò về Podman hoặc muốn chuyển sang workload dựa trên container
Bạn có thể gắn container vào và quản lý chúng như các dịch vụ hệ thống thông thường, không cần học thêm một lớp orchestration riêng để cho chúng chạy cùng nhau hay phải phụ thuộc vào tài nguyên không phải container
Chỉ cần viết systemd unit như cách bạn vẫn làm, còn tự động cập nhật hoặc khởi động lại/thông báo khi dịch vụ lỗi là phần cộng thêm
Cách cố làm điều tương tự với Docker thường là né Docker daemon bằng một lệnh
runkhổng lồ, rồi hay để lại các dịch vụ và container “ma”; Quadlet thì gọn gàng hơn nhiều, cấu hình cũng nằm cùng các vị trí unit của systemd như/etc/systemd/,.config/systemd,/usr/local/lib/systemd, nên dễ sao lưuTuy nhiên, nó không phải câu trả lời thay cho docker-compose trong phát triển cục bộ, và đội Podman cũng có vẻ không quá quan tâm đến mảng đó
Container người dùng phù hợp cho hạ tầng kiểm thử cục bộ chạy dài hạn như cơ sở dữ liệu nền, nhưng quá phiền cho vòng lặp thông thường biên dịch →
docker compose up→ kiểm thử →docker compose downCâu trả lời thực tế là
.kubeQuadlet (Kubernetes play), hoặc dùngdocker composevới Podman socketTôi thích đến mức đã dành thời gian rảnh suốt vài tháng để làm một công cụ GitOps quản lý Quadlet, và nó cho cảm giác như cách đúng đắn để quản lý các máy chủ được container hóa
Điều quan trọng là
[0]không phải podman-compose. Bài viết cũng chỉ ra rằng podman-compose không tốt lắm và thiếu phát triển. Podman triển khai phần lớn đặc tả compose, nên trong hầu hết tình huống bạn có thể dùngdocker composeCó lẽ những người từng thử khi RH mới bắt đầu thúc đẩy Podman đã rời bỏ vì sự lưng chừng của Podman 3 và trải nghiệm tệ với podman-compose
Sau khi đổi nhiều flag, nâng phiên bản, rồi đi theo luồng mà chính podlet cũng khuyên chuyển sang công cụ khác, mọi thứ thành một cái hang thỏ không hồi kết
Cuối cùng systemd của tôi chỉ đơn giản chạy
podman compose upTôi tò mò lợi ích của Quadlet là gì so với việc cứ để compose tự làm việc của nó
Nhân tiện, Podman chạy dưới user của tôi và hoàn toàn không có daemon
docker-composeđộc lậppodman composeGần đây tôi phát hiện Quadlet và đã dựng toàn bộ homelab dựa trên atomic OS cùng Quadlet rootless; rất khuyến nghị
Cũng có thể dùng kích hoạt socket của systemd, chẳng hạn tạo socket http/https của systemd và tự động kích hoạt Traefik giống như
ssh.socketvàpodman.socketlần lượt kích hoạtsshd.service,podman.serviceTrong cấu hình rootless, đây gần như là cách duy nhất để giữ nguyên IP gốc, nên gần như là cứu tinh. Podman/Docker rootless thường không dễ cho phép giữ IP gốc mà không có nhược điểm lớn
https://github.com/savely-krasovsky/homelab
Quadlet là một lựa chọn thay thế tốt cho mục đích docker compose kiểu “chạy tất cả các container phụ thuộc lẫn nhau trong một môi trường gần giống production”
Nhưng tôi mong phần phát triển — một mục đích khác của docker compose — sẽ tốt hơn
docker compose có thể khởi chạy cùng lúc cơ sở dữ liệu, Redis, OpenSearch, các dependency khác, proxy nginx, container phát triển mount
.:/applàm volume; rồi cũng có thể dọn chúng cùng nhau và đưadocker-compose.ymlvào repositoryQuadlet lại bảo đặt tất cả file trong
~/.config/containers/systemd, nên nó không còn bị cô lập theo dự án nữa, cũng không tiện để check-in và chia sẻ với các developer khác. Hơn nữa, họ cũng phải dùng PodmanPhần lớn mọi người vẫn dùng Docker, và các môi trường phát triển được host như Codespaces cũng cung cấp Docker
Vì vậy tôi dùng docker compose bằng file YAML đã được check-in. Do tôi dùng Podman nên phải tự thêm
:Zvào mọi volume, nhưng Docker thông thường lại không xử lý được phần đóSẽ tốt nếu có một lựa chọn thay thế docker compose cho phát triển, nhưng Quadlet có vẻ không phù hợp lắm
podman-compose --in-pod=1 systemd -a create-unit, bạn có thể tạo servicepodman-compose@, rồi sau đó đăng ký filecompose.ymlcùng với$namebằngpodman-compose systemd -a registerKhi đó bạn có thể quản lý pod dựa trên file compose qua
podman-compose@$name.service, và nó cũng hoạt động hoàn toàn rootlesssystemd-runcho phép chạy service systemd tạm thời dựa trên một lệnh bất kỳNếu cần, nó còn tạo ra một unit tạm thời gọn gàng, tuân theo các quy tắc phạm vi của systemd, bao gồm cả timer
[1] https://www.freedesktop.org/software/systemd/man/systemd-run...
Nó có định dạng tương tự Kubernetes, kèm thêm một chút tiện ích như build container
Đặt file kube play ở thư mục gốc dự án rồi chạy
podman kube play project.yaml --buildthì pod, volume, v.v. sẽ được chạy cùng nhauFile Quadlet hữu ích ở giai đoạn triển khai. Nếu muốn đưa dự án lên VPS, bạn có thể dùng Kube Quadlet[2] cùng với
project.yamlđã có[1] https://docs.podman.io/en/latest/markdown/podman-kube-play.1...
[2] https://docs.podman.io/en/latest/markdown/podman-systemd.uni...
docker-compose.ymlcho phát triển nên tôi hiểu nỗi đau nàyNhìn chung nó hoạt động rất tốt, nhưng trên OSX đôi khi hành xử kỳ lạ vì cái VM trung gian chết tiệt đó
Thỉnh thoảng tôi kiểm tra khả năng tương thích với Podman, nhưng giờ đã chấp nhận rằng triết lý rootless khác nhau quá nhiều nên không thể tương thích hoàn toàn
Dù vậy công cụ này rất tuyệt cho production. Tôi đang chạy vài dự án cá nhân trên node bare-metal bằng các service systemd tự viết, hiện tại là containerd ở chế độ user
Khi có thời gian có lẽ tôi sẽ thử chuyển sang nó
Bài viết này nói Podman-Compose “không được bảo trì tích cực” và chỉ ra commit cuối cùng là 5 tháng trước, rồi ngay sau đó lại đề xuất Podlet như một phương án thay thế dù commit cuối cùng của nó cũng là 5 tháng trước, khá thú vị
Podlet có thể hữu ích, nhưng không hỗ trợ nhiều tính năng của Docker Compose và cũng không phải lúc nào cũng chuyển đổi sạch sẽ
Đặc biệt, nó không hỗ trợ tính năng xếp chồng nhiều tệp YAML như
-f docker-compose.yml -f docker-compose.override.ymlCó vẻ compose CLI điều khiển engine qua socket, và Podman với Docker engine có API gần như giống nhau
Tôi đang dùng cách này vì podman-compose không hoạt động như mong đợi
Docker-compose thường được cài như plugin của docker client, nhưng tôi dùng nó như một ứng dụng độc lập để chạy với Podman
Ngoài ra, với thiết lập tích hợp, tôi thích dùng docker
contextshơn biến môi trườngDOCKER_HOSTNếu chỉ Quadlet thuần túy chưa đủ mạnh, Quadlet[3] và Podman thông thường[4] cũng hỗ trợ chạy các manifest Kubernetes ở mức giới hạn
Tôi vẫn chưa rõ Podman xử lý tùy chọn
restarttrong tệp compose như thế nào, vì Podman không có daemon giám sátNgược lại, tôi biết tùy chọn
healthcheckphụ thuộc vào systemd timerKhi dùng Podman trên Gentoo, một bản phân phối không dùng systemd, healthcheck tự động không hoạt động, nhưng nếu chạy healthcheck thủ công thì phần thiết lập còn lại vẫn chạy đến cuối
[1] https://github.com/docker/compose
[2] https://docs.podman.io/en/latest/markdown/podman-system-serv...
[3] https://docs.podman.io/en/latest/markdown/podman-systemd.uni...
[4] https://docs.podman.io/en/latest/markdown/podman-kube-play.1...
Podlet là công cụ phụ trợ, và về lâu dài làm việc với Quadlet sẽ tốt hơn
5 tháng không có nghĩa là không được bảo trì; phải khoảng 2 năm mới có thể nói vậy
Dù thế, nó vẫn làm tăng lo ngại. Tuy nhiên, 5 tháng tuyệt đối không phải bằng chứng cho thấy đang được bảo trì
Có nhiều lý do khiến một repository không được bảo trì vẫn được cập nhật, và chỉ có tính năng lưu trữ GitHub gần đây khá tệ mới ngăn được điều đó
Vài năm trước, khi làm lại cấu hình self-hosting từ đầu, tôi muốn thử thứ khác nên đã chọn openSUSE MicroOS, và cuối cùng chạy các container Podman dưới systemd/Quadlet; hiện tôi khá hài lòng với cấu hình này
Container được tự động cập nhật bằng công cụ tích hợp của Podman, còn việc xem log và giám sát thì xử lý bằng các công cụ systemd quen thuộc
Khi cần thay đổi gì đó, ngay cả khi quên vị trí tệp cấu hình, cũng dễ tìm, dễ đọc và dễ chỉnh sửa
Rootless và daemonless cũng rất tốt
Tôi đã thử vài thứ trong quá trình đó, nhưng podman compose cho cảm giác thô cứng; tôi mừng vì nó bị deprecated, và rõ ràng Quadlet mới là hướng đi
Cần lưu ý là có đường cong học tập và tài liệu ít hơn Docker
Nếu mục đích là bật/tắt stack nhiều dịch vụ trong phát triển cục bộ, tôi vẫn sẽ chọn Docker và docker compose
Mất một thời gian để chỉnh cấu hình cho đúng, nhưng tôi rất ấn tượng vì gần như không cần bảo trì. Đến giờ thì hoàn toàn chưa cần
Ai muốn làm tương tự có thể tham khảo cấu hình của tôi
https://github.com/jeppester/coreos-nextcloud
Tôi đang từ từ chuyển mọi node sang MicroOS, và ở công ty cũng đang thúc đẩy dùng MicroOS hoặc thứ tương tự
Sự kết hợp giữa tự động rollback của OS nền với cấu hình container dạng khai báo và tự động cập nhật cho cảm giác rất ăn khớp
Định dạng này rõ ràng hơn
podman generate systemdhay Kubernetes YAML, và tích hợp systemd cũng rất tuyệtĐiều khó chịu là upstream của Podman không cung cấp repository cho Debian/Ubuntu
Trên Debian stable, tôi bị kẹt ở 4.3.1 và bỏ lỡ nhiều tính năng mới, nên cuối cùng đã quyết định quay lại Docker compose
Cách vòng tránh được đề xuất là tự compile Podman hoặc dùng
debian/testingTôi thật sự hy vọng cách tiếp cận mới này sẽ giúp mọi người chuyển từ Docker sang Podman
Docker-Compose là lý do khiến nhiều người do dự khi chuyển đổi, và tôi cũng từng như vậy
Phải thừa nhận rằng trước Quadlet, Podman chưa có câu trả lời đúng nghĩa
Nếu bạn từng ngần ngại rời Docker vì Docker-Compose, thì Podman kết hợp với Quadlet là một lựa chọn thay thế cạnh tranh hơn nhiều
Có lẽ bạn sẽ không nhớ Docker nhiều như tưởng tượng, và còn có thêm lợi ích bảo mật nhờ chạy container rootless
Cách nhét mọi thứ vào
~/.config/quadlet/systemdlà không ổnĐiều này là bắt buộc cho phát triển và kiểm thử, còn hiện tại Quadlet thuần túy là một giải pháp triển khai
Tôi rất thích Quadlet vì nó cho phép dùng container như các dịch vụ hệ thống thông thường
Tuy nhiên, trải nghiệm người dùng của container rootless không thật sự khớp với cách khái niệm hóa này
Thông thường, dịch vụ hệ thống chạy dưới một system user trong phiên systemd của hệ thống, nhưng dịch vụ của container rootless lại nằm trong phiên systemd của người dùng thuộc system user đó
Sẽ thật tốt nếu có thể chạy Quadlet rootless bên trong phiên hệ thống
user-lingervà chạy rootless thông qua systemd của người dùng khôngTôi vẫn luôn làm như vậy
Ngoài ra, sẽ rất tốt nếu có thể chạy Quadlet rootless với tùy chọn
DynamicUser=DynamicUser=từng là một cách tuyệt vời để giới hạn quyền của dịch vụ hệ thống, nhưng hiện không thật sự hợp với PodmanThật thú vị khi thấy Quadlet trên trang nhất Hacker News. Tôi nghĩ nó chưa được chú ý đúng mức
Ygal và Valentin của dự án từng gửi một bài viết khách về cách chạy client đường hầm inlets. Nó tương tự Ngrok/Cloudflared, nhưng là cách tự host mà không có giới hạn kiểu SaaS
https://inlets.dev/blog/2023/10/03/client-quadlet.html
Họ dùng
[kube]thay vì[container]nên có thể mang theo YAML Kubernetes chuẩn, khiến tính di động khá tốtVới những ai quan tâm, tôi đã tạo một template Ansible cho thấy việc triển khai Quadlet gần đây dễ đến mức nào
GH: https://github.com/Mati365/hetzner-podman-bunjs-deploy
example.site.orgthay vìsite.example.orghttps://en.wikipedia.org/wiki/Example.com