Systemd'yi bir konteynerde çalıştırmak

Container'larda systemd kullanımı konusunu uzun süredir takip ediyoruz. 2014 yılında güvenlik mühendisimiz Daniel Walsh bir makale yazmıştı Systemd'yi Docker Container'da çalıştırmakve birkaç yıl sonra - adı verilen bir başkası Systemd'yi ayrıcalıklı olmayan bir kapta çalıştırmadurumunun pek iyileşmediğini ifade etti. Özellikle şunu yazdı: “Maalesef iki yıl sonra bile “Docker sistemi” diye Google'da arattığınızda karşınıza ilk çıkan yine aynı eski makalesi oluyor. Bu yüzden bir şeyleri değiştirmenin zamanı geldi." Ayrıca daha önce de bahsetmiştik Docker ve systemd geliştiricileri arasındaki çatışma.

Systemd'yi bir konteynerde çalıştırmak

Bu yazımızda zaman içinde nelerin değiştiğini ve Podman'ın bu konuda bize nasıl yardımcı olabileceğini göstereceğiz.

Systemd'yi bir konteynerin içinde çalıştırmanın birçok nedeni vardır, örneğin:

  1. Çok hizmetli konteynerler – birçok kişi çoklu hizmet uygulamalarını sanal makinelerden çıkarıp konteynerlerde çalıştırmak istiyor. Elbette bu tür uygulamaları mikro hizmetlere bölmek daha iyi olur, ancak herkes bunun nasıl yapılacağını henüz bilmiyor veya zamanı yok. Bu nedenle, systemd tarafından başlatılan hizmetler gibi uygulamaların birim dosyalardan çalıştırılması son derece mantıklıdır.
  2. Systemd Birim Dosyaları – Konteynerlerin içinde çalışan uygulamaların çoğu, daha önce sanal veya fiziksel makinelerde çalıştırılan kodlardan oluşturulmuştur. Bu uygulamalar, bu uygulamalar için yazılmış ve nasıl başlatılması gerektiğini anlayan bir birim dosyasına sahiptir. Bu nedenle, kendi init hizmetinizi hacklemek yerine, hizmetleri desteklenen yöntemleri kullanarak başlatmak yine de daha iyidir.
  3. Systemd bir süreç yöneticisidir. Hizmetleri diğer tüm araçlardan daha iyi yönetir (hizmetleri kapatır, yeniden başlatır veya zombi işlemlerini sonlandırır).

Bununla birlikte, systemd'yi konteynerlerde çalıştırmamak için birçok neden var. Bunlardan en önemlisi, systemd/journald'ın konteynerlerin çıktısını ve benzeri araçları kontrol etmesidir. Kubernetes veya Açık Vardiya kapsayıcıların doğrudan stdout ve stderr'e günlük yazmasını bekliyoruz. Bu nedenle, eğer konteynerleri yukarıda bahsettiğimiz gibi orkestrasyon araçlarıyla yönetecekseniz, systemd tabanlı konteynerleri kullanmayı ciddi olarak düşünmelisiniz. Ek olarak Docker ve Moby geliştiricileri, konteynerlerde systemd kullanılmasına sıklıkla şiddetle karşı çıkıyorlar.

Podman'ın Gelişi

Durumun nihayet ilerlediğini bildirmekten mutluluk duyuyoruz. Red Hat'te konteynerlerin işletilmesinden sorumlu ekip şunları geliştirmeye karar verdi: kendi konteyner motorunuz. Bir ismi var podman ve Docker ile aynı komut satırı arayüzünü (CLI) sunar. Ve neredeyse tüm Docker komutları Podman'da aynı şekilde kullanılabilir. Sık sık şu anda adı verilen seminerler düzenliyoruz. Docker'ı Podman'a değiştirmeve ilk slayt şunu yazmayı gerektirir: takma ad docker=podman.

Birçoğu öyle yapıyor.

Podman'ım ve ben hiçbir şekilde systemd tabanlı konteynerlere karşı değiliz. Sonuçta Systemd, en yaygın kullanılan Linux init alt sistemidir ve konteynerlerde düzgün çalışmasına izin vermemek, binlerce kişinin konteyner çalıştırmaya nasıl alıştığını göz ardı etmek anlamına gelir.

Podman, systemd'nin bir konteynerde düzgün çalışmasını sağlamak için ne yapılması gerektiğini biliyor. Tmpfs'yi /run ve /tmp'ye bağlamak gibi şeylere ihtiyacı var. "Konteynerleştirilmiş" ortamın etkinleştirilmesini seviyor ve cgroup dizininin kendisine ait kısmına ve /var/log/journald klasörüne yazma izinleri bekliyor.

İlk komutun init veya systemd olduğu bir kapsayıcıyı başlattığınızda Podman, systemd'nin sorunsuz bir şekilde başlatılmasını sağlamak için tmpfs ve Cgroups'u otomatik olarak yapılandırır. Bu otomatik başlatma modunu engellemek için --systemd=false seçeneğini kullanın. Lütfen Podman'ın systemd modunu yalnızca bir systemd veya init komutunu çalıştırması gerektiğini gördüğünde kullandığını unutmayın.

İşte kılavuzdan bir alıntı:

adam podman koşuyor
...

–systemd=doğru|yanlış

Bir konteyneri systemd modunda çalıştırmak. Varsayılan olarak etkindir.

Bir kapsayıcı içinde systemd veya init komutunu çalıştırırsanız Podman, aşağıdaki dizinlerde tmpfs bağlama noktalarını yapılandıracaktır:

/run, /run/lock, /tmp, /sys/fs/cgroup/systemd, /var/lib/journal

Ayrıca varsayılan durdurma sinyali SIGRTMIN+3 olacaktır.

Bütün bunlar systemd'nin herhangi bir değişiklik yapmadan kapalı bir kapta çalışmasına izin verir.

NOT: systemd, cgroup dosya sistemine yazmaya çalışır. Ancak SELinux varsayılan olarak konteynerlerin bunu yapmasını engeller. Yazmayı etkinleştirmek için Container_manage_cgroup Boolean parametresini etkinleştirin:

setsebool -P konteyner_yönet_cgroup doğru

Şimdi Podman kullanarak systemd'yi bir kapta çalıştırmak için Dockerfile'ın nasıl göründüğüne bakın:

# cat Dockerfile

FROM fedora

RUN dnf -y install httpd; dnf clean all; systemctl enable httpd

EXPOSE 80

CMD [ "/sbin/init" ]

Hepsi bu.

Şimdi kabı birleştiriyoruz:

# podman build -t systemd .

SELinux'a systemd'nin Cgroups yapılandırmasını değiştirmesine izin vermesini söylüyoruz:

# setsebool -P container_manage_cgroup true

Bu arada birçok kişi bu adımı unutuyor. Neyse ki, bunun yalnızca bir kez yapılması gerekir ve sistem yeniden başlatıldıktan sonra ayar kaydedilir.

Şimdi konteyneri başlatıyoruz:

# 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.

İşte bu, hizmet çalışıyor ve çalışıyor:

$ curl localhost

<html  xml_lang="en" lang="en">

…

</html>

NOT: Bunu Docker'da denemeyin! Orada bu tür kapları arka plan programı aracılığıyla fırlatmak için hala tefle dans etmeniz gerekiyor. (Tüm bunların Docker'da sorunsuz bir şekilde çalışması için ek alanlar ve paketler gerekecektir veya ayrıcalıklı bir kapsayıcıda çalıştırılması gerekecektir. Ayrıntılar için bkz. Makale.)

Podman ve systemd hakkında birkaç harika şey daha

Podman, sistem birimi dosyalarında Docker'dan daha iyi çalışır

Sistem önyüklendiğinde kapların başlatılması gerekiyorsa, hizmeti başlatacak ve izleyecek olan uygun Podman komutlarını systemd birim dosyasına ekleyebilirsiniz. Podman standart fork-exec modelini kullanır. Başka bir deyişle, konteyner süreçleri Podman sürecinin çocuklarıdır, dolayısıyla systemd bunları kolaylıkla izleyebilir.

Docker bir istemci-sunucu modeli kullanır ve Docker CLI komutları doğrudan bir birim dosyasına da yerleştirilebilir. Bununla birlikte, Docker istemcisi Docker arka plan programına bağlandığında, o (istemci) stdin ve stdout'u işleyen başka bir süreç haline gelir. Buna karşılık, systemd'nin Docker istemcisi ile Docker arka plan programının kontrolü altında çalışan konteyner arasındaki bağlantı hakkında hiçbir fikri yoktur ve bu nedenle bu modelde systemd temelde hizmeti izleyemez.

Systemd'yi soket üzerinden etkinleştirme

Podman, etkinleştirmeyi soket aracılığıyla doğru bir şekilde gerçekleştiriyor. Podman fork-exec modelini kullandığından soketi alt konteyner işlemlerine iletebilir. Docker istemci-sunucu modelini kullandığı için bunu yapamaz.

Podman'ın uzak istemcilerle konteynerlere iletişim kurmak için kullandığı varlink hizmeti aslında bir soket aracılığıyla etkinleştirilir. Node.js'de yazılan ve kokpit projesinin bir parçası olan kokpit-podman paketi, insanların bir web arayüzü aracılığıyla Podman konteynerleriyle etkileşime girmesine olanak tanıyor. Cockpit-podman'ı çalıştıran web arka plan programı, mesajları sistemin dinlediği bir varlink soketine gönderir. Systemd daha sonra mesajları almak ve kapsayıcıları yönetmeye başlamak için Podman programını etkinleştirir. Systemd'nin bir soket üzerinden etkinleştirilmesi, uzak API'leri uygularken sürekli çalışan bir arka plan programına olan ihtiyacı ortadan kaldırır.

Ek olarak, aynı Podman CLI'yi uygulayan ancak kapsayıcıları çalıştırmak için varlink'i çağıran podman-remote adında başka bir Podman istemcisi geliştiriyoruz. Podman-remote, SSH oturumlarının üzerinde çalışabilir ve farklı makinelerdeki konteynerlerle güvenli bir şekilde etkileşim kurmanıza olanak tanır. Zaman içinde podman-remote'un Linux'un yanı sıra MacOS ve Windows'u da desteklemesini etkinleştirmeyi planlıyoruz, böylece bu platformlardaki geliştiriciler Podman varlink'in çalıştığı bir Linux sanal makinesini çalıştırabilir ve konteynerlerin yerel makinede çalıştığına dair tam deneyime sahip olabilir.

SD_NOTIFY

Systemd, yardımcı hizmetlerin başlatılmasını, ihtiyaç duydukları konteynerli hizmet başlayana kadar ertelemenize olanak tanır. Podman, SD_NOTIFY soketini konteynerli hizmete iletebilir, böylece hizmet systemd'ye çalışmaya hazır olduğunu bildirir. Ve yine istemci-sunucu modelini kullanan Docker bunu yapamıyor.

Planlarda

Belirtilen belirli bir kapsayıcıyı yönetmek için bir systemd birim dosyası oluşturacak podman created systemd CONTAINERID komutunu eklemeyi planlıyoruz. Bu, ayrıcalıklı olmayan kaplar için hem kök hem de köksüz modlarda çalışmalıdır. Hatta OCI uyumlu bir systemd-nspawn çalışma zamanı talebi bile gördük.

Sonuç

Systemd'yi bir kapta çalıştırmak anlaşılabilir bir ihtiyaçtır. Ve Podman sayesinde nihayet systemd ile çakışmayan ancak kullanımı kolaylaştıran bir konteyner çalışma zamanına sahip olduk.

Kaynak: habr.com

Yorum ekle