Chúng tôi đã theo dõi chủ đề sử dụng systemd trong container từ lâu. Trở lại năm 2014, kỹ sư bảo mật Daniel Walsh của chúng tôi đã viết một bài báo
Trong bài viết này, chúng tôi sẽ chỉ ra những gì đã thay đổi theo thời gian và cách Podman có thể giúp chúng tôi trong vấn đề này.
Có nhiều lý do để chạy systemd bên trong một container, chẳng hạn như:
- Container đa dịch vụ – nhiều người muốn kéo các ứng dụng đa dịch vụ của họ ra khỏi máy ảo và chạy chúng trong các thùng chứa. Tất nhiên, sẽ tốt hơn nếu chia các ứng dụng đó thành microservice, nhưng không phải ai cũng biết cách thực hiện việc này hoặc đơn giản là không có thời gian. Do đó, việc chạy các ứng dụng như dịch vụ do systemd khởi chạy từ các tệp đơn vị là hoàn toàn hợp lý.
- Tệp đơn vị hệ thống – Hầu hết các ứng dụng chạy bên trong container đều được xây dựng từ mã chạy trước đó trên máy ảo hoặc vật lý. Các ứng dụng này có một tệp đơn vị được viết cho các ứng dụng này và hiểu cách khởi chạy chúng. Vì vậy, tốt hơn hết bạn nên bắt đầu dịch vụ bằng các phương pháp được hỗ trợ thay vì hack dịch vụ init của riêng bạn.
- Systemd là một người quản lý quy trình. Nó quản lý các dịch vụ (tắt, khởi động lại dịch vụ hoặc tiêu diệt các tiến trình zombie) tốt hơn bất kỳ công cụ nào khác.
Điều đó nói lên rằng, có nhiều lý do để không chạy systemd trong vùng chứa. Cái chính là systemd/journald kiểm soát đầu ra của vùng chứa và các công cụ như
Sự xuất hiện của Podman
Chúng tôi vui mừng thông báo rằng tình hình cuối cùng đã tiến triển. Nhóm chịu trách nhiệm chạy container tại Red Hat đã quyết định phát triển
Nhiều người làm điều đó.
Podman của tôi và tôi không hề phản đối các container dựa trên systemd. Xét cho cùng, Systemd là hệ thống con init Linux được sử dụng phổ biến nhất và việc không cho phép nó hoạt động bình thường trong các thùng chứa có nghĩa là bỏ qua việc hàng nghìn người đã quen với việc chạy các thùng chứa.
Podman biết phải làm gì để systemd hoạt động bình thường trong vùng chứa. Nó cần những thứ như gắn tmpfs trên/run và/tmp. Cô ấy thích kích hoạt môi trường "được chứa" và mong muốn có quyền ghi vào phần của mình trong thư mục cgroup và vào thư mục /var/log/journald.
Khi bạn khởi động một vùng chứa trong đó lệnh đầu tiên là init hoặc systemd, Podman sẽ tự động định cấu hình tmpfs và Cgroups để đảm bảo systemd khởi động mà không gặp sự cố. Để chặn chế độ tự động khởi chạy này, hãy sử dụng tùy chọn --systemd=false. Xin lưu ý rằng Podman chỉ sử dụng chế độ systemd khi thấy cần chạy lệnh systemd hoặc init.
Đây là một đoạn trích từ hướng dẫn:
người đàn ông podman chạy
...–systemd=true|false
Chạy một container ở chế độ systemd. Được bật theo mặc định.
Nếu bạn chạy lệnh systemd hoặc init bên trong vùng chứa, Podman sẽ định cấu hình các điểm gắn kết tmpfs trong các thư mục sau:
/run, /run/lock, /tmp, /sys/fs/cgroup/systemd, /var/lib/journal
Ngoài ra, tín hiệu dừng mặc định sẽ là SIGRTMIN+3.
Tất cả điều này cho phép systemd chạy trong một thùng chứa kín mà không cần bất kỳ sửa đổi nào.
LƯU Ý: systemd cố gắng ghi vào hệ thống tập tin cgroup. Tuy nhiên, SELinux ngăn các container thực hiện việc này theo mặc định. Để bật ghi, hãy bật tham số boolean container_manage_cgroup:
setsebool -P container_manage_cgroup đúng
Bây giờ hãy xem Dockerfile trông như thế nào khi chạy systemd trong vùng chứa bằng Podman:
# cat Dockerfile
FROM fedora
RUN dnf -y install httpd; dnf clean all; systemctl enable httpd
EXPOSE 80
CMD [ "/sbin/init" ]
Đó là tất cả.
Bây giờ chúng ta lắp ráp container:
# podman build -t systemd .
Chúng tôi yêu cầu SELinux cho phép systemd sửa đổi cấu hình Cgroups:
# setsebool -P container_manage_cgroup true
Nhân tiện, nhiều người quên bước này. May mắn thay, việc này chỉ cần thực hiện một lần và cài đặt sẽ được lưu sau khi khởi động lại hệ thống.
Bây giờ chúng ta chỉ cần khởi động container:
# podman run -ti -p 80:80 systemd
systemd 239 running in system mode. (+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN2 -IDN +PCRE2 default-hierarchy=hybrid)
Detected virtualization container-other.
Detected architecture x86-64.
Welcome to Fedora 29 (Container Image)!
Set hostname to <1b51b684bc99>.
Failed to install release agent, ignoring: Read-only file system
File /usr/lib/systemd/system/systemd-journald.service:26 configures an IP firewall (IPAddressDeny=any), but the local system does not support BPF/cgroup based firewalling.
Proceeding WITHOUT firewalling in effect! (This warning is only shown for the first loaded unit using IP firewalling.)
[ OK ] Listening on initctl Compatibility Named Pipe.
[ OK ] Listening on Journal Socket (/dev/log).
[ OK ] Started Forward Password Requests to Wall Directory Watch.
[ OK ] Started Dispatch Password Requests to Console Directory Watch.
[ OK ] Reached target Slices.
…
[ OK ] Started The Apache HTTP Server.
Thế là xong, dịch vụ đã hoạt động:
$ curl localhost
<html xml_lang="en" lang="en">
…
</html>
LƯU Ý: Đừng thử điều này trên Docker! Ở đó, bạn vẫn cần phải nhảy với tambourine để phóng những loại thùng chứa này qua daemon. (Các trường và gói bổ sung sẽ được yêu cầu để làm cho tất cả những điều này hoạt động trơn tru trong Docker hoặc nó sẽ cần được chạy trong một vùng chứa đặc quyền. Để biết chi tiết, hãy xem
Một vài điều thú vị nữa về Podman và systemd
Podman hoạt động tốt hơn Docker trong các tệp đơn vị systemd
Nếu cần khởi động các thùng chứa khi hệ thống khởi động, thì bạn chỉ cần chèn các lệnh Podman thích hợp vào tệp đơn vị systemd, lệnh này sẽ khởi động dịch vụ và giám sát nó. Podman sử dụng mô hình fork-exec tiêu chuẩn. Nói cách khác, các tiến trình container là con của tiến trình Podman, vì vậy systemd có thể dễ dàng giám sát chúng.
Docker sử dụng mô hình client-server và các lệnh Docker CLI cũng có thể được đặt trực tiếp trong một tệp đơn vị. Tuy nhiên, khi máy khách Docker kết nối với daemon Docker, nó (máy khách) sẽ trở thành một quy trình khác xử lý stdin và stdout. Đổi lại, systemd không biết về kết nối giữa máy khách Docker và vùng chứa chạy dưới sự kiểm soát của daemon Docker và do đó, trong mô hình này, về cơ bản, systemd không thể giám sát dịch vụ.
Kích hoạt systemd qua ổ cắm
Podman xử lý kích hoạt qua ổ cắm một cách chính xác. Vì Podman sử dụng mô hình fork-exec nên nó có thể chuyển tiếp socket tới các tiến trình vùng chứa con của nó. Docker không thể làm điều này vì nó sử dụng mô hình client-server.
Dịch vụ varlink mà Podman sử dụng để liên lạc với máy khách từ xa đến vùng chứa thực sự được kích hoạt thông qua ổ cắm. Gói buồng lái-podman, được viết bằng Node.js và là một phần của dự án buồng lái, cho phép mọi người tương tác với các vùng chứa Podman thông qua giao diện web. Trình nền web chạy Cockpit-podman sẽ gửi tin nhắn đến ổ cắm varlink mà systemd lắng nghe. Systemd sau đó kích hoạt chương trình Podman để nhận tin nhắn và bắt đầu quản lý vùng chứa. Kích hoạt systemd qua ổ cắm sẽ loại bỏ nhu cầu về trình nền chạy liên tục khi triển khai API từ xa.
Ngoài ra, chúng tôi đang phát triển một ứng dụng khách Podman khác có tên là podman-remote, ứng dụng này triển khai cùng một Podman CLI nhưng gọi varlink để chạy các vùng chứa. Podman-remote có thể chạy trên các phiên SSH, cho phép bạn tương tác an toàn với các vùng chứa trên các máy khác nhau. Theo thời gian, chúng tôi dự định kích hoạt podman-remote để hỗ trợ MacOS và Windows cùng với Linux, để các nhà phát triển trên các nền tảng đó có thể chạy máy ảo Linux với Podman varlink đang chạy và có trải nghiệm đầy đủ về các container đang chạy trên máy cục bộ.
SD_NOTIFY
Systemd cho phép bạn trì hoãn việc khởi chạy các dịch vụ phụ trợ cho đến khi dịch vụ được đóng gói trong container mà chúng yêu cầu bắt đầu. Podman có thể chuyển tiếp ổ cắm SD_NOTIFY tới dịch vụ được chứa trong container để dịch vụ thông báo cho systemd rằng nó đã sẵn sàng hoạt động. Và một lần nữa, Docker, sử dụng mô hình client-server, không thể làm được điều này.
trong kế hoạch
Chúng tôi dự định thêm lệnh podman tạo systemd CONTAINERID, lệnh này sẽ tạo tệp đơn vị systemd để quản lý một vùng chứa cụ thể được chỉ định. Điều này sẽ hoạt động ở cả chế độ root và không root đối với các vùng chứa không có đặc quyền. Chúng tôi thậm chí còn thấy yêu cầu về thời gian chạy systemd-nspawn tương thích với OCI.
Kết luận
Chạy systemd trong container là một nhu cầu dễ hiểu. Và nhờ có Podman, cuối cùng chúng ta cũng có được thời gian chạy container không xung đột với systemd nhưng giúp dễ sử dụng.
Nguồn: www.habr.com