Chạy systemd trong một container

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 Chạy systemd trong Docker Container, và vài năm sau - một cái khác, được gọi là Chạy systemd trong vùng chứa không có đặc quyền, trong đó ông cho rằng tình hình vẫn chưa được cải thiện nhiều. Đặc biệt, anh ấy viết rằng “thật không may, thậm chí hai năm sau, nếu bạn google “hệ thống Docker”, điều đầu tiên hiện ra vẫn là bài báo cũ của anh ấy. Vì vậy đã đến lúc phải thay đổi điều gì đó.” Ngoài ra, chúng ta đã nói về xung đột giữa Docker và nhà phát triển systemd.

Chạy systemd trong một container

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ư:

  1. 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ý.
  2. 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.
  3. 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ư Kubernetes hoặc mởShift mong đợi các thùng chứa ghi nhật ký trực tiếp vào thiết bị xuất chuẩn và thiết bị xuất chuẩn. Do đó, nếu bạn định quản lý các vùng chứa thông qua các công cụ điều phối như những công cụ được đề cập ở trên, bạn nên cân nhắc nghiêm túc việc sử dụng các vùng chứa dựa trên systemd. Ngoài ra, các nhà phát triển Docker và Moby thường phản đối mạnh mẽ việc sử dụng systemd trong các thùng chứa.

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 động cơ container của riêng bạn. Anh ấy có một cái tên podman và cung cấp giao diện dòng lệnh (CLI) tương tự như Docker. Và hầu như tất cả các lệnh Docker đều có thể được sử dụng trong Podman theo cách tương tự. Chúng tôi thường tổ chức các buổi hội thảo, ngày nay được gọi là Thay đổi Docker thành Podmanvà slide đầu tiên yêu cầu viết: alias docker=podman.

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 Bài viết.)

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

Thêm một lời nhận xét