systemd study중에 https://freedesktop.org/wiki/Software/systemd/ 에 링크된 Lennart(?)라는 분의 'The systemd for Administrators Blog Series'의 내용을 발견하고 내용이 좋아 번역해서(구글번역+약간의 교정) md 문서로 만들어 놨는데, 이번에 이를 포스팅 해봅니다.
번역이 매끄럽지 못한 부분은 원문을 참조하시거나, 아예 원문으로 보셔도 되겠습니다.
(원문: http://0pointer.de/blog/projects/systemd-for-admins-1.html)
많은 분들이 아시다시피, systemd는 F14로 시작하는 새로운 Fedora init 시스템이며 다른 여러 배포판에서도 채택되고 있습니다 (예: OpenSUSE). 관리자를 위해 systemd는 다양한 새로운 기능과 변경 사항을 제공하고 관리 프로세스를 크게 향상시킵니다. 이 블로그 이야기는 다음 달 동안 대략 매주 게시할 예정인 기사 시리즈의 첫 번째 부분입니다. 모든 포스트에서 나는 systemd의 새로운 기능을 설명하려고 노력할 것입니다. 이러한 기능 중 상당수는 작고 단순하므로 더 많은 청중에게 흥미로울 것입니다. 그러나 때때로 우리는 systemd가 제공하는 훌륭한 새로운 기능에 대해 조금 더 깊이 파고들 것입니다.
전통적으로 Linux 시스템을 부팅할 때 화면에 작은 메시지가 많이 전달됩니다. 부팅 프로세스의 속도를 높이고 병렬화하는 작업을 진행하면서 이러한 메시지는 더 짧고 짧은 시간 동안만 표시되고 점점 더 가독성이 떨어집니다. 그럼에도 불구하고 부팅 화면의 정보는 부팅의 일부로 시작되는 각 서비스에 대해 성공적으로 시작되었는지 실패했는지 (녹색 또는 빨간색 [OK] 또는 [FAILED] 표시기). 빠르게 부팅되고 병렬화된 시스템의 상황을 개선하고 런타임 중에 이 정보를 더 잘 사용할 수 있도록 하기위해 각 서비스가 성공적으로 시작되었는지, 0 이 아닌 종료코드로 종료되었는지, 타임아웃 되었거나 비정상적으로 종료되었는지 (세그폴팅 또는 이와 유사한 방식으로) 여부를 스타트업 및 런타임 동안 추적하고 기억하는 기능을 systemd에 추가했습니다. 셸에 systemctl을 입력하기 만하면 systemd 기본 서비스와 SysV/LSB 서비스 모두의 모든 서비스 상태를 쿼리할 수 있습니다:
[root@lambda] ~# systemctl
UNIT LOAD ACTIVE SUB JOB DESCRIPTION
dev-hugepages.automount loaded active running Huge Pages File System Automount Point
dev-mqueue.automount loaded active running POSIX Message Queue File System Automount Point
proc-sys-fs-binfmt_misc.automount loaded active waiting Arbitrary Executable File Formats File System Automount Point
sys-kernel-debug.automount loaded active waiting Debug File System Automount Point
sys-kernel-security.automount loaded active waiting Security File System Automount Point
sys-devices-pc...0000:02:00.0-net-eth0.device loaded active plugged 82573L Gigabit Ethernet Controller
[...]
sys-devices-virtual-tty-tty9.device loaded active plugged /sys/devices/virtual/tty/tty9
-.mount loaded active mounted /
boot.mount loaded active mounted /boot
dev-hugepages.mount loaded active mounted Huge Pages File System
dev-mqueue.mount loaded active mounted POSIX Message Queue File System
home.mount loaded active mounted /home
proc-sys-fs-binfmt_misc.mount loaded active mounted Arbitrary Executable File Formats File System
abrtd.service loaded active running ABRT Automated Bug Reporting Tool
accounts-daemon.service loaded active running Accounts Service
acpid.service loaded active running ACPI Event Daemon
atd.service loaded active running Execution Queue Daemon
auditd.service loaded active running Security Auditing Service
avahi-daemon.service loaded active running Avahi mDNS/DNS-SD Stack
bluetooth.service loaded active running Bluetooth Manager
console-kit-daemon.service loaded active running Console Manager
cpuspeed.service loaded active exited LSB: processor frequency scaling support
crond.service loaded active running Command Scheduler
cups.service loaded active running CUPS Printing Service
dbus.service loaded active running D-Bus System Message Bus
getty@tty2.service loaded active running Getty on tty2
getty@tty3.service loaded active running Getty on tty3
getty@tty4.service loaded active running Getty on tty4
getty@tty5.service loaded active running Getty on tty5
getty@tty6.service loaded active running Getty on tty6
haldaemon.service loaded active running Hardware Manager
hdapsd@sda.service loaded active running sda shock protection daemon
irqbalance.service loaded active running LSB: start and stop irqbalance daemon
iscsi.service loaded active exited LSB: Starts and stops login and scanning of iSCSI devices.
iscsid.service loaded active exited LSB: Starts and stops login iSCSI daemon.
livesys-late.service loaded active exited LSB: Late init script for live image.
livesys.service loaded active exited LSB: Init script for live image.
lvm2-monitor.service loaded active exited LSB: Monitoring of LVM2 mirrors, snapshots etc. using dmeventd or progress polling
mdmonitor.service loaded active running LSB: Start and stop the MD software RAID monitor
modem-manager.service loaded active running Modem Manager
netfs.service loaded active exited LSB: Mount and unmount network filesystems.
NetworkManager.service loaded active running Network Manager
ntpd.service loaded maintenance maintenance Network Time Service
polkitd.service loaded active running Policy Manager
prefdm.service loaded active running Display Manager
rc-local.service loaded active exited /etc/rc.local Compatibility
rpcbind.service loaded active running RPC Portmapper Service
rsyslog.service loaded active running System Logging Service
rtkit-daemon.service loaded active running RealtimeKit Scheduling Policy Service
sendmail.service loaded active running LSB: start and stop sendmail
sshd@172.31.0.53:22-172.31.0.4:36368.service loaded active running SSH Per-Connection Server
sysinit.service loaded active running System Initialization
systemd-logger.service loaded active running systemd Logging Daemon
udev-post.service loaded active exited LSB: Moves the generated persistent udev rules to /etc/udev/rules.d
udisks.service loaded active running Disk Manager
upowerd.service loaded active running Power Manager
wpa_supplicant.service loaded active running Wi-Fi Security Service
avahi-daemon.socket loaded active listening Avahi mDNS/DNS-SD Stack Activation Socket
cups.socket loaded active listening CUPS Printing Service Sockets
dbus.socket loaded active running dbus.socket
rpcbind.socket loaded active listening RPC Portmapper Socket
sshd.socket loaded active listening sshd.socket
systemd-initctl.socket loaded active listening systemd /dev/initctl Compatibility Socket
systemd-logger.socket loaded active running systemd Logging Socket
systemd-shutdownd.socket loaded active listening systemd Delayed Shutdown Socket
dev-disk-by\x1...x1db22a\x1d870f1adf2732.swap loaded active active /dev/disk/by-uuid/fd626ef7-34a4-4958-b22a-870f1adf2732
basic.target loaded active active Basic System
bluetooth.target loaded active active Bluetooth
dbus.target loaded active active D-Bus
getty.target loaded active active Login Prompts
graphical.target loaded active active Graphical Interface
local-fs.target loaded active active Local File Systems
multi-user.target loaded active active Multi-User
network.target loaded active active Network
remote-fs.target loaded active active Remote File Systems
sockets.target loaded active active Sockets
swap.target loaded active active Swap
sysinit.target loaded active active System Initialization
LOAD = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB = The low-level unit activation state, values depend on unit type.
JOB = Pending job for the unit.
221 units listed. Pass --all to see inactive units, too.
[root@lambda] ~#
(위의 출력을 약간 줄였고 이 블로그 게시물과 관련이 없는 몇 줄을 제거했습니다)
ACTIVE 열을 보면, 활성 (예: running), 비활성 (예: not running) 또는 기타 상태에 관계없이 서비스의 상위 수준 상태를 보여줍니다 (또는 실제로 모든 종류의 단위 시스템 유지 관리는 단순한 서비스 이상이 될 수 있지만 나중에 블로그 게시물에서 이에 대해 살펴 보겠습니다). 자세히 살펴보면 목록에서 유지 보수로 표시되고 빨간색으로 강조 표시된 항목 하나를 볼 수 있습니다. 실행에 실패했거나 문제가 발생한 서비스에 대해 알려줍니다. 이 경우 이것은 ntpd입니다. 이제 systemctl status 명령을 사용하여 ntpd에 실제로 무슨 일이 일어 났는지 알아 봅시다:
[root@lambda] ~# systemctl status ntpd.service
ntpd.service - Network Time Service
Loaded: loaded (/etc/systemd/system/ntpd.service)
Active: maintenance
Main: 953 (code=exited, status=255)
CGroup: name=systemd:/systemd-1/ntpd.service
[root@lambda] ~#
이것은 NTP가 런타임 (PID 953으로 실행되었을 때) 동안 종료되었음을 보여주고 오류 상태를 정확히 알려줍니다. 프로세스가 종료 상태 255로 종료되었습니다.
이후 시스템 버전에서는 이 개선 요청이 수정되는 즉시 이를 ABRT(Automatic Bug Reporting Tool)에 연결할 계획입니다. 그런 다음 systemctl 상태에 충돌 한 서비스에 대한 정보가 표시되면 ABRT의 적절한 충돌 덤프로 바로 연결됩니다.
Summary: use systemctl and systemctl status as modern, more complete replacements for the traditional boot-up status messages of SysV services. systemctl status not only captures in more detail the error condition but also shows runtime errors in addition to start-up errors.
요약: Systemctl 및 systemctl status를 SysV 서비스의 기존 부팅 상태 메시지에 대한 최신의 보다 완전한 대체물로 사용합니다. systemctl status는 오류 상태를 더 자세히 캡처할 뿐만 아니라 시작 오류와 함께 런타임 오류도 표시합니다.
이번 주에는 여기까지입니다. 다음 주에 다시 방문하여 관리자를위한 systemd에 대한 다음 게시물을 확인하세요!
(원문: http://0pointer.de/blog/projects/systemd-for-admins-2.html)
(어떤 서비스가 어떤 프로세스를 소유합니까?)
대부분의 Linux 시스템에서 기본적으로 실행되는 프로세스의 수는 상당합니다. 어떤 프로세스가 무엇을 하고 어디에 속해 있는지 아는 것이 점점 더 어려워집니다. 일부 서비스는 종종 인식하기 쉽지않은 많은 추가 프로세스로 "ps" 출력을 복잡하게 만드는 두 개의 작업자 프로세스를 유지합니다. Apache가 CGI 프로세스에서 수행하는 것처럼 데몬이 임의의 타사 프로세스를 생성하거나 cron이 사용자 작업에서 수행하는 경우 이는 더욱 복잡합니다.
이에 대한 약간의 해결책은 "ps xaf"에 표시된 것처럼 프로세스 상속 트리입니다. 그러나 부모가 죽는 프로세스가 PID 1로 다시 부모가 되어 상속에 대한 모든 정보가 손실되므로 일반적으로 신뢰할 수 없습니다. 프로세스가 "이중 포크"되면 시작된 프로세스와의 관계가 손실됩니다. (이것은 실제로 기능으로 간주되며 기존의 Unix 데몬화 논리에 의존합니다) 또한 프로세스는 PR_SETNAME을 사용하거나 argv[0]을 패치하여 이름을 자유롭게 변경할 수 있으므로 인식하기가 더 어려워집니다. 사실 그들은 이런 방식으로 관리자와 숨바꼭질을 할 수 있습니다.
systemd에서는 서비스 이름을 따서 명명된 제어 그룹에 생성되는 모든 프로세스를 배치합니다. 가장 기본적인 제어 그룹 (또는 cgroup)은 단순히 계층 구조로 배열되고 개별적으로 레이블이 지정될 수 있는 프로세스 그룹입니다. 프로세스가 다른 프로세스를 생성할 때 이러한 자식은 자동으로 부모 cgroup의 구성원이 됩니다. 권한이 없는 프로세스에서는 cgroup을 탈퇴 할 수 없습니다. 따라서 cgroup은 프로세스가 속한 서비스 이후에 프로세스에 레이블을 지정하는 효과적인 방법으로 사용할 수 있으며 서비스가 포크하거나 이름을 변경하는 빈도에 관계없이 서비스가 레이블에서 벗어날 수 없도록합니다. 또한 이것은 서비스와 서비스가 생성한 모든 프로세스를 안전하게 종료하는 데 사용할 수 있습니다.
오늘의 기사에서는 시스템 서비스와 프로세스를 연결하는 데 사용할 수 있는 두 가지 명령을 소개하고자 합니다. 첫 번째는 다른 프로세스 세부 정보와 함께 cgroup 정보를 표시하도록 업데이트된 잘 알려진 ps 명령이고 이것이 어떻게 보이는지 입니다:
$ ps xawf -eo pid,user,cgroup,args
PID USER CGROUP COMMAND
2 root - [kthreadd]
3 root - \_ [ksoftirqd/0]
[...]
4281 root - \_ [flush-8:0]
1 root name=systemd:/systemd-1 /sbin/init
455 root name=systemd:/systemd-1/sysinit.service /sbin/udevd -d
28188 root name=systemd:/systemd-1/sysinit.service \_ /sbin/udevd -d
28191 root name=systemd:/systemd-1/sysinit.service \_ /sbin/udevd -d
1096 dbus name=systemd:/systemd-1/dbus.service /bin/dbus-daemon --system --address=systemd: --nofork --systemd-activation
1131 root name=systemd:/systemd-1/auditd.service auditd
1133 root name=systemd:/systemd-1/auditd.service \_ /sbin/audispd
1135 root name=systemd:/systemd-1/auditd.service \_ /usr/sbin/sedispatch
1171 root name=systemd:/systemd-1/NetworkManager.service /usr/sbin/NetworkManager --no-daemon
4028 root name=systemd:/systemd-1/NetworkManager.service \_ /sbin/dhclient -d -4 -sf /usr/libexec/nm-dhcp-client.action -pf /var/run/dhclient-wlan0.pid -lf /var/lib/dhclient/dhclient-7d32a784-ede9-4cf6-9ee3-60edc0bce5ff-wlan0.lease -
1175 avahi name=systemd:/systemd-1/avahi-daemon.service avahi-daemon: running [epsilon.local]
1194 avahi name=systemd:/systemd-1/avahi-daemon.service \_ avahi-daemon: chroot helper
1193 root name=systemd:/systemd-1/rsyslog.service /sbin/rsyslogd -c 4
1195 root name=systemd:/systemd-1/cups.service cupsd -C /etc/cups/cupsd.conf
1207 root name=systemd:/systemd-1/mdmonitor.service mdadm --monitor --scan -f --pid-file=/var/run/mdadm/mdadm.pid
1210 root name=systemd:/systemd-1/irqbalance.service irqbalance
1216 root name=systemd:/systemd-1/dbus.service /usr/sbin/modem-manager
1219 root name=systemd:/systemd-1/dbus.service /usr/libexec/polkit-1/polkitd
1242 root name=systemd:/systemd-1/dbus.service /usr/sbin/wpa_supplicant -c /etc/wpa_supplicant/wpa_supplicant.conf -B -u -f /var/log/wpa_supplicant.log -P /var/run/wpa_supplicant.pid
1249 68 name=systemd:/systemd-1/haldaemon.service hald
1250 root name=systemd:/systemd-1/haldaemon.service \_ hald-runner
1273 root name=systemd:/systemd-1/haldaemon.service \_ hald-addon-input: Listening on /dev/input/event3 /dev/input/event9 /dev/input/event1 /dev/input/event7 /dev/input/event2 /dev/input/event0 /dev/input/event8
1275 root name=systemd:/systemd-1/haldaemon.service \_ /usr/libexec/hald-addon-rfkill-killswitch
1284 root name=systemd:/systemd-1/haldaemon.service \_ /usr/libexec/hald-addon-leds
1285 root name=systemd:/systemd-1/haldaemon.service \_ /usr/libexec/hald-addon-generic-backlight
1287 68 name=systemd:/systemd-1/haldaemon.service \_ /usr/libexec/hald-addon-acpi
1317 root name=systemd:/systemd-1/abrtd.service /usr/sbin/abrtd -d -s
1332 root name=systemd:/systemd-1/getty@.service/tty2 /sbin/mingetty tty2
1339 root name=systemd:/systemd-1/getty@.service/tty3 /sbin/mingetty tty3
1342 root name=systemd:/systemd-1/getty@.service/tty5 /sbin/mingetty tty5
1343 root name=systemd:/systemd-1/getty@.service/tty4 /sbin/mingetty tty4
1344 root name=systemd:/systemd-1/crond.service crond
1346 root name=systemd:/systemd-1/getty@.service/tty6 /sbin/mingetty tty6
1362 root name=systemd:/systemd-1/sshd.service /usr/sbin/sshd
1376 root name=systemd:/systemd-1/prefdm.service /usr/sbin/gdm-binary -nodaemon
1391 root name=systemd:/systemd-1/prefdm.service \_ /usr/libexec/gdm-simple-slave --display-id /org/gnome/DisplayManager/Display1 --force-active-vt
1394 root name=systemd:/systemd-1/prefdm.service \_ /usr/bin/Xorg :0 -nr -verbose -auth /var/run/gdm/auth-for-gdm-f2KUOh/database -nolisten tcp vt1
1495 root name=systemd:/user/lennart/1 \_ pam: gdm-password
1521 lennart name=systemd:/user/lennart/1 \_ gnome-session
1621 lennart name=systemd:/user/lennart/1 \_ metacity
1635 lennart name=systemd:/user/lennart/1 \_ gnome-panel
1638 lennart name=systemd:/user/lennart/1 \_ nautilus
1640 lennart name=systemd:/user/lennart/1 \_ /usr/libexec/polkit-gnome-authentication-agent-1
1641 lennart name=systemd:/user/lennart/1 \_ /usr/bin/seapplet
1644 lennart name=systemd:/user/lennart/1 \_ gnome-volume-control-applet
1646 lennart name=systemd:/user/lennart/1 \_ /usr/sbin/restorecond -u
1652 lennart name=systemd:/user/lennart/1 \_ /usr/bin/devilspie
1662 lennart name=systemd:/user/lennart/1 \_ nm-applet --sm-disable
1664 lennart name=systemd:/user/lennart/1 \_ gnome-power-manager
1665 lennart name=systemd:/user/lennart/1 \_ /usr/libexec/gdu-notification-daemon
1670 lennart name=systemd:/user/lennart/1 \_ /usr/libexec/evolution/2.32/evolution-alarm-notify
1672 lennart name=systemd:/user/lennart/1 \_ /usr/bin/python /usr/share/system-config-printer/applet.py
1674 lennart name=systemd:/user/lennart/1 \_ /usr/lib64/deja-dup/deja-dup-monitor
1675 lennart name=systemd:/user/lennart/1 \_ abrt-applet
1677 lennart name=systemd:/user/lennart/1 \_ bluetooth-applet
1678 lennart name=systemd:/user/lennart/1 \_ gpk-update-icon
1408 root name=systemd:/systemd-1/console-kit-daemon.service /usr/sbin/console-kit-daemon --no-daemon
1419 gdm name=systemd:/systemd-1/prefdm.service /usr/bin/dbus-launch --exit-with-session
1453 root name=systemd:/systemd-1/dbus.service /usr/libexec/upowerd
1473 rtkit name=systemd:/systemd-1/rtkit-daemon.service /usr/libexec/rtkit-daemon
1496 root name=systemd:/systemd-1/accounts-daemon.service /usr/libexec/accounts-daemon
1499 root name=systemd:/systemd-1/systemd-logger.service /lib/systemd/systemd-logger
1511 lennart name=systemd:/systemd-1/prefdm.service /usr/bin/gnome-keyring-daemon --daemonize --login
1534 lennart name=systemd:/user/lennart/1 dbus-launch --sh-syntax --exit-with-session
1535 lennart name=systemd:/user/lennart/1 /bin/dbus-daemon --fork --print-pid 5 --print-address 7 --session
1603 lennart name=systemd:/user/lennart/1 /usr/libexec/gconfd-2
1612 lennart name=systemd:/user/lennart/1 /usr/libexec/gnome-settings-daemon
1615 lennart name=systemd:/user/lennart/1 /usr/libexec/gvfsd
1626 lennart name=systemd:/user/lennart/1 /usr/libexec//gvfs-fuse-daemon /home/lennart/.gvfs
1634 lennart name=systemd:/user/lennart/1 /usr/bin/pulseaudio --start --log-target=syslog
1649 lennart name=systemd:/user/lennart/1 \_ /usr/libexec/pulse/gconf-helper
1645 lennart name=systemd:/user/lennart/1 /usr/libexec/bonobo-activation-server --ac-activate --ior-output-fd=24
1668 lennart name=systemd:/user/lennart/1 /usr/libexec/im-settings-daemon
1701 lennart name=systemd:/user/lennart/1 /usr/libexec/gvfs-gdu-volume-monitor
1707 lennart name=systemd:/user/lennart/1 /usr/bin/gnote --panel-applet --oaf-activate-iid=OAFIID:GnoteApplet_Factory --oaf-ior-fd=22
1725 lennart name=systemd:/user/lennart/1 /usr/libexec/clock-applet
1727 lennart name=systemd:/user/lennart/1 /usr/libexec/wnck-applet
1729 lennart name=systemd:/user/lennart/1 /usr/libexec/notification-area-applet
1733 root name=systemd:/systemd-1/dbus.service /usr/libexec/udisks-daemon
1747 root name=systemd:/systemd-1/dbus.service \_ udisks-daemon: polling /dev/sr0
1759 lennart name=systemd:/user/lennart/1 gnome-screensaver
1780 lennart name=systemd:/user/lennart/1 /usr/libexec/gvfsd-trash --spawner :1.9 /org/gtk/gvfs/exec_spaw/0
1864 lennart name=systemd:/user/lennart/1 /usr/libexec/gvfs-afc-volume-monitor
1874 lennart name=systemd:/user/lennart/1 /usr/libexec/gconf-im-settings-daemon
1903 lennart name=systemd:/user/lennart/1 /usr/libexec/gvfsd-burn --spawner :1.9 /org/gtk/gvfs/exec_spaw/1
1909 lennart name=systemd:/user/lennart/1 gnome-terminal
1913 lennart name=systemd:/user/lennart/1 \_ gnome-pty-helper
1914 lennart name=systemd:/user/lennart/1 \_ bash
29231 lennart name=systemd:/user/lennart/1 | \_ ssh tango
2221 lennart name=systemd:/user/lennart/1 \_ bash
4193 lennart name=systemd:/user/lennart/1 | \_ ssh tango
2461 lennart name=systemd:/user/lennart/1 \_ bash
29219 lennart name=systemd:/user/lennart/1 | \_ emacs systemd-for-admins-1.txt
15113 lennart name=systemd:/user/lennart/1 \_ bash
27251 lennart name=systemd:/user/lennart/1 \_ empathy
29504 lennart name=systemd:/user/lennart/1 \_ ps xawf -eo pid,user,cgroup,args
1968 lennart name=systemd:/user/lennart/1 ssh-agent
1994 lennart name=systemd:/user/lennart/1 gpg-agent --daemon --write-env-file
18679 lennart name=systemd:/user/lennart/1 /bin/sh /usr/lib64/firefox-3.6/run-mozilla.sh /usr/lib64/firefox-3.6/firefox
18741 lennart name=systemd:/user/lennart/1 \_ /usr/lib64/firefox-3.6/firefox
28900 lennart name=systemd:/user/lennart/1 \_ /usr/lib64/nspluginwrapper/npviewer.bin --plugin /usr/lib64/mozilla/plugins/libflashplayer.so --connection /org/wrapper/NSPlugins/libflashplayer.so/18741-6
4016 root name=systemd:/systemd-1/sysinit.service /usr/sbin/bluetoothd --udev
4094 smmsp name=systemd:/systemd-1/sendmail.service sendmail: Queue runner@01:00:00 for /var/spool/clientmqueue
4096 root name=systemd:/systemd-1/sendmail.service sendmail: accepting connections
4112 ntp name=systemd:/systemd-1/ntpd.service /usr/sbin/ntpd -n -u ntp:ntp -g
27262 lennart name=systemd:/user/lennart/1 /usr/libexec/mission-control-5
27265 lennart name=systemd:/user/lennart/1 /usr/libexec/telepathy-haze
27268 lennart name=systemd:/user/lennart/1 /usr/libexec/telepathy-logger
27270 lennart name=systemd:/user/lennart/1 /usr/libexec/dconf-service
27280 lennart name=systemd:/user/lennart/1 /usr/libexec/notification-daemon
27284 lennart name=systemd:/user/lennart/1 /usr/libexec/telepathy-gabble
27285 lennart name=systemd:/user/lennart/1 /usr/libexec/telepathy-salut
27297 lennart name=systemd:/user/lennart/1 /usr/libexec/geoclue-yahoo
(이 출력은 단축되었으며, 이 블로그 스토리의 맥락과 관련이 없기 때문에 여기에서 대부분의 커널 스레드를 제거했습니다)
세 번째 열에는 각 프로세스에 할당 된 cgroup systemd가 표시됩니다. udev 프로세스는 name=systemd:/systemd-1/sysinit.service cgroup에 있습니다. 여기서 systemd는 초기 부팅을 다루는 sysinit.service 서비스에 의해 시작된 모든 프로세스를 배치합니다.
내 개인적인 권장 사항은 shell alias psc를 위에 표시된 ps 명령 줄로 설정하는 것입니다:
alias psc='ps xawf -eo pid,user,cgroup,args'
이 서비스를 통해 프로세스의 정보는 키를 네 번만 누르면됩니다!
동일한 정보를 표시하는 다른 방법은 systemd와 함께 제공되는 systemd-cgls 도구입니다. 예쁜 트리에 cgroup 계층 구조를 보여줍니다. 출력은 다음과 같습니다:
$ systemd-cgls
+ 2 [kthreadd]
[...]
+ 4281 [flush-8:0]
+ user
| \ lennart
| \ 1
| + 1495 pam: gdm-password
| + 1521 gnome-session
| + 1534 dbus-launch --sh-syntax --exit-with-session
| + 1535 /bin/dbus-daemon --fork --print-pid 5 --print-address 7 --session
| + 1603 /usr/libexec/gconfd-2
| + 1612 /usr/libexec/gnome-settings-daemon
| + 1615 /ushr/libexec/gvfsd
| + 1621 metacity
| + 1626 /usr/libexec//gvfs-fuse-daemon /home/lennart/.gvfs
| + 1634 /usr/bin/pulseaudio --start --log-target=syslog
| + 1635 gnome-panel
| + 1638 nautilus
| + 1640 /usr/libexec/polkit-gnome-authentication-agent-1
| + 1641 /usr/bin/seapplet
| + 1644 gnome-volume-control-applet
| + 1645 /usr/libexec/bonobo-activation-server --ac-activate --ior-output-fd=24
| + 1646 /usr/sbin/restorecond -u
| + 1649 /usr/libexec/pulse/gconf-helper
| + 1652 /usr/bin/devilspie
| + 1662 nm-applet --sm-disable
| + 1664 gnome-power-manager
| + 1665 /usr/libexec/gdu-notification-daemon
| + 1668 /usr/libexec/im-settings-daemon
| + 1670 /usr/libexec/evolution/2.32/evolution-alarm-notify
| + 1672 /usr/bin/python /usr/share/system-config-printer/applet.py
| + 1674 /usr/lib64/deja-dup/deja-dup-monitor
| + 1675 abrt-applet
| + 1677 bluetooth-applet
| + 1678 gpk-update-icon
| + 1701 /usr/libexec/gvfs-gdu-volume-monitor
| + 1707 /usr/bin/gnote --panel-applet --oaf-activate-iid=OAFIID:GnoteApplet_Factory --oaf-ior-fd=22
| + 1725 /usr/libexec/clock-applet
| + 1727 /usr/libexec/wnck-applet
| + 1729 /usr/libexec/notification-area-applet
| + 1759 gnome-screensaver
| + 1780 /usr/libexec/gvfsd-trash --spawner :1.9 /org/gtk/gvfs/exec_spaw/0
| + 1864 /usr/libexec/gvfs-afc-volume-monitor
| + 1874 /usr/libexec/gconf-im-settings-daemon
| + 1882 /usr/libexec/gvfs-gphoto2-volume-monitor
| + 1903 /usr/libexec/gvfsd-burn --spawner :1.9 /org/gtk/gvfs/exec_spaw/1
| + 1909 gnome-terminal
| + 1913 gnome-pty-helper
| + 1914 bash
| + 1968 ssh-agent
| + 1994 gpg-agent --daemon --write-env-file
| + 2221 bash
| + 2461 bash
| + 4193 ssh tango
| + 15113 bash
| + 18679 /bin/sh /usr/lib64/firefox-3.6/run-mozilla.sh /usr/lib64/firefox-3.6/firefox
| + 18741 /usr/lib64/firefox-3.6/firefox
| + 27251 empathy
| + 27262 /usr/libexec/mission-control-5
| + 27265 /usr/libexec/telepathy-haze
| + 27268 /usr/libexec/telepathy-logger
| + 27270 /usr/libexec/dconf-service
| + 27280 /usr/libexec/notification-daemon
| + 27284 /usr/libexec/telepathy-gabble
| + 27285 /usr/libexec/telepathy-salut
| + 27297 /usr/libexec/geoclue-yahoo
| + 28900 /usr/lib64/nspluginwrapper/npviewer.bin --plugin /usr/lib64/mozilla/plugins/libflashplayer.so --connection /org/wrapper/NSPlugins/libflashplayer.so/18741-6
| + 29219 emacs systemd-for-admins-1.txt
| + 29231 ssh tango
| \ 29519 systemd-cgls
\ systemd-1
+ 1 /sbin/init
+ ntpd.service
| \ 4112 /usr/sbin/ntpd -n -u ntp:ntp -g
+ systemd-logger.service
| \ 1499 /lib/systemd/systemd-logger
+ accounts-daemon.service
| \ 1496 /usr/libexec/accounts-daemon
+ rtkit-daemon.service
| \ 1473 /usr/libexec/rtkit-daemon
+ console-kit-daemon.service
| \ 1408 /usr/sbin/console-kit-daemon --no-daemon
+ prefdm.service
| + 1376 /usr/sbin/gdm-binary -nodaemon
| + 1391 /usr/libexec/gdm-simple-slave --display-id /org/gnome/DisplayManager/Display1 --force-active-vt
| + 1394 /usr/bin/Xorg :0 -nr -verbose -auth /var/run/gdm/auth-for-gdm-f2KUOh/database -nolisten tcp vt1
| + 1419 /usr/bin/dbus-launch --exit-with-session
| \ 1511 /usr/bin/gnome-keyring-daemon --daemonize --login
+ getty@.service
| + tty6
| | \ 1346 /sbin/mingetty tty6
| + tty4
| | \ 1343 /sbin/mingetty tty4
| + tty5
| | \ 1342 /sbin/mingetty tty5
| + tty3
| | \ 1339 /sbin/mingetty tty3
| \ tty2
| \ 1332 /sbin/mingetty tty2
+ abrtd.service
| \ 1317 /usr/sbin/abrtd -d -s
+ crond.service
| \ 1344 crond
+ sshd.service
| \ 1362 /usr/sbin/sshd
+ sendmail.service
| + 4094 sendmail: Queue runner@01:00:00 for /var/spool/clientmqueue
| \ 4096 sendmail: accepting connections
+ haldaemon.service
| + 1249 hald
| + 1250 hald-runner
| + 1273 hald-addon-input: Listening on /dev/input/event3 /dev/input/event9 /dev/input/event1 /dev/input/event7 /dev/input/event2 /dev/input/event0 /dev/input/event8
| + 1275 /usr/libexec/hald-addon-rfkill-killswitch
| + 1284 /usr/libexec/hald-addon-leds
| + 1285 /usr/libexec/hald-addon-generic-backlight
| \ 1287 /usr/libexec/hald-addon-acpi
+ irqbalance.service
| \ 1210 irqbalance
+ avahi-daemon.service
| + 1175 avahi-daemon: running [epsilon.local]
+ NetworkManager.service
| + 1171 /usr/sbin/NetworkManager --no-daemon
| \ 4028 /sbin/dhclient -d -4 -sf /usr/libexec/nm-dhcp-client.action -pf /var/run/dhclient-wlan0.pid -lf /var/lib/dhclient/dhclient-7d32a784-ede9-4cf6-9ee3-60edc0bce5ff-wlan0.lease -cf /var/run/nm-dhclient-wlan0.conf wlan0
+ rsyslog.service
| \ 1193 /sbin/rsyslogd -c 4
+ mdmonitor.service
| \ 1207 mdadm --monitor --scan -f --pid-file=/var/run/mdadm/mdadm.pid
+ cups.service
| \ 1195 cupsd -C /etc/cups/cupsd.conf
+ auditd.service
| + 1131 auditd
| + 1133 /sbin/audispd
| \ 1135 /usr/sbin/sedispatch
+ dbus.service
| + 1096 /bin/dbus-daemon --system --address=systemd: --nofork --systemd-activation
| + 1216 /usr/sbin/modem-manager
| + 1219 /usr/libexec/polkit-1/polkitd
| + 1242 /usr/sbin/wpa_supplicant -c /etc/wpa_supplicant/wpa_supplicant.conf -B -u -f /var/log/wpa_supplicant.log -P /var/run/wpa_supplicant.pid
| + 1453 /usr/libexec/upowerd
| + 1733 /usr/libexec/udisks-daemon
| + 1747 udisks-daemon: polling /dev/sr0
| \ 29509 /usr/libexec/packagekitd
+ dev-mqueue.mount
+ dev-hugepages.mount
\ sysinit.service
+ 455 /sbin/udevd -d
+ 4016 /usr/sbin/bluetoothd --udev
+ 28188 /sbin/udevd -d
\ 28191 /sbin/udevd -d
(이것도 같은 방식으로 줄였습니다)
보시다시피 이 명령은 systemd가 서비스 다음에 cgroup에 레이블을 지정하므로 해당 cgroup 및 서비스별로 프로세스를 표시합니다. 예를 들어 감사 서비스 auditd.service가 auditd, audisp 및 sedispatch의 세 가지 개별 프로세스를 생성한다는 것을 쉽게 알 수 있습니다.
자세히 살펴보면 cgroup/user/1 에 여러 프로세스가 할당 되었음을 알 수 있습니다. 이 시점에서 단순히 cgroup의 서비스를 유지 관리 할뿐만 아니라 사용자 세션 프로세스도 systemd에 그대로 둡니다. 나중에 우리는 이것에 대해 더 자세히 논의 할 것입니다.
감사합니다. 다음 기사로 곧 돌아 오겠습니다.
(원문: http://0pointer.de/blog/projects/systemd-for-admins-3.html)
(SysV Init 스크립트를 systemd 서비스 파일로 어떻게 변환합니까?)
전통적으로 Unix 및 Linux 서비스(데몬)는 SysV init 스크립트를 통해 시작됩니다. 이들은 Bourne Shell 스크립트로, 일반적으로 /etc/rc.d/init.d/와 같은 디렉토리에 있으며서 start, stop 또는 restart와 같은 몇 가지 표준화된 인수(동사) 중 하나를 사용하여 호출되어 제어됩니다 (예: 해당 서비스의 시작, 중지 또는 재시작). 시작의 경우 일반적으로 데몬 바이너리를 호출한 다음 백그라운드 프로세스를 포크합니다 (더 정확하게는 데몬화). 쉘 스크립트는 느리고, 불필요하게 읽기 어렵고, 매우 장황하고 깨지기 쉬운 경향이 있습니다. 엄청나게 유연하지만 (결국 코드일뿐) 패럴라이즈된 실행 순서 지정, 프로세스를 올바르게 감독하거나 실행 컨텍스트를 모든 세부 사항으로 구성하는 것과 같이 쉘 스크립트로 제대로 수행하기가 매우 어렵습니다. systemd는 이러한 쉘 스크립트와의 호환성을 제공하지만 지적된 단점으로 인해 설치된 모든 데몬에 대해 기본 systemd 서비스 파일을 설치하는 것이 좋습니다. 또한 배포 시스템 서비스 파일에 맞게 조정해야하는 SysV init 스크립트와는 달리 systemd를 실행하는 모든 종류의 배포와 호환됩니다 (요즘 점점 더 많아지고 있습니다...). 다음은 SysV 초기화 스크립트를 가져 와서 기본 시스템 서비스 파일로 변환하는 방법에 대한 간결한 가이드입니다. 이상적으로는 업스트림 프로젝트는 tarball에 systemd 서비스 파일을 제공하고 설치해야합니다. 지침에 따라 SysV 스크립트를 성공적으로 변환한 경우 파일을 패치로 업스트림에 제출하는 것이 좋습니다. 그와 같은 패치를 준비하는 방법은 나중에 논의 될 것입니다. 이 시점에서는 systemd와 함께 제공되어 이와 관련된 많은 유용한 정보가 포함되어 있는 daemon (7) 메뉴얼 페이지면 충분하다 여깁니다.
이제 바로 시작해 보겠습니다. 예를 들어 ABRT 데몬의 init 스크립트를 systemd 서비스 파일로 변환합니다. ABRT는 모든 Fedora 설치의 표준 구성 요소이며 자동 버그보고 도구의 머리 글자이며 이 도구가 수행하는 작업을 거의 설명합니다. 즉, 크래시 덤프를 수집하는 서비스입니다. 여기에 업로드한 SysV 스크립트입니다
그러한 스크립트를 변환할 때 첫 번째 단계는 그것을 읽고 (놀랍게도!) 일반적으로 꽤 긴 스크립트에서 유용한 정보를 추출하는 것입니다. 거의 모든 경우 스크립트는 모든 init 스크립트에서 동일하거나 적어도 매우 유사한 대부분의 상용구 코드로 구성되며 일반적으로 하나에서 다른 스크립트로 복사하여 붙여 넣습니다. 따라서 위에 링크된 스크립트에서 흥미로운 정보를 추출해 보겠습니다:
서비스에 대한 설명 문자열은 "충돌 앱을 감지하는 데몬" 입니다. 결과적으로 헤더 주석에는 중복된 수의 설명 문자열이 포함되어 있으며, 그중 일부는 실제 서비스를 덜 설명하지만 시작하는 초기화 스크립트입니다. systemd 서비스에는 설명도 포함되며 서비스 파일이 아닌 서비스를 설명해야합니다.
LSB 헤더[1]에는 종속성 정보가 포함됩니다. 소켓 기반 활성화를 중심으로한 설계로 인해 systemd는 일반적으로 수동으로 구성된 종속성이 필요하지 않거나 거의 필요하지 않습니다 (소켓 활성화에 대한 자세한 내용은 원본 공지 블로그 게시물 참조). 이 경우 $syslog (abrtd에 syslog 데몬이 필요함을 인코딩 함) 에 대한 종속성은 유일한 귀중한 정보입니다. 헤더에 다른 종속성 ($local_fs)이 나열되어 있지만 일반 시스템 서비스는 항상 사용 가능한 모든 로컬 파일 시스템으로 시작되므로 systemd와 중복됩니다.
LSB 헤더는 이 서비스가 런레벨 3 (다중 사용자) 및 5 (그래픽)에서 시작되어야한다고 제안합니다.
데몬 바이너리는 /usr/sbin/abrtd 입니다.
그리고 그것은 이미 그것입니다. 이 115 줄 셸 스크립트의 나머지 전체 내용은 단순히 상용구 또는 중복 코드입니다: 동기화 및 직렬화 시작 (예: 잠금 파일 관련 코드)을 처리하거나 상태 메시지를 출력하는 코드 (예: 에코를 호출하는 코드) 또는 단순히 동사의 구문 분석 (예: 큰 케이스 블록).
위에서 추출한 정보에서 이제 systemd 서비스 파일을 작성할 수 있습니다:
[Unit]
Description=Daemon to detect crashing apps
After=syslog.target
[Service]
ExecStart=/usr/sbin/abrtd
Type=forking
[Install]
WantedBy=multi-user.target
이 파일의 내용에 대한 간단한 설명: [Unit] 섹션에는 서비스에 대한 일반 정보가 포함되어 있습니다. systemd는 시스템 서비스뿐만 아니라 장치, 마운트 지점, 타이머 및 기타 시스템 구성 요소도 관리합니다. systemd에서 이러한 모든 객체에 대한 일반 용어는 단위이며 [Unit] 섹션은 서비스뿐만 아니라 systemd가 유지하는 다른 단위 유형에도 적용할 수 있는 정보를 인코딩합니다. 이 경우 다음 unit 설정을 지정합니다: 설명 문자열을 설정하고 LSB에서 인코딩된 것과 유사하게 Syslog[2] 이후에 데몬이 시작되도록 구성합니다. 이 Syslog 종속성에 대해 systemd 단위 syslog.target에 After= 유형의 종속성을 만듭니다. 후자는 systemd의 특수 target unit이며 syslog 구현을 가져 오는 표준화된 이름입니다. 이러한 표준화된 이름에 대한 자세한 내용은 systemd.special(7)을 참조하십시오. After= 유형의 종속성은 제안된 순서만 인코딩하지만 abrtd가 있을때 실제로 syslog가 시작되지는 않습니다 - 이것은 우리가 원하는 것입니다, abrtd는 실제로 syslog가 없어도 잘 작동하기 때문입니다. 그러나 둘 다 시작되면(일반적으로 그러함) 이 종속성으로 제어되는 순서입니다.
다음 섹션은 서비스 자체에 대한 정보를 인코딩하는 [Service]입니다. 여기에는 서비스에만 적용되는 모든 설정이 포함되며 시스템에서 유지 관리하는 다른 종류의 유닛(마운트 포인트, 장치, 타이머 등)은 포함되지 않습니다. 여기에는 두 가지 설정이 사용됩니다. ExecStart= 서비스가 시작될 때 실행할 바이너리 경로를 사용합니다. 그리고 Type= 을 사용하여 서비스가 시작을 완료 했음을 초기화 시스템에 알리는 방법을 구성합니다. 전통적인 유닉스 데몬은 포크를 해제하고 백그라운드 데몬을 초기화한 후 부모 프로세스로 돌아가 이를 수행하므로 여기서 유형을 포크로 설정합니다. 이는 systemd가 시작 바이너리가 반환될 때 까지 기다린 다음 데몬 프로세스 이후에 여전히 실행중인 프로세스를 고려하도록 지시합니다.
마지막 섹션은 [Install]입니다. 제안된 설치의 모양, 즉 어떤 상황에서 서비스가 시작되는 트리거에 대한 정보를 인코딩합니다. 이 경우 단순히 multi-user.target 유닛이 활성화되면 이 서비스가 시작된다고 말합니다. 이것은 기본적으로 클래식 SysV Runlevel 3 [3]의 역할을 수행하는 특수 유닛(위 참조)입니다. WantedBy= 설정은 런타임 동안 데몬에 거의 영향을 주지 않습니다. systemctl enable 명령으로만 읽을 수 있으며 이는 systemd에서 서비스를 활성화하는데 권장되는 방법입니다. 이 명령은 단순히 multi-user.target이 요청 되자마자 우리의 작은 서비스가 자동으로 활성화되도록 보장합니다. 이것은 모든 정상적인 부팅에 있습니다 [4].
그게 답니다. 이제 최소한의 작동 시스템 서비스 파일이 이미 있습니다. 테스트를 위해 /etc/systemd/system/abrtd.service에 복사하고 systemctl daemon-reload를 호출합니다. 이렇게하면 systemd가 이를 인식하게되며, 이제 systemctl start abrtd.service로 서비스를 시작할 수 있습니다. systemctl status abrtd.service를 통해 상태를 확인할 수 있습니다. 그리고 systemctl stop abrtd.service를 통해 다시 중지할 수 있습니다. 마지막으로 활성화 할 수 있으므로 향후 부팅시 systemctl enable abrtd.service로 기본적으로 활성화됩니다.
위의 서비스 파일은 충분하고 기본적으로 SysV init 스크립트의 1:1 번역 (기능 및 기타)이지만 여전히 개선의 여지가 있습니다. 여기에 약간 업데이트되었습니다:
[Unit]
Description=ABRT Automated Bug Reporting Tool
After=syslog.target
[Service]
Type=dbus
BusName=com.redhat.abrt
ExecStart=/usr/sbin/abrtd -d -s
[Install]
WantedBy=multi-user.target
그래서 우리는 무엇을 바꿨습니까? 두가지입니다: 설명 문자열을 약간 개선했습니다. 그러나 더 중요한 것은 서비스 유형을 dbus로 변경하고 서비스의 D-Bus 버스 이름을 구성했습니다. 우리는 왜 이것을 했습니까? 언급했듯이 고전적인 SysV 서비스는 시작후 데몬 화되며 일반적으로 모든 터미널에서 이중 분기 및 분리가 포함됩니다. 데몬이 스크립트를 통해 호출 될 때 유용하고 필요하지만 systemd와 같은 적절한 프로세스 베이비 시터를 사용할 때는 비생산적 일뿐만 아니라 불필요하고 느립니다. 그 이유는 분기된 데몬 프로세스가 일반적으로 systemd에 의해 시작된 원래 프로세스와 거의 관련이 없기 때문입니다 (모든 데몬화 계획의 전체 아이디어는 이 관계를 제거하는 것입니다), 따라서 systemd가 분기 후에 파악하기가 어렵기 때문입니다. 서비스에 속하는 어떤 프로세스가 실제로 주 프로세스이고 어떤 프로세스가 보조일 수 있는지 완료됩니다. 그러나 이 정보는 프로세스 감독, 비정상 종료시 자동 리스폰, 수집 충돌 및 종료 코드 정보 등과 같은 고급 베이비 시팅을 구현하는 데 중요합니다. systemd가 데몬의 주요 프로세스를 쉽게 파악할 수 있도록 서비스 유형을 dbus로 변경했습니다. 이 서비스 유형의 의미는 초기화의 마지막 단계로 D-Bus 시스템 버스에서 이름을 취하는 모든 서비스에 적합합니다 [5]. ABRT는 그중 하나입니다. 이 설정을 사용하면 systemd는 ABRT 프로세스를 생성하여 더 이상 포크하지 않으며 (이는 데몬으로의 -d -s 스위치를 통해 구성됨) systemd는 com.redhat.abrt가 버스에 나타나는 즉시 서비스가 완전히 시작된 것으로 간주합니다. 이런 식으로 systemd에 의해 생성된 프로세스는 데몬의 주요 프로세스이며, systemd는 데몬이 완전히 시작된 시기를 파악할 수 있는 신뢰할 수 있는 방법을 가지고 있으며 systemd는 이를 쉽게 감독할 수 있습니다.
그게 전부입니다. 이제 115로 인코딩 된 원래 SysV init 스크립트보다 더 많은 정보를 10 줄로 인코딩하는 간단한 시스템 서비스 파일이 있습니다. 그리고 지금도 더 많은 시스템 제공 기능을 활용하여 추가 개선을위한 여지가 많이 남아 있습니다. 예를 들어 Restart=restart-always를 설정하여 이 서비스가 종료되면 자동으로 다시 시작하도록 systemd에 알릴 수 있습니다. 또는 OOMScoreAdjust=-500을 사용하여 OOM 킬러가 혼란을 일으킬때 이 프로세스를 종료하도록 커널에 요청할 수 있습니다. 또는 CPUSchedulingPolicy=idle을 사용하여 abrtd가 백그라운드에서만 크래시 덤프를 처리하도록하여 커널이 항상 실행 중이고 CPU 시간이 필요한 다른 항목에 우선권을 부여할 수 있습니다.
여기에 언급 된 구성 옵션에 대한 자세한 내용은 해당 매뉴얼 페이지를 참조하십시오. systemd.unit(5), systemd.service(5), systemd.exec(5). 또는 [모든 systemd의 man 페이지]((http://0pointer.de/public/systemd-man/)를 찾아 보십시오.
물론 모든 SysV 스크립트가 이 스크립트만큼 쉽게 변환되는 것은 아닙니다. 그러나 다행스럽게도 대다수가 실제로 그렇습니다.
오늘은 여기까지입니다. 시리즈의 다음 편을 위해 곧 돌아오겠습니다.
[1] 초기화 스크립트의 LSB 헤더는 SysV 초기화 스크립트 상단의 주석 블록에 서비스에 대한 메타 데이터를 포함하는 규칙이며 Linux Standard Base에 의해 정의 됨. 이것은 배포판 간의 초기화 스크립트를 표준화하기위한 것입니다. 대부분의 배포판에서 이 체계를 채택했지만 헤더 처리는 배포판마다 크게 다르며 실제로 모든 배포판에 대해 init 스크립트를 조정해야합니다. 따라서 LSB 사양은 약속을 지키지 않았습니다.
[2] 엄밀히 말하면 이 종속성은 Syslog 데몬이 소켓 활성화가 가능한 시스템에서 중복되기 때문에 여기에서 인코딩할 필요조차 없습니다. 최신 syslog 시스템 (예: rsyslog v5)은 소켓 활성화가 가능하도록 업스트림 패치되었습니다. 그러한 초기화 시스템이 사용되는 경우 After=syslog.target 종속성의 구성은 중복되고 암시 적입니다. 그러나 업데이트되지 않은 syslog 서비스와의 호환성을 유지하기 위해 여기에 이 종속성을 포함합니다.
[3] 적어도 Fedora에서 정의되던 방법.
[4] systemd에서 그래픽 부트업 (graphical.target, SysV 런레벨 5의 역할을 맡음)은 콘솔 전용 부트업 (다중 사용자 대상, 즉 런레벨 3과 유사)의 암시적 수퍼 세트입니다. 즉, 서비스를 후자에 연결하면 전자에 연결됩니다.
[5] Actually the majority of services of the default Fedora install now take a name on the bus after startup.
실제로 기본 Fedora 설치의 대부분의 서비스는 이제 시작후 버스에서 이름을 사용합니다.
(원문: http://0pointer.de/blog/projects/systemd-for-admins-4.html)
시스템 데몬을 죽이는것은 쉽죠? 아니면?
물론 데몬이 단일 프로세스만 지속하는한 실제로는 다소 사실 일 수 있습니다. killall rsyslogd를 입력하면 syslog 데몬이 사라집니다. 그러나 불운한 사용자가 우연히 그렇게 이름을 지었을 수도 있는 프로세스를 포함하여 이와 같이 호출되는 모든 프로세스를 종료한다는 점을 감안할 때 그렇게하는 것은 약간 더럽습니다. 약간 더 정확한 버전은 .pid 파일을 읽는 것입니다. 즉cat /var/run/syslogd.pid
를 죽이는 것입니다. 그것은 이미 우리에게 훨씬 더 많이 주지만 정말 이것이 우리가 원하는 것입니까?
실제로는 그렇지 않은 경우가 많습니다. 일반적인 작업의 일부로 자식 프로세스를 생성하는 Apache, crond 또는 atd와 같은 서비스를 고려하십시오. cron 또는 at 작업, CGI 스크립트, 전체 애플리케이션 서버와 같은 임의의 사용자 구성 가능한 하위 프로세스. 메인 apache/crond/atd 프로세스를 죽이면 자식 프로세스도 풀다운 될 수도 있고 풀다운되지 않을 수도 있으며, 그 프로세스가 주변에 머무르거나 중단할 것인지 여부는 해당 프로세스에 달려 있습니다. 기본적으로 이는 Apache를 종료하면 CGI 스크립트가 계속 유지되고 init의 자식으로 재 할당되고 추적하기가 어려울 수 있음을 의미합니다.
systemd to the rescue: systemctl kill을 사용하면 서비스의 모든 프로세스에 신호를 쉽게 보낼 수 있습니다. 예:
# systemctl kill crond.service
이렇게하면 SIGTERM이 주요 프로세스뿐만 아니라 crond 서비스의 모든 프로세스에 전달됩니다. 물론 원하는 경우 다른 신호를 보낼 수도 있습니다. 예를 들어, 당신이 나쁜놈이라면 즉시 SIGKILL로 가고 싶을 수 있습니다:
# systemctl kill -s SIGKILL crond.service
그리고 당신이 가면, 서비스는 이중 포크 또는 포크 폭격으로 감독을 피하려고 시도했는지 여부에 관계없이 몇 번이나 포크했는지에 관계없이 전체적으로 잔인하게 학살됩니다.
때로는 SIGHUP를 통해 재로드를 트리거하기를 원하기 때문에 서비스의 주요 프로세스에 특정 신호를 보내는 것뿐입니다. PID 파일을 사용하는 대신 다음을 수행하는 더 쉬운 방법이 있습니다:
# systemctl kill -s HUP --kill-who=main crond.service
다시 말하지만, systemd에서 서비스를 죽이는 것에 대해 새롭고 멋진 것은 무엇입니까? 글쎄요, 리눅스에서 처음으로 우리는 실제로 제대로 할 수 있습니다. 이전 솔루션은 항상 데몬이 스스로 종료하면 생성된 모든 것을 제거하기 위해 실제로 협력하는 데몬에 의존했습니다. 그러나 일반적으로 SIGTERM 또는 SIGKILL을 사용하려는 경우 실제로 적절하게 협력하지 않기 때문에 그렇게하는 것입니다.
이것이 systemctl stop과 어떤 관련이 있습니까? kill은 직접 이동하여 그룹의 모든 프로세스에 신호를 보내지 만 stop은 서비스를 종료하기 위해 공식적으로 구성된 방식을 거칩니다. 즉, 서비스 파일에서 ExecStop= 으로 구성된 중지 명령을 호출합니다. 일반적으로 중지하면 충분합니다. kill은 서비스의 공식적인 종료 명령이 실행되는 것을 원하지 않거나 다른 방식으로 서비스가 중단되고 중단되는 경우에 더 어려운 버전입니다.
(-s 스위치에 SIG 접두사를 포함하거나 포함하지 않고 신호 이름을 지정하는 것은 BTW의 몫입니다. 둘 다 작동합니다.)
우리가 서비스를 제대로 종료 할 수 없는 상태에서 지금까지 Linux에 도달했다는 것은 약간 놀랍습니다. systemd를 사용하면 이 작업을 제대로 수행할 수 있습니다.
(원문: http://0pointer.de/blog/projects/three-levels-of-off)
("Off"의 세가지 레벨들)
systemd에는 서비스 (또는 다른 장치)를 끄는 세 가지 수준이 있습니다. 어떤 것이 있는지 살펴 보겠습니다:
서비스를 중지 할 수 있습니다. 이는 단순히 서비스의 실행중인 인스턴스를 종료하고 다른 작업은 거의 수행하지 않습니다. 어떤 형태의 활성화 (수동 활성화, 소켓 활성화, 버스 활성화, 시스템 부팅 활성화 또는 하드웨어 플러그 활성화)로 인해 서비스가 다시 요청되면 서비스가 시작됩니다. 따라서 서비스 중지는 매우 간단하고 일시적이며 피상적인 작업입니다. 다음은 NTP 서비스에 대해이 작업을 수행하는 방법의 예입니다:
$ systemctl stop ntpd.service
이는 대부분의 SysV 기반 시스템에서 사용할 수 있는 다음과 같은 기존 명령과 거의 동일합니다:
$ service ntpd stop
실제로 Fedora 15에서 후자의 명령을 실행하면 투명하게 전자로 변환됩니다.
서비스를 비활성화 할 수 있습니다. 이렇게하면 활성화 트리거에서 서비스의 후크가 해제됩니다. 즉, 서비스에 따라 더 이상 부팅시, 소켓 또는 버스 활성화 또는 하드웨어 플러그 (또는 이에 적용되는 다른 트리거)에 의해 활성화되지 않습니다. 그러나 원하는 경우 수동으로 시작할 수 있습니다. 이미 시작된 인스턴스가 있는 경우 서비스를 비활성화해도 서비스를 중지하는 효과가 없습니다. 다음은 서비스를 비활성화하는 방법의 예입니다:
$ systemctl disable ntpd.service
전통적인 Fedora 시스템에서 이것은 대략 다음 명령과 동일합니다:
$ chkconfig ntpd off
그리고 여기에서도 Fedora 15에서 후자의 명령은 필요한 경우 투명하게 전자로 변환됩니다.
종종 서비스 중지 및 비활성화를 결합하여 현재 인스턴스를 제거하고 다시 시작되지 않도록합니다 (수동으로 트리거된 경우 제외):
$ systemctl disable ntpd.service
$ systemctl stop ntpd.service
이와 같은 명령은 예를 들어 Fedora에서 systemd 서비스의 패키지 제거 중에 사용됩니다.
서비스 비활성화는 영구적인 변경입니다. 실행을 취소 할 때까지 재부팅 후에도 유지됩니다.
서비스를 숨길 수 있습니다. 이것은 서비스를 비활성화하는 것과 비슷하지만 스테로이드에 있습니다. 서비스가 더 이상 자동으로 시작되지 않도록 할뿐만 아니라 서비스가 더 이상 수동으로 시작되지 않도록합니다. 이것은 일반적으로 유용하지 않고 사용자를 혼란스럽게 할 수 있기 때문에 systemd의 숨겨진 기능 중 일부입니다. 하지만 방법은 다음과 같습니다:
$ ln -s /dev/null /etc/systemd/system/ntpd.service
$ systemctl daemon-reload
서비스 파일을 /dev/null에 심볼릭 링크하면 systemd에게 해당 서비스를 시작하지 않고 실행을 완전히 차단하도록 지시합니다. /etc/systemd/system에 저장된 유닛 파일은 동일한 이름을 가진 /lib/systemd/system의 파일을 재정의합니다. 전자 디렉토리는 관리자 영역이고 후자는 패키지 관리자의 테러 영역입니다. /etc/systemd/system/ntpd.service에 심볼릭 링크를 설치하여 systemd가 업스트림 제공 서비스 파일 /lib/systemd/system/ntpd.service를 읽지 않도록합니다.
systemd는 /dev/null에 심볼릭 링크된 단위를 인식하고 마스크된 것으로 표시합니다. 이러한 서비스를 수동으로 시작하려고하면 (예: systemctl start를 통해) 오류와 함께 실패합니다.
SysV 시스템에 대한 유사한 트릭은 (공식적으로) 존재하지 않습니다. 그러나 init 스크립트를 편집하고 맨 위에 exit 0을 배치하거나 실행 비트를 제거하는 것과 같은 몇 가지 비공식적인 해킹이 있습니다. 그러나 이러한 솔루션에는 다양한 단점이 있습니다. 예를 들어 패키지 관리자를 방해합니다.
서비스 마스킹은 서비스 비활성화와 마찬가지로 영구적인 변경입니다.
세 가지 수준에서 서비스를 끄는 방법을 배웠으므로 이제 한 가지 질문만 남았습니다. 다시 켜려면 어떻게해야합니까? 음, 그것은 상당히 대칭적입니다. systemctl start를 사용하여 systemctl stop을 실행 취소합니다. systemctl enable을 사용하여 systemctl disable을 실행 취소하고 rm을 사용하여 ln을 실행 취소합니다.
지금은 그게 다입니다. 관심을 가져 주셔서 감사합니다!
(원문: http://0pointer.de/blog/projects/changing-roots.html)
관리자 또는 개발자로서 조만간 chroot() 환경을 살펴볼 것입니다. chroot() 시스템 호출은 프로세스와 모든 자식이 루트 디렉토리 / 를 고려하는 것을 단순히 이동시켜 프로세스가 파일 계층 구조에서 볼 수 있는 것을 하위 트리로 제한합니다. 주로 chroot() 환경에는 두 가지 용도가 있습니다.
고전적인 System-V 기반 운영 체제에서는 chroot() 환경을 사용하는 것이 비교적 쉽습니다. 예를 들어 chroot() 기반 게스트 OS 트리 내에서 테스트 또는 기타 이유로 특정 데몬을 시작하려면 /proc, /sys 및 몇 가지 다른 API 파일 시스템을 트리에 마운트한 다음 chroot(1)를 사용하여 다음을 chroot 입력합니다. 그리고 마지막으로 chroot 내부에서 /sbin/service 를 통해 SysV init 스크립트를 실행합니다.
시스템 기반 OS에서는 더 이상 쉽지 않습니다. systemd의 큰 장점중 하나는 모든 데몬이 서비스 시작을 요청하는 사용자의 컨텍스트와 전혀 관련이 없는 완전하고 독립적인 컨텍스트에서 호출된다는 것입니다. sysvinit 기반 시스템에서는 리소스 제한, 환경 변수 등과 같은 실행 컨텍스트의 상당 부분이 init skript를 호출하는 사용자 셸에서 상속되지만 systemd에서는 사용자가 init 데몬에 알림만 보내면 init 데몬이 정상적이고 잘 정의된 원시 실행 컨텍스트에서 데몬을 분기하고 사용자 컨텍스트 매개 변수의 상속이 발생하지 않습니다. 이것은 강력한 기능이지만 실제로는 chroot() 환경 내에서 서비스를 호출하는 기존의 접근 방식을 깨뜨립니다. 실제 데몬은 항상 PID 1 에서 생성되어 그로부터 chroot() 설정을 상속하기 때문에 클라이언트가 다음을 수행하는지 여부는 관련이 없습니다. 데몬 시작 요청이 chroot()ed 여부입니다. 게다가 systemd는 실제로 로컬 통신 소켓을 /run/systemd 에 배치하기 때문에 chroot() 환경의 프로세스는 init 시스템과 통신할 수도 없습니다 (하지만 이는 아마도 좋은 일이며 대담하게 물론 bind 마운트를 사용하여 이 문제를 해결하십시오)
이것은 물론 시스템 환경에서 어떻게 chroot()를 올바르게 사용하는지에 대한 의문을 열어줍니다. 다음은 이 질문에 대해 완전하고 포괄적으로 답변해 드릴 수 있도록 우리가 고안 한 것입니다:
첫 번째 사용 사례를 먼저 살펴 보겠습니다. 보안을 위해 데몬을 chroot() 감옥에 잠그는 것입니다. 우선 보안 도구로서의 chroot()는 실제로는 매우 모호합니다. chroot()는 일방 통행로가 아니기 때문입니다. man 페이지에서도 지적했듯이 chroot() 환경에서 벗어나는 것은 비교적 쉽습니다. 몇 가지 다른 기술과 결합해야만 다소 안전할 수 있습니다. 그로 인해 일반적으로 변조 방지 방식으로 자체적으로 chroot()하려면 응용 프로그램에서 특정 지원이 필요합니다. 또한 일반적으로 chroot() 환경을 올바르게 설정하려면 chroot()ed 서비스에 대한 깊은 이해가 필요합니다. 예를 들어 호스트 트리에서 마운트할 디렉토리를 알고 있어야 모든 통신 채널을 사용할 수 있습니다. 서비스에 실제로 필요한 chroot() 이를 종합하면 보안 목적을 위한 chroot()ing 소프트웨어는 거의 항상 데몬 자체의 C 코드에서 가장 잘 수행됩니다. 개발자는 chroot()를 적절하게 보호하는 방법과 chroot() 내에서 데몬에 필요한 최소한의 파일, 파일 시스템 및 디렉토리 집합이 무엇인지 가장 잘 알고 있습니다 (또는 최소한 가장 잘 알고 있어야 함). 요즘에는 많은 데몬이 이 작업을 수행 할 수 있지만, 안타깝게도 일반 Fedora 설치에서 기본적으로 실행되는 데몬은 Avahi와 RealtimeKit 두 가지만 수행합니다. 둘 다 똑같은 정말 똑똑한 친구가 쓴 것 같습니다. Chapeau! ;-) (시스템에서 ls -l /proc/*/root를 실행하여 쉽게 확인하십시오)
즉, systemd는 물론 특정 데몬을 chroot()하고 일반적인 도구를 사용하여 다른 데몬을 관리하는 방법을 제공합니다. 이는 systemd 서비스 파일의 RootDirectory= 옵션을 통해 지원됩니다. 예를 들면 다음과 같습니다:
[Unit]
Description=A chroot()ed Service
[Service]
RootDirectory=/srv/chroot/foobar
ExecStartPre=/usr/local/bin/setup-foobar-chroot.sh
ExecStart=/usr/bin/foobard
RootDirectoryStartOnly=yes
이 예에서 RootDirectory= 는 ExecStart= 로 지정된 데몬 바이너리를 호출하기 전에 chroot() 할 위치를 구성합니다. ExecStart= 에 지정된 경로는 chroot() 내부의 바이너리를 참조해야 합니다. 호스트 트리의 바이너리 경로가 아닙니다 (예: 이 예에서 실행된 바이너리는 호스트 OS에서 /srv/chroot/foobar/usr/bin/foobard로 표시됩니다). 데몬이 시작되기 전에 쉘 스크립트 setup-foobar-chroot.sh가 호출되는데, 그 목적은 필요에 따라 chroot 환경을 설정하는 것입니다. 즉, 서비스에 필요한 것에 따라 /proc 및 유사한 파일 시스템을 여기에 마운트합니다. RootDirectoryStartOnly= 스위치를 사용하면 ExecStart= 에 지정된 데몬만 chrooted되고 전체 OS 계층 구조에 액세스 해야하는 ExecStartPre= 스크립트가 아니라 거기에서 마운트 디렉토리를 바인딩할 수 있습니다. (이러한 스위치에 대한 자세한 내용은 각 man 페이지를 참조하십시오) /etc/systemd/system/foobar.service에 이와 같은 단위 파일을 배치하면 systemctl start foobar.service를 입력하여 chroot()ed 서비스를 시작할 수 있습니다. 그런 다음 systemctl status foobar.service로 검사 할 수 있습니다. 다른 서비스와 마찬가지로 관리자가 액세스 할 수 있으며, SysV와 달리 chroot()로 처리된다는 사실은 모니터링 및 제어 도구와 상호 작용하는 방식을 변경하지 않습니다.
최신 Linux 커널은 파일 시스템 네임 스페이스를 지원합니다. 이것들은 chroot()와 비슷하지만 훨씬 더 강력하며, chroot()와 같은 보안 문제를 겪지 않습니다. systemd는 단위 파일 자체에서 파일 시스템 네임 스페이스로 할 수 있는 작업의 하위 집합을 노출합니다. 종종 이것은 하위 디렉토리에 전체 chroot() 환경을 설정하는 것보다 유용하고 간단한 대안입니다. ReadOnlyDirectories= 및 InaccessibleDirectories= 스위치를 사용하여 서비스에 대한 파일 시스템 네임 스페이스 감옥을 설정할 수 있습니다. 처음에는 호스트 OS의 파일 시스템 네임 스페이스와 동일합니다. 이러한 지시문에 디렉토리를 나열하면 호스트 OS의 특정 디렉토리 또는 마운트 지점을 읽기 전용으로 표시하거나 데몬에 완전히 액세스 할 수 없는 것으로 표시 할 수 있습니다. 예:
[Unit]
Description=A Service With No Access to /home
[Service]
ExecStart=/usr/bin/foobard
InaccessibleDirectories=/home
이 서비스는 한 가지 예외를 제외하고 호스트 OS의 전체 파일 시스템 트리에 액세스 할 수 있습니다. /home은 볼 수 없으므로 잠재적인 악용자로부터 사용자 데이터를 보호합니다. (이러한 옵션에 대한 자세한 내용은 man 페이지를 참조하십시오.)
사실 파일 시스템 네임 스페이스는 여러면에서 chroot()를 더 잘 대체합니다. 결국 Avahi와 RealtimeKit은 chroot()s를 대체하는 네임 스페이스를 사용하도록 업데이트 해야합니다.
보안 사용 사례에 대한건 너무 많습니다. 이제 디버깅, 테스트, 빌드, 설치 또는 복구를 위한 OS 이미지 설정 및 제어와 같은 다른 사용 사례를 살펴 보겠습니다.
chroot() 환경은 상대적으로 간단한 것입니다. 파일 시스템 계층 구조만 가상화합니다. chroot()를 서브 디렉토리에 삽입함으로써 프로세스는 여전히 모든 시스템 호출에 대한 완전한 액세스 권한을 가지며 모든 프로세스를 종료하고 실행중인 호스트와 다른 모든 것에 대해 공유 할 수 있습니다. 따라서 chroot() 내에서 OS (또는 OS의 작은 부분)를 실행하는 것은 위험한 일입니다. 호스트와 게스트 간의 격리는 파일 시스템으로 제한되고 다른 모든 것은 chroot() 내에서 자유롭게 액세스 할 수 있습니다. 예를 들어, chroot() 내부의 배포판을 업그레이드하고 패키지 스크립트가 SIGTERM을 PID 1로 전송하여 init 시스템의 재실행을 트리거하면 실제로 호스트 OS에서 발생합니다! 또한 SysV 공유 메모리, 추상 네임 스페이스 소켓 및 기타 IPC 기본 요소는 호스트와 게스트간에 공유됩니다. OS 테스트, 디버깅, 빌드, 설치 또는 복구를 위해 완전히 안전한 격리는 필요하지 않을 수 있지만 chroot() 환경 내에서 호스트 OS의 우발적인 수정을 방지하기위한 기본 격리가 바람직합니다: 호스트 OS를 방해 할 수 있는 코드 패키지 스크립트가 실행되는 것을 알 수 없습니다.
이 용도로 chroot() 설정을 처리하기 위해 systemd는 몇 가지 기능을 제공합니다:
우선, systemctl은 chroot에서 실행될 때를 감지합니다. 그렇다면 systemctl enable 및 systemctl disable을 제외한 대부분의 작업은 NOP가 됩니다. 따라서 패키지 설치 스크립트가 이 두 명령을 호출하면 게스트 OS에서 서비스가 활성화됩니다. 그러나 패키지 설치 스크립트에 패키지 업그레이드 프로세스의 일부로 systemctl restart와 같은 명령이 포함되어 있으면 chroot() 환경에서 실행될 때 전혀 영향을 미치지 않습니다.
그러나 더 중요한 것은 systemd가 스테로이드에서 chroot(1) 역할을 하는 systemd-nspawn 도구와 함께 기본 제공됩니다: 파일 시스템 및 PID 네임 스페이스를 사용하여 파일 시스템 트리에서 간단한 경량 컨테이너를 부팅합니다. 호스트 OS로부터의 격리가 훨씬 더 완전하고 훨씬 더 안전하며 사용하기 더 쉽다는 점을 제외하면 chroot(1)와 거의 비슷하게 사용할 수 있습니다. 실제로 systemd-nspawn은 단일 명령으로 컨테이너에서 완전한 systemd 또는 sysvinit OS를 부팅 할 수 있습니다. PID를 가상화하기 때문에 컨테이너의 init 시스템은 PID 1로 작동 할 수 있으므로 정상적으로 작동합니다. chroot(1)와 달리 이 도구는 암시적으로 /proc, /sys를 마운트합니다.
다음은 nspawn 컨테이너 내부의 Fedora 시스템에서 세 가지 명령으로 Debian OS를 부팅하는 방법의 예입니다:
# yum install debootstrap
# debootstrap --arch=amd64 unstable debian-tree/
# systemd-nspawn -D debian-tree/
이것은 OS 디렉토리 트리를 부트스트랩한 다음 그 안에 쉘을 호출합니다. 컨테이너의 전체 시스템을 부팅하려면 다음과 같은 명령을 사용하십시오:
# systemd-nspawn -D debian-tree/ /sbin/init
그리고 빠른 부팅 후에는 전체 OS 내에서 컨테이너에서 부팅된 셸 프롬프트가 표시되어야합니다. 컨테이너는 외부의 프로세스를 볼 수 없습니다. 네트워크 구성을 공유하지만 수정할 수는 없습니다. (부팅중에 몇 개의 EPERM이 예상되지만 치명적이지는 않습니다.) /sys 및 /proc/sys와 같은 디렉토리는 컨테이너에서 사용할 수 있지만 컨테이너가 커널 또는 하드웨어 구성을 수정할 수 없도록 읽기 전용으로 마운트됩니다. 그러나 이렇게하면 매개 변수가 실수로 변경되는 경우에만 호스트 OS를 보호 할 수 있습니다. 컨테이너의 프로세스는 읽기-쓰기 가능한 파일 시스템을 수동으로 다시 마운트한 다음 변경하려는 항목을 변경할 수 있습니다.
그래서, systemd-nspawn의 또 다른 장점은 무엇입니까?
정말 사용하기 쉽습니다. /proc 및 /sys를 chroot() 환경에 수동으로 마운트할 필요가 없습니다. 도구가 이를 수행하고 컨테이너가 종료되면 커널이 자동으로 정리합니다.
격리는 훨씬 더 완벽하여 컨테이너 내부에서 우발적인 변경으로부터 호스트 OS를 보호합니다.
단일 셸이 아니라 컨테이너에서 전체 OS를 실제로 부팅 할 수 있다는 점이 너무 좋습니다.
실제로는 작고 systemd가 설치된 모든 곳에 설치됩니다. 복잡한 설치나 설정이 없습니다.
systemd 자체는 그러한 컨테이너에서 매우 잘 작동하도록 수정되었습니다. 예를 들어, 종료하고 컨테이너에서 실행되는 것을 감지하면 마지막 단계로 reboot() 대신 exit()를 호출합니다.
systemd-nspawn은 전체 컨테이너 솔루션이 아닙니다. 필요한 경우 LXC가 더 나은 선택입니다. 동일한 기본 커널 기술을 사용하지만 네트워크 가상화를 포함하여 더 많은 것을 제공합니다. 그렇다면 systemd-nspawn은 컨테이너 솔루션의 GNOME 3입니다. 매끄럽고 사용하기 쉽지만 구성 옵션이 거의 없습니다. LXC OTOH는 KDE와 비슷합니다. 코드 줄보다 구성 옵션이 더 많습니다. 저는 특별히 테스트, 디버깅, 빌드, 설치, 복구를 다루기 위해 systemd-nspawn을 작성했습니다. 그것이 당신이 그것을 사용해야하는 것과 그것이 정말로 잘하는 것, 그리고 그것이 chroot(1)에 대한 훨씬 더 좋은 대안인 곳입니다.
자, 이것을 끝내도록합시다. 이것은 이미 충분히 길었습니다. 이 작은 블로그 이야기에서 집으로 가져갈 내용은 다음과 같습니다:
보안 chroot()는 프로그램의 C 소스에서 기본적으로 가장 잘 수행됩니다.
ReadOnlyDirectories=, InaccessibleDirectories= 는 전체 chroot() 환경에 대한 적절한 대안일 수 있습니다.
RootDirectory=는 특정 서비스를 chroot ()하려는 경우 친구입니다.
systemd-nspawn은 멋지게 만들어졌습니다.
chroot()는 불충분하고 파일 시스템 네임 스페이스는 완전히 엘리트(l33t, 신조어) 입니다.
이 모든 것은 Fedora 15 시스템에서 쉽게 사용할 수 있습니다.
오늘은 여기까지입니다. 다음 편에서 다시 만나요.
(원문: http://0pointer.de/blog/projects/blame-game.html)
Fedora 15[1]는 스포츠 시스템에 대한 첫 번째 Fedora 릴리스입니다. F15의 주요 목표는 모든 것을 통합하고 잘 작동시키는 것이 었습니다. Fedora 16의 한 가지 초점은 현재 배포판에 있는 내용을 더욱 다듬고 속도를 높이는 것입니다. 이주기를 준비하기 위해 몇 가지 도구 (이미 F15에서 사용 가능)를 구현했습니다.이 도구를 사용하면 부팅시 가장 큰 문제가 정확히 어디에 남아 있는지 정확히 파악할 수 있습니다. 이 블로그 스토리를 통해 느린 부팅에 대한 책임이 무엇인지, 그리고 이에 대해 어떻게 해야하는지 알아 내고 싶습니다. 우리는 당신이 책임이 있는 시스템 구성 요소에 대한 책임을 비난할 수 있기를 원합니다.
첫 번째 유틸리티는 매우 간단합니다: systemd는 부팅이 끝나면 syslog/kmsg에 필요한 시간과 함께 로그 메시지를 자동으로 작성합니다.
systemd[1]: Startup finished in 2s 65ms 924us (kernel) + 2s 828ms 195us (initrd) + 11s 900ms 471us (userspace) = 16s 794ms 590us.
그리고 이것을 읽는 방법은 다음과 같습니다. 초기 RAM 디스크 (initrd, 즉 dracut)가 시작될 때까지 커널 초기화에 2초가 소요되었습니다. 3초 미만이 initrd에 사용되었습니다. 마지막으로 사용자 공간을 불러 오기 위해 initrd가 실제 시스템 초기화 데몬 (systemd)을 호출한 후 12초 미만이 소요되었습니다. 부트 로더가 커널 코드에 뛰어든 후 systemd가 부팅 할 때 필요한 모든 작업을 완료 할 때까지 경과한 시간을 합하면 17초도 안됩니다. 이 숫자는 이해하기 쉽고 이해하기 쉬우며 오해하기도 쉽습니다. 그놈 세션을 초기화하는데 소요된 시간은 init 시스템의 범위를 벗어나므로 포함되지 않습니다. 또한 대부분의 경우 시스템이 필요한 모든 작업을 마친 곳입니다. 이 시간이 경과하면 일부 데몬은 시작을 완료하기 위해 필요한 모든 작업을 수행 하느라 바쁠 것입니다. 따라서 여기에 기록된 시간은 일반적인 부팅 속도에 대한 좋은 지표이지만 사용자가 실제로 부팅하는데 걸리는 시간은 아닙니다.
또한 이것은 매우 피상적인 가치입니다. 어떤 시스템 구성 요소가 항상 기다리고 있었는지에 대한 통찰력을 제공하지 않습니다. 이 문제를 해결하기 위해 systemd-analyze blame 도구를 도입했습니다:
$ systemd-analyze blame
6207ms udev-settle.service
5228ms cryptsetup@luks\x2d9899b85d\x2df790\x2d4d2a\x2da650\x2d8b7d2fb92cc3.service
735ms NetworkManager.service
642ms avahi-daemon.service
600ms abrtd.service
517ms rtkit-daemon.service
478ms fedora-storage-init.service
396ms dbus.service
390ms rpcidmapd.service
346ms systemd-tmpfiles-setup.service
322ms fedora-sysinit-unhack.service
316ms cups.service
310ms console-kit-log-system-start.service
309ms libvirtd.service
303ms rpcbind.service
298ms ksmtuned.service
288ms lvm2-monitor.service
281ms rpcgssd.service
277ms sshd.service
276ms livesys.service
267ms iscsid.service
236ms mdmonitor.service
234ms nfslock.service
223ms ksm.service
218ms mcelog.service
...
이 도구는 부팅시 초기화를 완료하는데 얼마나 많은 시간이 필요한 systemd 장치를 나열하며 가장 나쁜 공격자가 먼저 나열됩니다. 여기서 볼 수 있는 것은 이 부팅에서 두 서비스가 1초 이상의 부팅 시간을 필요로한다는 것입니다 : udev-settle.service 및 cryptsetup@luks\x2d9899b85d\x2df790\x2d4d2a\x2da650\x2d8b7d2fb92cc3.service. 이 도구의 출력은 쉽게 오해를받을 수 있습니다. 문제의 서비스가 실제로 이렇게 많은 시간을 필요로하는 이유를 밝히지 않고 단지 그렇게했다고 판단합니다. 또한 여기에 나열된 시간은 "병렬"로 소비될 수 있습니다. 즉, 두 서비스가 동시에 초기화될 수 있으므로 두 서비스를 모두 초기화하는데 소요되는 시간은 두 개별 시간을 합친 것보다 훨씬 적습니다.
이 부팅에서 최악의 공격자인 udev-settle.service라는 이름의 서비스를 자세히 살펴 보겠습니다: 그렇다면 초기화 하는데 시간이 그렇게 많이 걸리는 이유는 무엇이며 어떻게 해야할까요? 이 서비스는 실제로 거의 수행하지 않습니다. udev에 의해 수행되는 장치 검색이 완료될 때까지 기다린 다음 종료됩니다. 장치 검색이 느릴 수 있습니다. 예를 들어, 이 경우 장치가 6초 이상 걸리는 이유는 기기에 내장된 3G 모뎀 때문입니다. SIM 카드가 삽입되지 않은 경우 소프트웨어 프로브 요청에 응답하는데 이 시간이 오래 걸립니다. 소프트웨어 프로빙은 ModemManager가 작동하도록하고 NetworkManager가 쉬운 3G 설정을 제공할 수 있도록하는 로직의 일부입니다. 뻔한 반응는 이제 그렇게 느린 프로버를 가진 ModemManager를 비난하는 것일 수 있습니다. 그러나 그것은 실제로 잘못된 방향입니다. 하드웨어 프로빙은 상당히 느리고 ModemManager의 경우 3G 하드웨어가 이 정도 시간이 걸린다는 것은 단순한 사실입니다. 개별 프로버가 프로빙을 완료하는데 이 정도 시간이 걸릴 수 있는 적절한 하드웨어 프로빙 솔루션을 위한 필수 요구 사항입니다. 실제 범인은 다른 것입니다. 우리가 실제로 프로빙을 기다리고 있다는 사실, 즉 udev-settle.service가 부팅 프로세스의 일부라는 것입니다.
그렇다면 왜 udev-settle.service가 부팅 프로세스의 일부일까요? 글쎄, 실제로 그럴 필요는 없습니다. 이것은 Fedora의 스토리지 설정 로직에 의해 가져옵니다: 정확히 말하면 LVM, RAID 및 Multipath 설정 스크립트에 의해. 이러한 스토리지 서비스는 현재 하드웨어 감지 및 검색이 작동하는 방식으로 구현되지 않았습니다: "모든 장치가 검색된" 시점에서 초기화되어 사용 가능한 디스크 목록을 간단히 반복하고 수행할 수 있습니다. 그러나 현대 기계에서는 이것이 실제로 작동하는 방식이 아닙니다: 하드웨어가 올 수 있고 하드웨어가 부팅 중 및 런타임 중에 항상 이동할 수 있습니다. 일부 기술의 경우 장치 열거가 완료되는 시기를 알 수도 없으므로(예: USB 또는 iSCSI) 모든 저장 장치가 표시되고 검색 될 때까지 기다리는 것은 표시 될 수있는 모든 장치가 표시되고 검색되었다고 가정 할 때 반드시 고정 지연을 포함해야합니다. 이 경우 이 모든 것이 부팅 시간에 매우 부정적으로 표시됩니다. 스토리지 스크립트는 모든 잠재적 장치가 표시되고 모든 장치가 검색 될 때까지 부팅을 지연하도록합니다. 실제로 대부분의 장치가 필요하지 않더라도 모든 작업이 수행됩니다. 특히 이 시스템은 실제로 LVM, RAID 또는 다중 경로를 사용하지 않기 때문에! [2]
이제 우리가 알고있는 것을 알면 다음 부팅을 위해 udev-settle.service를 비활성화 할 수 있습니다. LVM, RAID 또는 Multipath를 사용하지 않기 때문에 문제의 서비스를 마스킹하여 부팅 속도를 약간 높일 수 있습니다:
# ln -s /dev/null /etc/systemd/system/udev-settle.service
# ln -s /dev/null /etc/systemd/system/fedora-wait-storage.service
# ln -s /dev/null /etc/systemd/system/fedora-storage-init.service
# systemctl daemon-reload
다시 시작한 후 부팅이 이제 약 1초 더 빠르다는 것을 측정할 수 있습니다. 왜 1초 입니까? 음, 두 번째로 최악의 공격자는 여기에서 cryptsetup입니다. 문제의 컴퓨터에는 암호화된 /home 디렉토리가 있습니다. 테스트 목적으로 디스크의 파일에 암호를 저장하여 사용자가 느린 typer이기 때문에 부팅이 지연되지 않도록했습니다. cryptsetup 도구는 안타깝게도 암호화 된 파티션을 설정하는데 더 많은 시간이 걸립니다. cryptsetup [3]을 수정하는 대신 게으르기 때문에 여기에 테이프를 붙여서 [4] : systemd 일반적으로 /etc/fstab에서 noauto 옵션으로 표시되지 않은 모든 파일 시스템이 나타나고, fsck되고 마운트 될 때까지 기다렸다가 부팅을 진행하고 일반적인 시스템 서비스를 시작합니다. /home의 경우 (예: /var와 달리) 매우 늦게 (즉, 사용자가 실제로 로그인 할 때) 필요하다는 것을 알고 있습니다. 따라서 쉬운 수정은 부팅 중에 이미 마운트 지점을 사용 가능하게하지만 실제로 cryptsetup, fsck 및 mount 실행이 완료될 때까지 기다리지 않는 것입니다. 파일 시스템을 실제로 마운트하기 전에 마운트 지점을 어떻게 사용할 수 있는지 물어 보시겠습니까? 글쎄, systemd는 /etc/fstab의 comment=systemd.automount 마운트 옵션의 형태로 마법의 힘을 가지고 있습니다. 이를 지정하면 systemd는 /home에 자동 마운트 지점을 만들고 파일 시스템에 처음 액세스 할 때 적절한 파일 시스템이 여전히 지원하지 않을 때 systemd는 장치를 기다렸다가 fsck하고 마운트합니다.
다음은 /etc/fstab을 변경한 결과입니다.
systemd[1]: Startup finished in 2s 47ms 112us (kernel) + 2s 663ms 942us (initrd) + 5s 540ms 522us (userspace) = 10s 251ms 576us.
좋습니다! 몇 가지 수정을 통해 부팅 시간을 거의 7초 단축했습니다. 그리고 이 두 가지 변경 사항은 가장 피상적인 두 가지 문제에 대한 수정일뿐입니다. 약간의 사랑과 세부적인 작업으로 개선할 여지가 많이 있습니다. 사실, 다른 컴퓨터에서 2년이 넘은 X300 노트북 (당시까지도 지구상에서 가장 빠른 컴퓨터는 아니 었습니다)과 약간의 정돈된 부분은 합리적으로 완전한 GENOME 시스템으로 부팅 시간이 약 4초(total)입니다. 그리고 그 안에 여전히 많은 공간이 있습니다.
systemd-analyze blame은 느린 서비스를 추적하기위한 훌륭하고 간단한 도구입니다. 그러나 큰 문제가 있습니다. 서비스의 병렬 실행이 실제로 느린 시작 서비스에 대해 지불하는 가격을 줄이는 방법을 시각화하지 않습니다. 이를 위해 우리는 시스템 분석 플롯을 준비했습니다. 다음과 같이 사용하십시오:
$ systemd-analyze plot > plot.svg
$ eog plot.svg
다른 서비스와 관련하여 서비스를 시작하는데 소요된 시간을 보여주는 예쁜 그래프를 생성합니다. 현재 어떤 서비스가 어떤 서비스를 기다리는지 명시적으로 시각화하지 않지만 약간의 추측 작업을 통해 쉽게 확인할 수 있습니다.
여기에 두 가지 작은 최적화의 효과를 확인하기 위해 시스템 분석 플롯으로 생성된 두 개의 그래프가 있습니다. 첫 번째 그래프는 변경 전과 후입니다:
(완전성을 위해 다음은 이 두 가지 부팅에 대한 systemd-analyze blame의 두 가지 완전한 출력입니다 : before and after)
지식이 풍부한 독자라면 이것이 Michael Meeks 'bootchart와 어떤 관련이 있는지 궁금해 할 것입니다. 이 플롯과 부트 차트는 유사한 그래프를 보여줍니다. Bootchart는 훨씬 더 강력한 도구입니다. 부팅 중에 일어나는 일, CPU 및 IO가 사용되는 양을 자세히 표시합니다. systemd-analyze 플롯은 더 높은 수준의 데이터를 보여줍니다. 어떤 서비스가 초기화하는 데 얼마나 많은 시간이 걸렸는지, 어떤 서비스를 기다려야하는지. 둘 다 함께 사용하면 부팅이 가능한 한 빠르지 않은 이유를 알아낼 수있는 멋진 도구 세트가 있습니다.
이제 이러한 도구를 사용하여 시스템에서 최악의 부팅 시간 위반자에 대해 버그를 신고하기 전에 다시 생각하십시오. 이러한 도구는 원시 데이터를 제공하므로 잘못 읽지 마십시오. 위의 최적화 예제에서 알 수 있듯이 느린 부팅에 대한 책임은 실제로 udev-settle.service가 아니고 ModemManager 프로버가 실행하는 것이 아닙니다. 이 서비스를 처음 도입한 것은 서브 시스템과 함께합니다. 그리고 그것이 문제를 해결해야하는 곳입니다. 따라서 올바른 위치에 버그를 제출하십시오. 비난이 속한 곳에 비난을 두십시오.
앞서 언급했듯이 이 세 가지 유틸리티는 기본적으로 Fedora 15 시스템에서 사용할 수 있습니다.
이 작은 블로그 스토리에서 집으로 가져갈 내용은 다음과 같습니다:
오늘은 여기까지 입니다. 관심을 가져 주셔서 감사합니다.
[1] 역대 최고의 자유 소프트웨어 OS 릴리스로도 알려져 있습니다.
[2] 여기서 올바른 해결책은 libudev 또는 이와 유사한 것을 통해 핫 플러그 이벤트를 적극적으로 수신하고 표시되는 장치에 대해 조치를 취하도록 해당 서비스를 개선하여 실제로 필요한 모든 것이 표시되는 즉시 부팅할 수 있도록하는 것입니다. 빠른 부팅을 얻으려면 모든 것이 아니라 실제로 진행해야하는 작업을 기다려야합니다. 또한 스토리지 서비스는 최신 동적 하드웨어에 잘 대처하지 못하는 유일한 서비스가 아니며 장치 목록이 정적이고 변경되지 않은 상태로 유지된다고 가정합니다. 예를 들어, 이 예에서 initrd가 실제로 느린 이유는 대부분 모든 비디오 장치가 표시되고 검색되었을때 Plymouth가 실행될 것으로 예상하기 때문입니다. 알수없는 이유로 (적어도 나에게 알려지지 않은) 인텔 그래픽 카드용 비디오 커널 모듈을 로드하는데 몇 초가 걸리므로 전체 부팅이 불필요하게 지연됩니다. (여기서도 나는 프로빙에 대한 책임이 아니라 진행하기 전에 완료될 때까지 기다린다는 사실에 책임이 있습니다)
[3] 글쎄요, 정확히 말하자면 저는 이 문제를 해결하려고 했습니다. 대부분의 crypsetup 지연은-내 눈에-cryptsetup의 --iter-time에 대한 불필요하게 높은 기본값 때문입니다. 나는 우리의 cryptsetup 관리자에게 여기서 기본값인 100ms가 1 초보다 안전하지 않다고 설득하려했지만 실패했습니다.
[4] 물론 문제를 고치는 대신 테이프로 테이프를 붙이는 것은 일반적으로 우리 스타일이 아니지만, 또 다른 멋진 시스템 기능을 과시할 수 있는 좋은 기회입니다.
(원문: http://0pointer.de/blog/projects/the-new-configuration-files)
systemd의 강력한 새 기능 중 하나는 단순하고 빠르며 병렬화 가능하며 강력한 C로 작성된 모듈식 초기 부팅 서비스의 완전한 세트와 함께 제공되어 이전에 등장했던 다양한 배포판의 쉘 "novels"를 대체한다는 것입니다. 우리의 작은 Project Zero Shell [1]은 완전히 성공했습니다. 현재 우리는 대부분의 데스크탑 및 임베디드 배포판에 필요한 거의 모든 것과 서버에 필요한 많은 부분을 다룹니다:
표준 Fedora 15 설치에서는 일부 레거시 및 스토리지 서비스에만 초기 부팅 중에 여전히 셸 스크립트가 필요합니다. 그것들이 필요하지 않다면 쉽게 비활성화 할 수 있습니다 (매일하는 것처럼). 쉘리스 부팅 systemd는 Linux에서 고유한 기능을 제공합니다.
이러한 작은 구성 요소의 대부분은 /etc의 구성 파일을 통해 구성됩니다. 이들 중 일부는 배포판간에 상당히 표준화되어 있으므로 C 구현에서 지원하는 것이 쉽고 분명했습니다. 예: /etc/fstab, /etc/crypttab 또는 /etc/sysctl.conf. 그러나 다른 사람들을 위해 우리가 지원하려는 배포판이 이러한 것들을 저장하는 다른 장소를 처리하기 위해 소스에 #ifdef orgies를 추가해야하는 표준화된 파일 또는 디렉토리가 존재하지 않았습니다. 이러한 모든 구성 파일은 매우 단순하다는 공통점이 있으며 배포판이 그들과 자신을 구별할 이유가 없습니다: 조금만 다를뿐 모두 매우 똑같은 일을 합니다.
상황을 개선하고 systemd의 통합된 힘의 이점을 누리기 위해 우리는 배포별 구성 파일을 폴백으로만 읽고 해당되는 경우 구성의 기본 소스로 새 구성 파일을 도입하기로 결정했습니다. 물론 가능하면 이러한 표준화된 구성 파일은 새로운 발명이 아니라 이전에 사용된 최상의 배포별 구성 파일의 표준화 일뿐입니다. 다음은 모든 배포판에서 systemd가 지원하는 새로운 공통 구성 파일에 대한 간략한 개요입니다:
구성 도구에서 이러한 새 구성 파일을 사용하도록 설득하는 것이 우리의 확실한 의도입니다. 구성 프런트 엔드가 이전 파일 대신 이러한 파일을 작성하면 자동으로 Linux 배포간에 더 이식 가능해지며 Linux 표준화를 돕습니다. 이를 통해 사용자와 관리자는 이해하기 쉽고 명확하게 이해할 수 있습니다. 물론 지금은 시스템 기반 배포판만이 파일을 읽지만, 이미 하나를 제외하고는 어떤 방식으로든 중요한 배포판을 모두 다루고 있습니다. 그리고 이것은 약간의 닭고기와 달걀 같은 문제입니다. 표준은 사용됨으로써 표준이 됩니다. 모든 사람이 이러한 파일을 표준화하도록 부드럽게 추진하기 위해 조만간 systemd 에서 이전 구성 파일에 대한 대체 지원을 중단할 계획임을 분명히하고 싶습니다. 이는 이 새로운 계획의 채택이 천천히 그리고 하나씩 이루어질 수 있음을 의미합니다. 그러나 한 세트의 구성 파일만 갖는 최종 목표는 명확해야 합니다.
이러한 구성 파일의 대부분은 구성 도구뿐만 아니라 업스트림 프로젝트(때로는 주로)와도 관련이 있습니다. 예를 들어 Mono, Java 또는 WINE과 같은 프로젝트를 초대하여 업스트림 빌드 시스템에서 /etc/binfmt.d/에 drop-in 파일을 설치합니다. 바이너리 형식에 대한 배포별 다운 스트림 지원은 더 이상 필요하지 않으며 플랫폼은 모든 배포에서 동일하게 작동합니다. 예를 들어 /run 계층 구조 아래 (예: /var/run으로 알려져 있음)와 같이 부팅시 특정 런타임 파일 및 디렉토리를 생성/정리 해야하는 모든 소프트웨어에 유사한 내용이 적용됩니다. 이러한 프로젝트는 업스트림 빌드 시스템에서도 /etc/tmpfiles.d의 구성 파일에 드롭해야 합니다. 바이너리 형식 등록 또는 부팅시 임시/휘발성 파일 제거/생성과 같은 사소한 작업을 구현하는 별도의 프로젝트 별 SysV 셸 스크립트가 더 이상 필요하지 않기 때문에 부팅 프로세스 속도를 높이는데도 도움이 됩니다. 또는 업스트림 지원이 환상적일 수 있는 또 다른 예: X11과 같은 프로젝트는 /etc/vconsole.conf에서 디스플레이에 대한 기본 키보드 매핑을 읽는 것이 도움이 될 수 있습니다.
물론 모든 사람이 이러한 구성 파일의 이름 (및 형식) 선택에 만족하는 것은 아닙니다. 결국 우리는 무언가를 골라야했고, 모든 선택 중에서 가장 설득력이 있는 것 같았습니다. 파일 형식은 가능한 한 간단하며 일반적으로 쉘 스크립트에서도 쉽게 쓰고 읽을 수 있습니다. 즉, /etc/bikeshed.conf는 물론 환상적인 구성 파일 이름이 될 수도 있습니다!
그러니 리눅스 표준화를 도와주세요! 새 구성 파일을 사용하십시오! 업스트림을 채택하고 다운 스트림을 채택하고 배포 전반에 걸쳐 모두 채택하십시오!
Oh, and in case you are wondering: yes, all of these files were discussed in one way or another with various folks from the various distributions. And there has even been some push towards supporting some of these files even outside of systemd systems.
아, 그리고 궁금한 점이 있는 경우: 네, 이러한 모든 파일은 다양한 배포판의 다양한 사람들과 어떤식으로든 논의되었습니다. 그리고 심지어 systemd 시스템 외부에서도 이러한 파일중 일부를 지원하기위한 일부 추진이 있었습니다.
[1] 우리의 슬로건 : "부팅 중에 시작해야 할 유일한 쉘은 gnome-shell입니다!" - 예, 슬로건에는 약간의 작업이 필요하지만 아이디어를 얻습니다.
(원문: http://0pointer.de/blog/projects/on-etc-sysinit.html)
그래서, 여기에 다양한 배포판에 존재하는 /etc/sysconfig/ 및 /etc/default 디렉토리와 왜 그것들의 사용이 사라져야 한다고 생각하는지에 대한 약간의 의견이 있습니다. 이 블로그에서 제가 말하는 모든 내용과 마찬가지로 이어지는 내용은 복음이 아니라 제 개인적인 의견일 뿐이며 Fedora 프로젝트나 고용주의 입장과는 아무 관련이 없습니다. /etc/sysconfig에 대한 주제는 계속해서 논의되고 있습니다. 나는 이 블로그 이야기를 통해 우리가 이 파일들에 대해 어떻게 생각하는지 설명 할 수 있기를 바랍니다.
역사적 맥락에 대한 몇 줄 : /etc/sysconfig가 도입되었을 때는 없었습니다. 오랫동안 Red Hat 및 SUSE 배포판에서 사용되어 왔다고 말하면 충분합니다. 결국 /etc/default는 매우 유사한 의미를 가진 데비안에서 소개되었습니다. 다른 많은 배포판도 유사한 의미를 가진 디렉토리를 알고 있으며, 대부분은 이를 하나 또는 다른 방식으로 부릅니다. 사실, 다른 Unix-OS에서도 이와 같은 디렉토리를 자랑했습니다. (예: SCO. 자세한 내용에 관심이 있으시면 여러분이 신뢰하는 유닉스 할배(greybeard)로부터 제가 여기서 모호한 부분을 채울 수 있다고 확신합니다.) 따라서 이와 같은 디렉토리가 Linux 및 Unix에서 널리 알려져 있지만, POSIX 나 LSB/FHS에서 표준화된 적이 없습니다. 이 디렉토리는 배포판이 서로 구별되는 부분입니다.
/etc/default 및 /etc/sysconfig의 의미는 단지 매우 약한 정의 입니다. 이 디렉토리에 저장된 거의 모든 파일이 공통적으로 가지고있는 것은 주로 환경 변수 할당으로 구성된 sourcable 셸 스크립트라는 것입니다. 이러한 디렉토리에 있는 대부분의 파일은 동일한 이름의 SysV init 스크립트에서 제공됩니다. 데비안 정책 매뉴얼 (9.3.2)과 페도라 패키징 가이드 라인은 이러한 디렉토리 사용을 제안하지만, 두 배포판 모두 이 체계를 따르지 않는 파일을 가지고 있습니다. 즉, 일치하는 SysV init 스크립트가 없거나 심지어 쉘 스크립트이기도 합니다.
이러한 파일이 도입된 이유는 무엇일까요? SysV 시스템에서 서비스는 /etc/rc.d/init.d (또는 유사한 디렉토리)의 init 스크립트를 통해 시작됩니다. /etc/는 (당일) 시스템 구성이 저장되는 장소로 간주됩니다. 원래 이러한 초기화 스크립트는 관리자에 의해 사용자 정의되었습니다. 그러나 성장하고 복잡 해짐에 따라 대부분의 배포판은 더 이상 실제 구성 파일이 아니라 특별한 종류의 프로그램으로 간주되었습니다. 사용자 정의를 쉽게하고 안전한 업그레이드 경로를 보장하기 위해 사용자 정의 가능한 비트가 별도의 구성 파일로 이동되었으며 이 파일은 init 스크립트가 소스로 사용합니다.
이러한 파일로 어떤 종류의 구성을 수행할 수 있는지 간략히 살펴 보겠습니다. 다음은 Fedora와 Debian 컴퓨터의 디렉토리를 탐색하면서 찾은 이러한 소스 파일의 환경 설정을 통해 구성할 수 있는 다양한 항목에 대한 간단한 포괄적인 목록입니다:
Now, let's go where the beef is: what's wrong with /etc/sysconfig (resp. /etc/default)? Why might it make sense to fade out use of these files in a systemd world?
이제 불만이 있는 곳으로 갑시다: /etc/sysconfig (resp. /etc/default)에 무엇이 문제인가? 시스템화된 세계에서 이러한 파일의 사용이 사라져야 한다는 것이 합리적일 수 있는 이유는 무엇입니까?
이러한 파일의 대부분에 대한 이유는 더 이상 존재하지 않습니다. systemd 단위 파일은 SysV init 스크립트와 같은 프로그램이 아닙니다. 단위 파일은 간단하고 선언적인 설명이며 일반적으로 6줄 이상으로 구성되지 않습니다. Bourne 인터프리터 없이 쉽게 생성하고 구문 분석하고 독자가 이해할 수 있습니다. 또한 수정하기가 매우 쉽습니다. /lib/systemd/system에서 /etc/systemd/system으로 복사한 다음 패키지 관리자가 수정하지 않는 곳에서 편집하면 됩니다. systemd 단위 파일에는 코드가 포함되어 있지 않기 때문에 이러한 파일을 도입한 원래 이유였던 코드와 구성을 분리할 필요가 더 이상 없습니다. 따라서 이러한 파일은 이제 더 이상 존재하지 않는 문제를 찾는 솔루션입니다.
본질적으로 배포판에 따라 다릅니다. systemd를 통해 우리는 배포판 간의 표준화를 권장합니다. 이것의 일부는 단위 파일이 패키지 프로그램에 의해 추가되는 것이 아니라 업스트림과 함께 제공되기를 원한다는 것입니다. 일반적으로 SysV 세계에서 수행되는 방식입니다. 디렉토리의 위치와 파일에서 사용 가능한 변수는 배포마다 매우 다르기 때문에 업스트림 단위 파일에서 /etc/sysconfig 파일을 지원하는 것은 불가능합니다. 이러한 파일에 저장된 구성은 Linux 플랫폼의 균형 해제에 대해 작동합니다.
시스템화된 세계에서 많은 설정이 완전히 중복됩니다. 예를 들어 다양한 서비스는 사용자/그룹 ID, 리소스 제한, CPU 선호도 또는 OOM 조정 설정과 같은 프로세스 자격 증명의 구성을 지원합니다. 그러나 이러한 설정은 일부 SysV init 스크립트에서만 지원되며 여러 스크립트에서 지원되는 경우 이름이 다른 경우가 많습니다. systemd의 OTOH 에서 이러한 모든 설정은 유닛 파일의 동일한 구성 옵션을 사용하여 모든 서비스에 대해 동일하고 균일하게 사용할 수 있습니다.
유닛 파일은 대부분의 /etc/sysconfig 파일이 제공하는 것보다 더 포괄적인 사용하기 쉬운 많은 프로세스 컨텍스트 설정을 알고 있습니다.
이러한 설정중 다수는 전적으로 의문의 여지가 있습니다. 예를 들어 서비스가 실행되는 사용자/그룹 ID에 대한 앞서 언급한 구성 옵션은 주로 배포자가 처리해야하는 사항입니다. 관리자가 이러한 설정을 변경할 수 있는 것은 거의 없으며 배포 자만이 UID/GID 및 이름 충돌이 발생하지 않도록하는 광범위한 개요를 가지고 있습니다.
파일 형식이 이상적이지 않습니다. 파일은 일반적으로 쉘 스크립트로 제공되기 때문에 구문 분석 오류는 해독하기가 매우 어렵고 서비스의 다른 구성 문제와 함께 기록되지 않습니다. 일반적으로 알려지지 않은 변수 할당은 효과가 없지만 경고하지 않습니다. 이로 인해 이러한 파일은 필요 이상으로 디버깅하기가 더 어렵습니다.
쉘 스크립트의 구성 파일 소스는 인터프리터의 실행 매개 변수의 영향을받으며 다음과 같은 많은 항목이 있습니다: IFS 또는 LANG와 같은 설정은 쉘 스크립트가 구문 분석되고 이해되는 방식을 대폭 수정하는 경향이 있습니다. 이것은 그들을 연약하게 만듭니다.
이러한 파일의 해석은 부팅시 생성될 각 서비스에 대해 하나 이상의 프로세스를 추가하는 셸을 생성해야하기 때문에 느립니다.
종종 /etc/sysconfig의 파일은 구성 파일을 기본적으로 지원하지 않는 데몬의 구성 파일을 "속이는데" 사용됩니다. 이는 데몬에 전달되는 이러한 변수 할당에서 명령줄 인수를 함께 붙여서 수행됩니다. 일반적으로 이러한 데몬의 기본 구성 파일은 훨씬 더 예쁜 솔루션입니다. "-k", "-a" 또는 "-f"와 같은 명령줄 옵션은 자명하지 않으며 매우 복잡한 구문을 가지고 있습니다. 더욱이 많은 데몬의 동일한 스위치는 (제한된 어휘로 인해) 종종 매우 모순되는 효과를 갖습니다. (한 데몬에서 -f 로 인해 데몬이 데몬화되고 다른 데몬에서는 이 옵션이 정확히 이 동작을 해제합니다) 일반적으로 명령줄에는 대부분의 구성 파일이 할 수 있는 적절한 주석이 포함될 수 없습니다.
/etc/sysconfig의 많은 구성 설정은 완전히 중복됩니다. 예를 들어, 많은 배포판에서 RTC가 UTC 또는 현지 시간인지 여부에 관계없이 /etc/sysconfig 파일을 통해 제어할 수 있습니다. 그러나 이러한 옵션은 이미 /etc/adjtime의 세 번째 줄에 있습니다 (모든 배포판에서 알려져 있음). 따라서 이를 재정의하는 두 번째 중복된 배포별 옵션을 추가하는 것은 불필요하며 이점이 없는 상황을 복잡하게 만듭니다.
/etc/sysconfig의 많은 구성 설정은 서비스 비활성화를 허용합니다. 이것에 의해 그들은 기본적으로 init 시스템이 이미 제공하는 것보다 두 번째 수준의 활성화/비활성화가 됩니다: 이 설정에서 systemctl enable 또는 chkconfig를 사용하여 서비스를 활성화하면 이를 무시하고 init 시스템이 시작하도록 구성 되었더라도 데몬을 설정합니다. 물론 이것은 사용자/관리자에게 매우 혼란스럽고 사실상 이점을 제공하지 않습니다.
로드할 정적 커널 모듈 구성과 같은 옵션: 요즘에는 부팅시 커널 모듈을 로드하는 훨씬 더 좋은 방법이 있습니다. 예를 들어, 대부분의 모듈은 이제 올바른 하드웨어를 찾으면 udev에 의해 자동로드 될 수 있습니다. 이것은 매우 멀리 진행되며 ACPI 및 기타 고급 기술도 포함합니다. 현재 커널 모듈 자동로드를 수행하지 않는 몇 안되는 예외 중 하나는 CPU 기능 및 모델 기반 자동로드이지만 곧 지원 될 것입니다. 특정 모듈을 자동으로 로드할 수 없는 경우에도 일반적으로 정적으로 로드하는 더 좋은 방법이 있습니다. 예를 들어 관리자가 정적으로 로드된 모든 모듈에 대해 표준화된 위치를 확인할 수 있도록 /etc/load-modules.d 에 고정하는 방법이 있습니다.
마지막으로 /etc는 이미 시스템 구성 (FHS에 따른 "호스트 특정 시스템 구성")을위한 장소로 사용됩니다. 따라서 시스템 구성을 배치하기 위해 sysconfig라는 하위 디렉토리는 이미 언어 수준에서 완전히 중복됩니다.
대신 무엇을 사용해야합니까? 다음은 시스템화된 세계에서 장기적으로 이러한 파일로 수행할 작업에 대한 몇 가지 권장 사항입니다:
교체하지 않고 그냥 버리십시오. 완전히 중복된 경우 (로컬/UTC RTC 설정과 같이) 비교적 쉬운 방법이어야 합니다 (호환성에 대한 필요성을 무시 함). systemd가 기본적으로 유닛 파일에서 동등한 옵션을 지원하는 경우 sysconfig 파일에서 이러한 설정을 복제할 필요가 없습니다. 서비스에 대해 설정할 수 있는 실행 옵션 목록은 해당 매뉴얼 페이지 (systemd.exec(5) 및 systemd.service(5))를 확인하십시오. 설정이 단순히 서비스를 비활성화 할 수 있는 다른 레이어를 추가하는 경우 이를 제거하여 단순하게 유지하십시오. 서비스를 비활성화하기 위해 여러 가지 방법이 필요하지 않습니다.
그들에게 더 좋은 곳을 찾으십시오. 시스템 로케일 또는 시스템 시간대의 구성에 대해서는 배포를 올바른 방향으로 부드럽게 밀어 넣고 자합니다. 자세한 내용은 이 시리즈의 이전 에피소드를 참조하십시오.
이 설정을 데몬의 기본 설정으로 바꾸십시오. 필요한 경우 기본 구성 파일을 읽기위한 지원을 데몬에 추가합니다. 고맙게도 우리가 Linux에서 실행하는 대부분의 작업은 자유 소프트웨어이므로 비교적 쉽게 수행할 수 있습니다.
물론 이러한 파일을 조금 더 오래 지원하는 데에는 한 가지 좋은 이유가 있습니다. 바로 업그레이드 호환성입니다. 하지만 이것이 제가 생각 해낼 수 있는 유일한 방법입니다. 잠시 동안 호환성을 유지하는 데 충분한 이유이지만 최소한 새 패키지에서 이러한 파일의 사용을 단계적으로 중단하는 것이 좋습니다.
호환성이 중요한 경우 systemd는 기본 systemd 단위 파일을 사용하더라도 여전히 이러한 구성 파일을 읽을 수 있도록 허용합니다. sysconfig 파일이 간단한 옵션 만 알고있는 경우 EnvironmentFile=-/etc/sysconfig/foobar를 사용하여 설정을 환경으로 가져 와서 명령줄을 조합하는 데 사용할 수 있습니다. (이 옵션에 대한 자세한 내용은 systemd.exec (5)를 참조하십시오) 이러한 설정을 이해하기 위해 프로그래밍 언어가 필요하면 쉘과 같은 프로그래밍 언어를 사용하십시오. 예를 들어, 호환성을 위해 이 파일을 읽는 /usr/lib// 에 짧은 쉘 스크립트를 배치한 다음 exec는 실제 데몬 바이너리입니다. 그런 다음 유닛 파일에서 ExecStart= 를 사용하여 실제 데몬 바이너리 대신이 스크립트를 생성합니다.
오늘은 여기까지 입니다. 관심 가져 주셔서 감사합니다.
(원문: http://0pointer.de/blog/projects/instances.html)
(인스턴스화된 서비스)
Linux/Unix의 대부분의 서비스는 단일(singleton) 서비스입니다: 일반적으로 특정 시스템에서 동시에 실행되는 Syslog, Postfix 또는 Apache의 인스턴스는 하나만 있습니다. 반면에 일부 선택된 서비스는 동일한 호스트의 여러 인스턴스에서 실행될 수 있습니다. 예를 들어 Dovecot IMAP 서비스와 같은 인터넷 서비스는 다른 IP 포트 또는 다른 로컬 IP 주소의 여러 인스턴스에서 실행될 수 있습니다. 모든 설치에 존재하는보다 일반적인 예는 getty, 각 TTY에 대해 한 번 실행되고 로그인 프롬프트를 표시하는 미니 서비스입니다. 대부분의 시스템에서 이 서비스는 처음 6개의 가상 콘솔 tty1에서 tty6까지 각각 한 번씩 인스턴스화 됩니다. 관리자 구성 또는 부팅 시간 매개 변수에 따라 일부 서버에서는 직렬 또는 가상화 콘솔에 대해 추가 getty가 인스턴스화됩니다. systemd 세계에서 또 다른 일반적인 인스턴스화 서비스는 검사해야하는 각 블록 장치에 대해 한 번 인스턴스화되는 파일 시스템 검사기인 fsck입니다. 마지막으로, 시스템 소켓에서 활성화 된 연결 별 서비스 (클래식 inetd를 생각해보세요!)도 인스턴스화된 서비스를 통해 구현됩니다: 들어오는 연결마다 새 인스턴스가 생성됩니다. 이 기사에서는 systemd가 인스턴스화된 서비스를 구현하는 방법과 이를 관리자로서 활용하는 방법에 대해 설명하고자 합니다.
이 시리즈의 이전 에피소드를 살펴보면 systemd의 서비스 이름이 foobar.service 패턴에 따라 지정된다는 것을 알고있을 것입니다. 여기서 foobar는 서비스의 식별 문자열이고 .service는 모든 서비스 유닛들에 대해 동일한 고정 접미사입니다.이러한 서비스에 대한 정의 파일은 이 이름으로 /etc/systemd/system 및 /lib/systemd/system (및 가능한 다른 디렉토리)에서 검색됩니다. 인스턴스화된 서비스의 경우 이 패턴이 약간 확장됩니다. 서비스 이름은 foobar@quux.service가 됩니다. 여기서 foobar는 공통 서비스 식별자이고 quux는 인스턴스 식별자입니다. 예: serial-getty@ttyS2.service는 ttyS2에 대해 인스턴스화된 serial getty 서비스입니다.
서비스 인스턴스는 필요에 따라 동적으로 생성될 수 있습니다. 추가 구성없이 새 인스턴스에 대해 systemctl start 명령을 호출하여 직렬 포트에서 새 getty를 쉽게 시작할 수 있습니다:
# systemctl start serial-getty@ttyUSB0.service
위와 같은 명령이 실행되면 systemd는 먼저 요청한 정확한 이름으로 장치 구성 파일을 찾습니다. 이 서비스 파일을 찾을 수 없는 경우 (일반적으로 이와 같이 인스턴스화된 서비스를 사용하는 경우에는 해당되지 않음) 검색된 결과 템플릿 이름에 따라 이름 및 유닛 구성 파일에서 인스턴스 ID가 제거됩니다. 즉, 위의 예에서 정확한 serial-getty@ttyUSB0.service 유닛 파일을 찾을 수 없으면 serial-getty@.service가 대신 로드됩니다. 따라서 이 유닛 템플릿 파일은 이 서비스의 모든 인스턴스에 공통됩니다. 직렬 getty의 경우 다음과 같은 systemd (/lib/systemd/system/serial-getty@.service)에 템플릿 유닛 파일을 제공합니다:
[Unit]
Description=Serial Getty on %I
BindTo=dev-%i.device
After=dev-%i.device systemd-user-sessions.service
[Service]
ExecStart=-/sbin/agetty -s %I 115200,38400,9600
Restart=always
RestartSec=0
(실제로 serial gettys를 위해 systemd와 함께 제공되는 유닛 템플릿 파일은 약간 더 깁니다. 관심이 있으시면 SysV와의 호환성에 대한 추가 지시문이 포함된 실제 파일을 확인하여 화면을 지우고 TTY 장치에서 이전 사용자를 제거하십시오. 단순하게 유지하기 위해 여기에서 유닛 파일을 관련 줄로 줄였습니다)
이 파일은 대부분 다른 단위 파일과 비슷하지만 다음과 같은 차이점이 있습니다. 지정자 %I 및 %i는 여러 위치에서 사용됩니다. 유닛 로드 시간에 %I 및 %i는 서비스의 인스턴스 식별자로 systemd로 대체됩니다. 위의 예에서 서비스가 serial-getty@ttyUSB0.service로 인스턴스화되면 지정자 %I 및 %i는 ttyUSB0으로 대체됩니다. systemctl 상태 serial-getty@ttyUSB0.service로 인스턴스화된 장치를 검사하면 다음과 같은 교체가 수행된 것을 볼 수 있습니다:
$ systemctl status serial-getty@ttyUSB0.service
serial-getty@ttyUSB0.service - Getty on ttyUSB0
Loaded: loaded (/lib/systemd/system/serial-getty@.service; static)
Active: active (running) since Mon, 26 Sep 2011 04:20:44 +0200; 2s ago
Main PID: 5443 (agetty)
CGroup: name=systemd:/system/getty@.service/ttyUSB0
└ 5443 /sbin/agetty -s ttyUSB0 115200,38400,9600
그리고 그것은 이미 systemd에서 인스턴스화된 서비스의 핵심 아이디어입니다. 보시다시피 systemd는 필요에 따라 서비스를 동적으로 인스턴스화 하는데 사용할 수 있는 매우 간단한 템플릿 시스템을 제공합니다. 이를 효과적으로 사용하기 위해 몇 가지 참고 사항:
이러한 서비스는 파일 시스템의 .wants/ 심볼릭 링크에서 즉시 인스턴스화 할 수 있습니다. 예를 들어 ttyUSB0의 serial getty가 부팅할 때마다 자동으로 시작되도록하려면 다음과 같은 심볼릭 링크를 만듭니다:
# ln -s /lib/systemd/system/serial-getty@.service /etc/systemd/system/getty.target.wants/serial-getty@ttyUSB0.service
systemd는 심볼릭 링크 이름에 지정된 인스턴스 이름으로 심볼릭 링크된 유닛 파일을 인스턴스화합니다.
인스턴스 식별자를 지정하지 않으면 단위 템플릿을 인스턴스화 할 수 없습니다. 즉, 인스턴스 이름이 지정되지 않았기 때문에 systemctl start serial-getty@.service가 반드시 실패합니다.
특정 인스턴스에 대한 일반 템플릿을 opt-out하는 것이 유용할 때도 있습니다. 이러한 경우 systemd는 템플릿 파일 이름으로 돌아가기 전에 항상 전체 인스턴스 파일 이름을 먼저 검색한다는 사실을 활용하십시오: /etc/systemd/system에서 완전히 인스턴스화된 이름 아래에 유닛 파일을 배치해야 합니다. 그러면 이 특정 인스턴스에 대한 일반 템플릿 버전이 무시됩니다.
위에 표시된 유닛 파일은 일부 위치에서 %i를 사용하고 다른 위치에서 %I를 사용합니다. 이 지정자의 차이점이 무엇인지 궁금할 수 있습니다. %i는 인스턴스 식별자의 정확한 문자로 대체됩니다. 반면에 %I의 경우 인스턴스 식별자는 먼저 간단한 이스케이프 해제 알고리즘을 통해 전달됩니다. ttyUSB0과 같은 간단한 인스턴스 식별자의 경우 효과적인 차이가 없습니다. 그러나 장치 이름에 하나 이상의 슬래시 ("/")가 포함된 경우 이는 장치이름 (또는 Unix 파일 이름)의 일부가 될 수 없습니다. 이러한 장치 이름을 인스턴스 식별자로 사용하려면 먼저 "/"가 "-"가 되고 대부분의 다른 특수 문자 ("-"포함)가 "\xAB"로 대체되도록 이스케이프해야 합니다. 여기서 AB는 다음의 ASCII 코드입니다. 16진수 표기법의 문자 [1]. 예: 버스 경로로 USB 직렬 포트를 참조하려면 serial/by-path/pci-0000:00:1d.0-usb-0:1.4:1.1-port0과 같은 포트 이름을 사용합니다. 이 이름의 이스케이프된 버전은 serial-by\x2dpath-pci\x2d0000:00:1d.0\x2dusb\x2d0:1.4:1.1\x2dport0입니다. 그런 다음 %I는 전자를, %i는 후자를 참조합니다. 사실상 이것은 %i가 다른 유닛를 참조해야하는 경우에 유용하다는 것을 의미합니다 (예: 추가 종속성 표현). 반면에 %I는 명령줄에서 사용하거나 예쁜 설명 문자열에 포함하는데 유용합니다. 위의 유닛 파일로 이것이 어떻게 보이는지 확인해 봅시다:
# systemctl start 'serial-getty@serial-by\x2dpath-pci\x2d0000:00:1d.0\x2dusb\x2d0:1.4:1.1\x2dport0.service'
# systemctl status 'serial-getty@serial-by\x2dpath-pci\x2d0000:00:1d.0\x2dusb\x2d0:1.4:1.1\x2dport0.service'
serial-getty@serial-by\x2dpath-pci\x2d0000:00:1d.0\x2dusb\x2d0:1.4:1.1\x2dport0.service - Serial Getty on serial/by-path/pci-0000:00:1d.0-usb-0:1.4:1.1-port0
Loaded: loaded (/lib/systemd/system/serial-getty@.service; static)
Active: active (running) since Mon, 26 Sep 2011 05:08:52 +0200; 1s ago
Main PID: 5788 (agetty)
CGroup: name=systemd:/system/serial-getty@.service/serial-by\x2dpath-pci\x2d0000:00:1d.0\x2dusb\x2d0:1.4:1.1\x2dport0
└ 5788 /sbin/agetty -s serial/by-path/pci-0000:00:1d.0-usb-0:1.4:1.1-port0 115200 38400 9600
인스턴스 식별자는 이스케이프된 문자열인 반면 명령 줄과 설명 문자열은 실제로 예상대로 이스케이프되지 않은 버전을 사용합니다.
(참고: %i 및 %I보다 더 많은 지정자를 사용할 수 있으며, 대부분은 서비스 인스턴스용 템플릿뿐만 아니라 모든 유닛 파일에서 실제로 사용할 수 있습니다. 자세한 내용은 전체 목록과 간결한 설명이 포함된 man 페이지를 참조하십시오)
그리고 이 시점에서 이것이 전부가 될 것입니다. 인스턴스화된 서비스가 inetd 스타일 소켓 활성화에 사용되는 방법에 대한 후속 기사를 계속 지켜봐주십시오.
[1] Yupp, 이 이스케이프 알고리즘은 특히 예쁜 이스케이프 문자열을 생성하지는 않습니다. 다시 말하지만 대부분의 이스케이프 알고리즘은 가독성에 도움이되지 않습니다. 여기에서 사용한 알고리즘은 비슷한 경우에 udev가 한 가지 변경 사항으로 수행하는 작업에서 영감을 얻었습니다. 결국 우리는 무언가를 선택해야 했습니다. 이스케이프 알고리즘에 대해 언급할 생각이시라면 어디 사는지 말하십시오. 내가 돌아가 자전거 창고를 파란색 줄무니로 노란색 칠을 할 수 있게. 감사합니다!
(원문: http://0pointer.de/blog/projects/inetd.html)
이 시리즈의 이전 에피소드에서 SysV init 스크립트를 systemd 단위 파일로 변환하는 방법을 다루었습니다. 이 이야기에서는 inetd 서비스를 시스템 단위로 변환하는 방법을 설명하고자합니다.
약간의 배경 지식부터 시작하겠습니다. inetd는 고전적인 Unix 서비스중 하나로서 오랜 전통을 가지고 있습니다. 수퍼 서버로서 다른 서비스를 대신하여 인터넷 소켓에서 수신한 다음 들어오는 연결에서 해당 서비스를 활성화하여 주문형 소켓 활성화 시스템을 구현합니다. 이를 통해 제한된 리소스를 가진 Unix 시스템은 항상 프로세스를 실행하고 리소스를 모두 투자 할 필요없이 다양한 서비스를 제공할 수 있었습니다. 수년에 걸쳐 Linux 배포판에 inetd의 여러 독립적 구현이 제공되었습니다. 가장 눈에 띄는 것은 BSD inetd 및 xinetd를 기반으로 한 것입니다. inetd는 기본적으로 대부분의 배포판에 설치되어 있었지만, 요즘에는 선택된 서비스가 거의 없을 때만 사용되며 공통 서비스는 주로 (인식된) 성능상의 이유로 부팅시 무조건 실행됩니다.
systemd의 핵심 기능 중 하나는 소켓 활성화인데, 이는 inetd가 개척했지만 당시에는 다른 초점을 맞추 었습니다. 시스템 스타일 소켓 활성화는 둘 다 지원되지만 인터넷 소켓 (AF_INET)이 아닌 로컬 소켓 (AF_UNIX)에 초점을 맞춥니다. 더 중요한 것은 systemd의 소켓 활성화는 주로 inetd의 핵심이었던 on-demand 측면이 아니라 병렬화 (소켓 활성화를 통해 소켓의 클라이언트와 서버를 동시에 시작할 수 있음), 단순성 (소켓 활성화 이후 서비스간의 명시적 종속성을 구성할 필요가 제거됨) 및 견고성 (서비스를 다시 시작할 수 있거나 소켓 연결 손실없이 충돌할 수 있기 때문). 그러나 systemd는 이러한 방식으로 구성된 경우 연결이 수신될 때 요청시 서비스를 활성화 할 수도 있습니다.
모든 종류의 소켓 활성화에는 서비스 자체의 지원이 필요합니다. systemd는 sd_listen_fds()를 중심으로 구축된 소켓 활성화를 제공하기 위해 서비스가 구현할 수 있는 매우 간단한 인터페이스를 제공합니다. 따라서 이미 매우 최소한의 단순한 계획입니다. 그러나 전통적인 inetd 인터페이스는 훨씬 더 간단합니다. 활성화된 서비스에 단일 소켓만 전달할 수 있습니다. 소켓 fd는 생성된 프로세스의 STDIN 및 STDOUT에 간단히 복제되며 이미 완료되었습니다. 호환성을 제공하기 위해 systemd는 프로세스에 동일한 인터페이스를 선택적으로 제공하므로 이미 inetd 스타일 소켓 활성화를 지원하지만 아직 systemd의 기본 활성화는 지원하지 않는 많은 서비스를 활용합니다.
구체적인 예제를 계속하기 전에 소켓 활성화를 사용하기위한 세 가지 다른 방식을 살펴 보겠습니다:
병렬화, 단순성, 견고성을 위한 소켓 활성화: 소켓은 초기 부팅 중에 바인딩되며 모든 클라이언트 요청을 처리하는 싱글톤 서비스 인스턴스는 부팅시 즉시 시작됩니다. 이것은 자주 그리고 지속적으로 사용되는 모든 서비스에 유용하므로 시스템의 나머지 부분과 병행하여 초기에 시작하는 것이 좋습니다. 예: D-Bus, Syslog.
싱글톤 서비스에 대한 주문형(On-demand) 소켓 활성화: 소켓은 초기 부팅 중에 바인딩되며 수신 트래픽에서 싱글톤 서비스 인스턴스가 실행됩니다. 이는 거의 사용되지 않는 서비스에 유용하며, 부팅시 리소스와 시간을 절약하고 실제로 필요할 때까지 활성화를 지연하는 것이 좋습니다. 예: CUPS.
연결별 서비스 인스턴스에 대한 주문형(On-demand) 소켓 활성화: 소켓은 초기 부팅 중에 바인딩되며 들어오는 각 연결에 대해 새 서비스 인스턴스가 인스턴스화되고 연결 소켓(리스닝 소켓이 아님)이 여기에 전달됩니다. 거의 사용되지 않고 성능이 중요하지 않은 서비스에 유용합니다. 즉, 들어오는 연결마다 새로운 서비스 프로세스를 생성하는 비용이 제한되는 경우. 예: SSH.
세 가지 방식은 서로 다른 성능 특성을 제공합니다. 서비스 시작이 완료된후 처음 두 구성표에서 제공하는 성능은 독립형 서비스와 동일합니다. (예, 소켓 활성화없이 슈퍼 서버없이 시작되는 서버), 리스닝 소켓이 실제 서비스로 전달되고 그 이후의 코드 경로는 독립형 서비스의 경로와 동일하며 모든 연결은 독립형 서비스에서와 동일한 방식으로 프로세스가 됩니다. 반면에 세 번째 계획의 성능은 일반적으로 좋지 않습니다. 각 연결에 대해 새로운 서비스를 시작해야하기 때문에 리소스 비용이 훨씬 더 높습니다. 그러나 다음과 같은 여러 가지 이점도 있습니다: 예를 들어 클라이언트 연결이 더 잘 격리되고 이러한 방식으로 활성화된 서비스를 개발하는 것이 더 쉽습니다.
systemd의 경우 기본적으로 첫 번째 체계에 중점을 두지만 다른 두 체계도 지원됩니다. (사실 시스템 스타일 소켓 활성화에 필요한 코드 변경 사항을 다룬 블로그 스토리는 두 번째 유형의 서비스, 즉 CUPS에 관한 것입니다). inetd는 주로 세 번째 체계에 초점을 맞추지만 두 번째 체계도 지원됩니다. (첫 번째는 그렇지 않습니다. 아마도 세 번째 계획 inetd에 대한 초점이 "느린"것으로 명성을 얻었기 때문일 것입니다)
배경에 대해 너무 많이 살펴본것 같으니 이제 본론으로 들어가 inetd 서비스가 systemd의 소켓 활성화에 통합 될 수 있음을 보여 드리겠습니다. 우리는 널리 설치되고 사용되는 매우 일반적인 서비스인 SSH에 초점을 맞출 것입니다. 그러나 대부분의 머신에서 아마도 평균적으로 1/h 이상 (일반적으로 훨씬 더 적게) 시작되지 않을 것입니다. SSH는 위에서 언급한 세 번째 체계에 따라 오랫동안 inetd 스타일 활성화를 지원했습니다. 가끔씩만 시작되고 동시에 제한된 수의 연결로만 시작되기 때문에 추가 리소스 비용이 무시할 수 있으므로 이 체계에 대한 매우 좋은 후보입니다. 소켓 활성화 가능 SSH를 만들면 기본적으로 아무도 그것을 사용하지 않습니다. 그리고 누군가 SSH를 통해 로그인하자마자 시작되고 모든 리소스의 연결을 끊는 순간 다시 해제됩니다. 제공된 inetd 호환성을 활용하여 systemd에서 SSH 소켓을 활성화하는 방법을 알아 보겠습니다!
다음은 클래식 inetd와 SSH를 연결하는데 사용되는 설정 라인 입니다:
ssh stream tcp nowait root /usr/sbin/sshd sshd -i
그리고 xinetd 구성 조각과 동일합니다:
service ssh {
socket_type = stream
protocol = tcp
wait = no
user = root
server = /usr/sbin/sshd
server_args = -i
}
이 두 조각은 거의 동일한 정보를 표현하기 때문에 대부분은 이해하기 쉽습니다. 분명하지 않은 부분: 포트 번호(22)는 inetd 구성에서 구성되지 않지만 /etc/services의 서비스 데이터베이스를 통해 간접적으로 구성됩니다. 서비스 이름은 해당 데이터베이스에서 조회키로 사용되며 포트 번호로 변환됩니다. /etc/services를 통한이 간접적인 방법은 유닉스 전통의 일부 였지만 점점 더 유행에서 벗어나고 있습니다. 따라서 최신 xinetd는 명시적 포트 번호로 구성을 선택적으로 허용합니다. 여기서 가장 흥미로운 설정은 직관적으로 이름이 지정되지 않은 nowait (resp. wait=no) 옵션입니다. 서비스가 두 번째 (wait) 응답인지 여부를 구성합니다. 위에서 언급한 세 번째 (nowait) 계획. 마지막으로 -i 스위치는 SSH에서 inetd 모드를 활성화하는데 사용됩니다.
이러한 구성 조각의 체계적 변환은 다음 두 유닛입니다. 첫째: sshd.socket은 listen할 소켓에 대한 정보를 캡슐화하는 유닛입니다:
[Unit]
Description=SSH Socket for Per-Connection Servers
[Socket]
ListenStream=22
Accept=yes
[Install]
WantedBy=sockets.target
이것의 대부분은 자명해야합니다. 몇 가지 참고: Accept=yes는 nowait에 해당합니다. nowait의 경우 슈퍼 서버가 수신 소켓에서 accept()를 호출한다는 사실을 참조하면 더 나은 이름이 될 것입니다. 여기서 wait는 실행된 서비스 프로세스의 작업 입니다. WantedBy=sockets.target은 활성화 되었을때 이 장치가 부팅시 적시에 활성화되도록 하는데 사용됩니다.
다음은 일치하는 서비스 파일 sshd@.service입니다.
[Unit]
Description=SSH Per-Connection Server
[Service]
ExecStart=-/usr/sbin/sshd -i
StandardInput=socket
이것 역시 대부분 자명해야합니다. 흥미로운 것은 이 서비스에 대한 inetd 호환성을 활성화하는 옵션인 StandardInput=socket 입니다. StandardInput= 을 사용하여 이 서비스에 연결되어야하는 서비스의 STDIN을 구성할 수 있습니다 (자세한 내용은 man 페이지 참조). 소켓으로 설정하여 간단한 inetd 인터페이스에서 예상한 대로 여기에 연결 소켓을 전달합니다. 여기서 StandardOutput= 을 명시적으로 구성할 필요는 없습니다. 기본적으로 StandardInput= 의 설정은 아무것도 구성되지 않은 경우 상속되기 때문입니다. 중요한 것은 바이너리 이름 앞의 "-"입니다. 이렇게하면 systemd에서 연결별 sshd 프로세스의 종료 상태를 잊게됩니다. 일반적으로 systemd는 비정상적으로 종료되는 모든 서비스 인스턴스의 종료 상태를 저장합니다. SSH는 때때로 종료 코드 1 또는 이와 유사한 종료 코드로 비정상적으로 종료되며, 이로 인해 systemd가 이러한 방식으로 종료된 수많은 이전 연결에 대한 정보를 유지하지 않도록 해야합니다 (이 정보가 systemctl reset-failed로 잊혀질 때까지).
sshd@.service는 이 시리즈의 이전 기사에서 설명한대로 인스턴스화된 서비스입니다. 들어오는 각 연결에 대해 systemd는 연결 자격 증명의 이름을 따서 명명된 인스턴스 식별자를 사용하여 sshd@.service의 새 인스턴스를 인스턴스화합니다.
inetd 서비스의 systemd 구성에서 왜 하나가 아닌 두 개의 단위 파일이 필요한지 궁금할 것입니다. 그 이유는 단순화하기 위해 라이브 유닛과 유닛 파일 사이의 관계가 분명한지 확인하는 동시에 종속성 그래프에서 소켓 유닛과 서비스 유닛을 독립적으로 주문하고 유닛을 제어할 수 있기 때문입니다. 가능한 한 독립적으로. (생각: 이를 통해 인스턴스와 독립적으로 소켓을 종료하고 각 인스턴스를 개별적으로 종료할 수 있습니다)
이제 이것이 실제 생활에서 어떻게 작동하는지 봅시다. 이 파일들을 /etc/systemd/system에 놓으면 소켓을 활성화하고 시작할 준비가 된 것입니다:
# systemctl enable sshd.socket
ln -s '/etc/systemd/system/sshd.socket' '/etc/systemd/system/sockets.target.wants/sshd.socket'
# systemctl start sshd.socket
# systemctl status sshd.socket
sshd.socket - SSH Socket for Per-Connection Servers
Loaded: loaded (/etc/systemd/system/sshd.socket; enabled)
Active: active (listening) since Mon, 26 Sep 2011 20:24:31 +0200; 14s ago
Accepted: 0; Connected: 0
CGroup: name=systemd:/system/sshd.socket
이것은 소켓이 listening 중이며 지금까지 연결이 이루어지지 않았음을 나타냅니다.
(Accepted: 소켓이 시작된 이후 총 연결 수를 보여줍니다. Connected: 현재 활성화된 연결 수.)
이제 두 개의 다른 호스트에서 여기에 연결하고 현재 활성화된 서비스를 확인합니다:
$ systemctl --full | grep ssh
sshd@172.31.0.52:22-172.31.0.4:47779.service loaded active running SSH Per-Connection Server
sshd@172.31.0.52:22-172.31.0.54:52985.service loaded active running SSH Per-Connection Server
sshd.socket loaded active listening SSH Socket for Per-Connection Servers
예상대로 두 개의 연결에 대해 두 개의 서비스 인스턴스가 실행되고 있으며 TCP 연결의 소스 및 대상 주소와 포트 번호의 이름을 따서 명명됩니다. (AF_UNIX 소켓의 경우 인스턴스 식별자는 연결 클라이언트의 PID 및 UID를 전달합니다) 이를 통해 특정 클라이언트의 세션을 종료하려는 경우 특정 sshd 인스턴스를 개별적으로 검사하거나 종료 할 수 있습니다 :
# systemctl kill sshd@172.31.0.52:22-172.31.0.4:47779.service
그리고 그것은 아마도 이미 inetd 서비스를 systemd와 연결하고 나중에 사용하는 방법에 대해 알아야 할 대부분의 것입니다.
SSH의 경우 리소스를 이러한 종류의 inetd 스타일 소켓 활성화에 기본값으로 저장하기 위해 대부분의 배포판에 좋은 제안 일 수 있지만 선택적으로 활성화 할 수 있는 독립형 단위 파일도 sshd에 제공합니다. 곧 Fedora의 SSH 패키지에 대한 위시리스트 버그를 제출할 것입니다.
xinetd와 systemd가 기능을 비교하는 방법과 xinetd가 systemd에 의해 완전히 폐기되었는지 여부에 대한 몇 가지 최종 참고 사항입니다. 여기서 짧은 대답은 systemd가 전체 xinetd 기능 세트를 제공하지 않으며 xinetd가 완전히 구식이 아니라는 것입니다. 더 긴 대답은 조금 더 복잡합니다: xinetd가 제공하는 다양한 옵션을 살펴보면 systemd가 비교하지 않는다는 것을 알 수 있습니다. 예를 들어, systemd는 내장 에코, 시간, 주간 또는 폐기 서버를 제공하지 않으며 이러한 서버를 포함하지 않습니다. TCPMUX는 지원되지 않으며 RPC 서비스도 지원되지 않습니다. 그러나 이들중 대부분은 오늘날의 인터넷과 관련이 없거나 다른 방식으로 유행하지 않게된 것도 알 수 있습니다. 대부분의 inetd 서비스는 이러한 추가 기능을 직접 활용하지 않습니다. 사실, Fedora에 제공된 xinetd 서비스는 이러한 옵션을 사용하지 않습니다. 즉, systemd가 지원하지 않는 몇 가지 유용한 기능 (예: IP ACL 관리)이 있습니다. 그러나 대부분의 관리자는 방화벽이 이러한 종류의 문제에 대해 더 나은 솔루션이라는 데 동의 할 것이며, 그 외에도 systemd는 이와 같은 레트로 기술에 탐닉하는 사람들을 위해 tcpwrap을 통해 ACL 관리를 지원합니다. 반면에 systemd는 위에 표시된 인스턴스의 개별 제어 또는 인스턴스에 대한 실행 컨텍스트의 보다 표현적인 구성 가능성으로 시작하여 xinetd가 제공하지 않는 다양한 기능을 제공합니다. 나는 systemd가 제공하는 것이 매우 포괄적이고, 레거시 조각이 거의 없지만 필요한 모든 것을 제공해야한다고 믿습니다. 그리고 systemd가 다루지 않는 것이 있다면, xinetd는 systemd와 함께 쉽게 실행할 수 있기 때문에 항상 빈 공간을 채울 것입니다. 대부분의 경우 systemd는 필요한 것을 다루어야하며 시스템을 구축하는데 필요한 구성 요소를 줄일 수 있습니다. 어떤면에서 systemd는 고전적인 Unix inetd의 기능을 되돌리고 다시 Linux 시스템의 중심 부분으로 바꿉니다.
여기까지 입니다. 긴 글을 읽어 주셔서 감사합니다. 이제 가서 서비스를 전환하십시오! 더 좋은 점은 개별 패키지 업스트림 또는 배포에서 이 작업을 수행하는 것입니다!
(원문: http://0pointer.de/blog/projects/security.html)
Unix 시스템의 핵심 기능중 하나는 OS의 다른 구성 요소 간의 권한 분리 개념입니다. 많은 시스템 서비스는 자체 사용자 ID로 실행되므로 수행할 수 있는 작업을 제한하고 악용 될 경우 OS에 미칠 수 있는 영향을 제한합니다.
그러나 이러한 종류의 권한 분리는 매우 기본적인 보호만 제공합니다. 일반적으로 이런 방식으로 실행되는 시스템 서비스는 루트 만큼은 아니지만 최소한 일반 로컬 사용자만큼 많은 작업을 수행할 수 있기 때문입니다. 그러나 보안상의 이유로 서비스가 할 수 있는 일을 더 제한하고 일반 사용자가 할 수 있는 몇 가지 일을 차단하는 것은 매우 흥미 롭습니다.
서비스의 영향을 제한하는 가장 좋은 방법은 SELinux와 같은 MAC 기술을 사용하는 것입니다. 서버 보안에 관심이 있다면 SELinux를 실행하는 것이 좋습니다. systemd를 사용하면 개발자와 관리자가 MAC과 관계없이 로컬 서비스에 추가 제한을 적용 할 수 있습니다. 따라서 SELinux를 사용할 수 있는지 여부에 관계없이 서비스에 특정 보안 제한을 적용할 수 있습니다.
이 시리즈의 반복에서 우리는 systemd의 이러한 보안 기능 몇 가지와 서비스에서 이를 사용하는 방법에 초점을 맞추고 자합니다. 이러한 기능은 커널에서 오랫동안 사용할 수 있었지만 널리 사용 가능한 방식으로 노출된 적이 없는 몇 가지 Linux 관련 기술을 활용합니다. 이러한 시스템 기능은 관리자와 업스트림 개발자에게 매력적으로 보이도록 가능한 한 사용하기 쉽게 설계되었습니다:
여기에 설명된 모든 옵션은 systemd의 man 페이지, 특히 systemd.exec(5)에 문서화되어 있습니다. 자세한 내용은 이 매뉴얼 페이지를 참조하십시오.
이러한 모든 옵션은 SELinux 또는 기타 MAC의 활성화 여부에 관계없이 모든 시스템 시스템에서 사용할 수 있습니다.
이 모든 옵션은 비교적 저렴하므로 의심스러운 경우 사용하십시오. 서비스가 /tmp에 쓰지 않아서 PrivateTmp=yes (아래 설명)를 활성화 할 필요가 없다고 생각할 수도 있지만, 오늘날의 복잡한 소프트웨어로 인해 이 기능을 활성화하는 것이 좋습니다. 사용자가 제어하지 않는 라이브러리에 링크 (및 해당 라이브러리에 대한 플러그인)는 결국 임시 파일이 필요할 수 있기 때문입니다. 예: 로컬 설치가 활성화한 NSS 모듈의 종류와 NSS 모듈이 /tmp로 무엇을 하는지 알 수 없습니다.
이러한 옵션은 관리자가 로컬 시스템을 보호하고 업스트림 개발자가 기본적으로 서비스를 안전하게 제공하는데 모두 흥미로울 것입니다. 업스트림 개발자는 업스트림 서비스 단위에서 기본적으로 이러한 옵션을 사용하는 것이 좋습니다. 사용하기가 매우 쉽고 보안에 큰 이점이 있습니다.
systemd 서비스 정의에서 사용할 수 있는 매우 간단하지만 강력한 구성 옵션은 PrivateNetwork= 입니다 :
...
[Service]
ExecStart=...
PrivateNetwork=yes
...
이 간단한 스위치를 사용하면 서비스 및 구성되는 모든 프로세스가 모든 종류의 네트워킹에서 완전히 분리됩니다. 네트워크 인터페이스는 프로세스에서 사용할 수 없게 되었고, 그들이 보게될 유일한 것은 루프백 장치 "lo" 이지만 실제 호스트 루프 백과는 분리되어 있습니다. 이것은 네트워크 공격으로부터 매우 강력한 보호입니다.
경고(Caveat): 일부 서비스는 네트워크가 작동해야합니다. 물론 아파치와 같은 네트워크 지향 서비스에서 PrivateNetwork=yes를 사용하는 것을 고려하는 사람은 아무도 없습니다. 그러나 네트워크에 연결되지 않은 서비스의 경우에도 네트워크 지원이 필요할 수 있으며 항상 명확하지는 않습니다. 예: 로컬 시스템이 LDAP 기반 사용자 데이터베이스에 대해 구성된 경우 getpwnam()과 같은 호출로 glibc 이름 조회를 수행하면 결국 네트워크 액세스가 발생할 수 있습니다. 즉, 이러한 경우에도 시스템 서비스 사용자의 사용자 ID는 네트워크가 없어도 확인할 수 있어야하므로 PrivateNetwork=yes를 사용하는 것이 좋습니다. 즉, 서비스에서 해결해야하는 유일한 사용자 ID가 PrivateNetwork=yes를 사용하는 매직 1000 경계 미만이면 괜찮습니다.
내부적으로 이 기능은 커널의 네트워크 네임 스페이스를 사용합니다. 활성화된 경우 새 네트워크 네임 스페이스가 열리고 여기에 구성된 루프백 장치만 있습니다.
매우 간단하지만 강력한 또 다른 구성 스위치는 PrivateTmp= 입니다 :
...
[Service]
ExecStart=...
PrivateTmp=yes
...
이 옵션을 활성화하면 서비스에 표시되는 /tmp 디렉토리가 비공개이고 호스트 시스템의 /tmp와 분리되어 있는지 확인합니다. /tmp는 전통적으로 모든 로컬 서비스와 사용자를 위한 공유 공간이었습니다. 수년에 걸쳐 다양한 서비스에서 보안 문제의 주요 원인이었습니다. 추측 가능한 /tmp 임시 파일로 인한 Symlink 공격 및 DoS 취약성이 일반적입니다. 나머지 호스트에서 서비스의 /tmp를 분리하면 이러한 취약점이 문제가 됩니다.
Fedora 17의 경우 많은 서비스에서 이 옵션을 활성화 하기위한 기능이 허용되었습니다.
경고(Caveat): 일부 서비스는 실제로 /tmp를 IPC 소켓 및 기타 통신 기본 요소의 위치로 오용합니다. 비록 이것이 거의 항상 취약점이지만(통신에 사용하는 경우 추측 가능한 이름이 필요하고 추측 가능한 이름은 코드를 DoS 및 심볼릭 링크 공격에 취약하게 만들기 때문입니다) /run이 권한이 없는 프로세스에 쓸 수 있는 위치가 아니기 때문에 이를 훨씬 더 안전하게 대체 할 수 있습니다. 예를 들어, X11은 /tmp 아래에 통신 소켓을 배치합니다. (아직도 이상적이지는 않지만 실제로는 안전합니다. 이 예외는 초기 부팅시 생성되는 안전한 하위 디렉토리에 있기 때문입니다) /tmp에 있는 그러한 통신 프리미티브를 통해 통신해야하는 서비스는 PrivateTmp= 의 후보가 아닙니다. 고맙게도 요즘은 이와 같이 /tmp를 오용하는 서비스가 거의 없습니다.
내부적으로 이 기능은 커널의 파일 시스템 네임 스페이스를 사용합니다. 활성화되면 /tmp를 제외한 대부분의 호스트 계층 구조를 상속하는 새 파일 시스템 네임 스페이스가 열립니다.
(디렉터리를 읽기 전용으로 표시하거나 서비스에 액세스 할 수 없도록 설정)
ReadOnlyDirectories= 및 InaccessibleDirectories= 옵션을 사용하면 resp를 작성하기 위해 서비스가 지정된 디렉토리에 액세스 할 수 없게 하거나 읽기 및 쓰기 둘다 할수 없게 만들 수 있습니다:
...
[Service]
ExecStart=...
InaccessibleDirectories=/home
ReadOnlyDirectories=/var
...
With these two configuration lines the whole tree below /home becomes inaccessible to the service (i.e. the directory will appear empty and with 000 access mode), and the tree below /var becomes read-only.
이 두 구성 줄을 사용하면 /home 아래의 전체 트리가 서비스에 액세스 할 수 없게되고 (즉, 디렉토리가 비어 있고 000 액세스 모드로 표시됨) /var 아래의 트리는 읽기 전용이됩니다.
경고(Caveat): ReadOnlyDirectories= 는 현재 지정된 디렉토리의 하위 마운트에 재귀적으로 적용되지 않습니다 (즉, 위의 예에서 /var 아래 마운트는 쓰기 가능 상태로 유지됨). 이것은 곧 해결될 것입니다.
내부적으로 이것은 또한 파일 시스템 네임 스페이스를 기반으로 구현됩니다.
(서비스에서 기능 제거)
systemd의 또 다른 매우 강력한 보안 옵션은 CapabilityBoundingSet= 로, 서비스가 시작한 커널 기능이 유지하는 비교적 세밀한 방식으로 제한할 수 있습니다:
...
[Service]
ExecStart=...
CapabilityBoundingSet=CAP_CHOWN CAP_KILL
...
위의 예에서 CAP_CHOWN 및 CAP_KILL 기능만 서비스에 의해 유지되며 서비스 및 생성할 수 있는 모든 프로세스는 setuid 바이너리를 통해서도 다른 기능을 다시 획득할 기회가 없습니다. 현재 정의된 기능 목록은 capabilities(7)에서 사용할 수 있습니다. 불행히도 정의된 기능 중 일부는 지나치게 일반적이지만 (예: CAP_SYS_ADMIN), 특히 전체 루트 권한으로 실행되는 서비스의 경우 여전히 매우 유용한 도구입니다.
서비스가 깨끗하게 실행되는데 필요한 기능을 정확하게 식별하는 것은 항상 쉬운 것은 아니며 약간의 테스트가 필요합니다. 이 프로세스를 약간 단순화하기 위해 필요한 모든 기능을 화이트리스트에 추가하는 대신 반드시 필요하지 않은 특정 기능을 블랙리스트에 올릴 수 있습니다. 예: CAP_SYS_PTRACE는 시스템의 모든 로컬 프로세스를 검사하고 조작할 수 있기 때문에 디버거 구현에 필요한 특히 강력하고 보안 관련 기능입니다. Apache와 같은 서비스는 분명히 다른 프로세스에 대한 디버거 역할을 하지 않으므로 해당 기능을 제거하는 것이 안전합니다:
...
[Service]
ExecStart=...
CapabilityBoundingSet=~CAP_SYS_PTRACE
...
여기에 할당된 값의 접두사가 붙은 ~ 문자는 옵션의 의미를 반전시킵니다. 서비스가 유지할 모든 기능을 나열하는 대신 유지하지 않을 기능을 나열할 수 있습니다.
경고(Caveat): 일부 서비스는 특정 기능을 사용할 수 없는 경우 혼란스럽게 반응 할 수 있습니다. 따라서 유지해야 할 올바른 기능 세트를 결정할 때 이 작업을 신중하게 수행해야하며, 서비스를 성공적으로 실행하는 데 필요한 작업을 가장 잘 알고 있어야하기 때문에 업스트림 유지 관리자와 상의하는 것이 좋습니다.
경고(Caveat)2: 기능 능력은 마술 지팡이가 아닙니다. 진정으로 유용하게 만들기 위해 이들을 결합하고 다른 보안 옵션과 함께 사용하고 싶을 것입니다.
시스템에서 어떤 프로세스가 어떤 기능을 유지하는지 쉽게 확인하려면 libcap-ng-utils 패키지의 pscap 도구를 사용하십시오.
systemd의 CapabilityBoundingSet= 옵션을 사용하는 것은 종종 모든 시스템 데몬을 개별적으로 패치하여 자체적으로 능력 경계 세트를 제어하기위한 간단하고 검색 가능하며 저렴한 대체품입니다.
(포크 금지, 서비스 파일 생성 제한)
리소스 제한은 실행중인 서비스에 특정 보안 제한을 적용하는 데 사용할 수 있습니다. 주로 리소스 제한은 그다지 액세스 제어가 아니라 리소스 제어 (이름에서 알 수 있듯이 ...)에 유용합니다. 그러나 그 중 두 가지는 특정 OS 기능을 비활성화하는 데 유용 할 수 있습니다. RLIMIT_NPROC 및 RLIMIT_FSIZE를 사용하여 분기를 비활성화하고 크기가 0보다 큰 파일의 쓰기를 비활성화 할 수 있습니다:
...
[Service]
ExecStart=...
LimitNPROC=1
LimitFSIZE=0
...
이는 해당 서비스가 권한을 삭제하고 자체 (루트가 아닌) 사용자 ID로 실행되거나 위에서 설명한대로 CapabilityBoundingSet= 를 통해 CAP_SYS_RESOURCE 기능을 삭제하는 경우에만 작동합니다. 그것 없이는 프로세스가 단순히 자원 제한을 다시 증가시켜 효과를 무효화 할 수 있습니다.
경고(Caveat): LimitFSIZE= 는 꽤 잔인합니다. 서비스가 크기가 0보다 큰 파일을 쓰려고하면 SIGXFSZ와 함께 즉시 종료되며, 잡히지 않으면 프로세스가 종료됩니다. 또한 이 옵션을 사용하더라도 크기가 0 인 파일을 만들 수 있습니다.
이러한 리소스 제한 및 기타 리소스 제한에 대한 자세한 내용은 setrlimit(2)를 참조하십시오.
(서비스의 장치 노드 액세스 제어)
장치 노드는 커널 및 해당 드라이버에 대한 중요한 인터페이스입니다. 드라이버는 코어 커널보다 훨씬 적은 테스트와 보안 검사를 받는 경향이 있기 때문에 종종 보안 해킹의 주요 진입점이 됩니다. systemd를 사용하면 각 서비스에 대해 장치에 대한 액세스를 개별적으로 제어할 수 있습니다:
...
[Service]
ExecStart=...
DeviceAllow=/dev/null rw
...
이는 /dev/null 및 이 장치 노드에 대한 액세스를 제한하여 다른 장치 노드에 대한 액세스를 허용하지 않습니다.
이 기능은 장치 cgroup 컨트롤러 위에 구현됩니다.
위의 사용하기 쉬운 옵션 외에도 여러 가지 다른 보안 관련 옵션을 사용할 수 있습니다. 그러나 일반적으로 서비스 자체에서 약간의 준비가 필요하므로 주로 업스트림 개발자에게 유용할 것입니다. 이러한 옵션은 RootDirectory= (서비스에 대한 chroot() 환경 설정) 및 User= 및 Group= 으로 지정된 사용자 및 그룹에 대한 권한을 삭제합니다. 이러한 옵션은 권한을 안전하게 삭제하는 모든 복잡성을 systemd에 맡기고 데몬 자체에서 보호 할 수 있는 데몬 작성을 크게 단순화하는 데 특히 유용합니다.
이러한 옵션이 기본적으로 활성화되지 않는 이유가 궁금한 경우: 그들중 일부는 단순히 전통적인 Unix의 이음새를 깨뜨리고 호환성을 유지하기 위해 기본적으로 활성화 할 수 없습니다. 예: 전통적인 유닉스에서는 /tmp가 공유 네임 스페이스라고 강제했기 때문에. 그리고 프로세스는 IPC를 위해 그것을 사용할 수 있습니다. IPC에서 /tmp의 역할이 이제 /run으로 대체 되었기 때문에 우리는 전역적으로 그것을 끌 수 없습니다.
오늘은 여기까지 입니다. 업스트림 또는 배포를 위해 단위 파일을 작업하는 경우 위에 나열된 옵션 중 하나 이상을 사용하는 것이 좋습니다. 이러한 옵션을 활용하여 서비스가 기본적으로 안전하다면 사용자뿐만 아니라 인터넷을보다 안전한 곳으로 만드는 데 도움이됩니다.
(원문: http://0pointer.de/blog/projects/systemctl-journal.html)
이것은 짧은 에피소드입니다. systemd 시스템에서 가장 일반적으로 사용되는 명령중 하나는 서비스 (또는 다른 장치)의 상태를 확인하는데 사용할 수 있는 systemctl status 입니다. 시스템에서 실행되는 데몬의 프로세스, 런타임 정보 및 기타 메타 데이터를 파악하는데 항상 귀중한 도구였습니다.
Fedora 17 에서 우리는 기존 시스템 로그 구현과 어느 정도의 호환성을 제공하면서 systemd 시스템에서 구조화되고 색인화되고 안정적인 로깅을 제공하는 새로운 로깅 체계인 저널을 도입했습니다. 우리가 저널 작업을 시작한 원래 이유는 외부인에게는 단순해 보이지만 저널 없이는 구현하기 어렵고 비효율적이라는 특정 기능 아이디어였습니다: systemctl 상태의 출력과 함께 데몬의 마지막 10 개의 로그 메시지를 표시하려고 했습니다. 로그 데이터는 서비스 상태에 대한 가장 중요한 정보입니다. 따라서 서비스의 일반 상태 옆에 표시하는 것은 분명한 선택입니다.
이제 짧게 설명하겠습니다: 저널을 systemd와 Fedora에 통합하는 동시에 systemctl도 여기에 연결했습니다. 다음은 출력 예입니다:
$ systemctl status avahi-daemon.service
avahi-daemon.service - Avahi mDNS/DNS-SD Stack
Loaded: loaded (/usr/lib/systemd/system/avahi-daemon.service; enabled)
Active: active (running) since Fri, 18 May 2012 12:27:37 +0200; 14s ago
Main PID: 8216 (avahi-daemon)
Status: "avahi-daemon 0.6.30 starting up."
CGroup: name=systemd:/system/avahi-daemon.service
├ 8216 avahi-daemon: running [omega.local]
└ 8217 avahi-daemon: chroot helper
May 18 12:27:37 omega avahi-daemon[8216]: Joining mDNS multicast group on interface eth1.IPv4 with address 172.31.0.52.
May 18 12:27:37 omega avahi-daemon[8216]: New relevant interface eth1.IPv4 for mDNS.
May 18 12:27:37 omega avahi-daemon[8216]: Network interface enumeration completed.
May 18 12:27:37 omega avahi-daemon[8216]: Registering new address record for 192.168.122.1 on virbr0.IPv4.
May 18 12:27:37 omega avahi-daemon[8216]: Registering new address record for fd00::e269:95ff:fe87:e282 on eth1.*.
May 18 12:27:37 omega avahi-daemon[8216]: Registering new address record for 172.31.0.52 on eth1.IPv4.
May 18 12:27:37 omega avahi-daemon[8216]: Registering HINFO record with values 'X86_64'/'LINUX'.
May 18 12:27:38 omega avahi-daemon[8216]: Server startup complete. Host name is omega.local. Local service cookie is 3555095952.
May 18 12:27:38 omega avahi-daemon[8216]: Service "omega" (/services/ssh.service) successfully established.
May 18 12:27:38 omega avahi-daemon[8216]: Service "omega" (/services/sftp-ssh.service) successfully established.
물론 이것은 약속대로 10개의 가장 최근 로그 라인과 함께 프로세스 목록과 함께 모든 사람이 좋아하는 mDNS/DNS-SD 데몬의 상태를 보여줍니다. 임무 완수!
출력을 약간 변경하고 필요에 맞게 조정하는 데 사용할 수 있는 몇 가지 스위치가 있습니다. 가장 흥미로운 두 가지 스위치는 -f (tail -f 에서와 같이)를 사용하도록 설정하고 -n 은 표시할 줄 수를 변경합니다 (짐작했듯이, tail -n 에서와 같이).
표시된 로그 데이터는 다음 세 가지 소스에서 가져옵니다: libc의 syslog() 호출로 기록된 데몬의 모든 프로세스, 기본 저널 API를 사용하여 제출된 모든 것, STDOUT 또는 STDERR에 기록된 데몬의 모든 프로세스에 대한 모든 것. 간단히 말해: 데몬이 로그 데이터로 생성하는 모든 것이 수집되고 적절히 인터리브되어 동일한 형식으로 표시됩니다.
벌써 오늘 내용이 끝났습니다. 매우 간단한 기능이지만 모든 관리자에게 매우 유용한 기능입니다. "15년 전에 이미 이 작업을 수행하지 않은 이유는 무엇입니까?"와 같은 종류의 하나입니다.
다음 편을 기대해 주십시오!
(원문: http://0pointer.de/blog/projects/self-documented-boot.html)
(설명이 필요없는 부팅)
systemd에 대해 자주 듣는 한 가지 불만은 부팅 프로세스가 이해하기 어렵고 이해할 수 없다는 것입니다. 일반적으로 저는 이 감정에 동의하지 않을 수 있습니다. 심지어 그 반대라고 믿습니다: 이전에 가졌던 것과 비교하면 - 무슨 일이 일어나고 있는지 원격으로 이해할 수 있는 곳에서 Bourne Shell [1]이라는 프로그래밍 언어에 대한 적절한 이해가 있어야 했습니다 - systemd의 부팅 프로세스를 이해하는 것이 훨씬 쉽습니다. 그러나 많은 불만과 마찬가지로 자주 들리는 불편함에도 몇 가지 진실이 있습니다. 노련한 Unix 관리자에게는 systemd로 전환할 때 수행할 수 있는 방법이 약간 있습니다. 그리고 시스템 개발자로서 학습 곡선을 얕게 만들고 가능한 한 적은 놀라움을 소개하고 불가능한 경우 좋은 문서를 제공하는 것이 우리의 의무입니다.
systemd는 위키와 제가 게시한 다양한 블로그 스토리에 항상 매뉴얼 페이지 (현재 거의 100 페이지에 달하는 개별 페이지)로 방대한 양의 문서를 가지고 있었습니다. 그러나 어떤 양의 문서만으로는 소프트웨어를 쉽게 이해할 수 없습니다. 사실, 두꺼운 매뉴얼은 때때로 위협적인 것처럼 보이며 독자가 전체 시스템에 대한이 간단한 개념에 관심이 있다면 어디에서 읽기를 시작해야할지 궁금해합니다.
이 모든 것을 인정하면서 우리는 이제 systemd에 새롭고 깔끔하고 작은 기능을 추가했습니다: 설명이 필요없는(자명한) 부팅 프로세스. 그게 무슨 뜻입니까? 단순히 우리 부팅의 모든 단일 구성 요소가 설명서와 함께 제공되고 이 설명서가 해당 구성 요소와 밀접하게 연결되어 있으므로 쉽게 찾을 수 있습니다.
보다 구체적으로, systemd의 모든 장치 (부트 구성 요소를 캡슐화)는 이제 해당 설명서, 구성 파일 설명서 및 추가 적용 가능한 설명서에 대한 참조를 포함합니다. 유닛의 목적, 부팅 프로세스에 적합한 방법 및 구성 방법을 이해하려는 사용자는 이제 잘 알려진 systemctl status 명령을 사용하여 이 문서를 쉽게 찾을 수 있습니다. 다음은 systemd-logind.service를 찾는 방법의 예입니다:
$ systemctl status systemd-logind.service
systemd-logind.service - Login Service
Loaded: loaded (/usr/lib/systemd/system/systemd-logind.service; static)
Active: active (running) since Mon, 25 Jun 2012 22:39:24 +0200; 1 day and 18h ago
Docs: man:systemd-logind.service(7)
man:logind.conf(5)
http://www.freedesktop.org/wiki/Software/systemd/multiseat
Main PID: 562 (systemd-logind)
CGroup: name=systemd:/system/systemd-logind.service
└ 562 /usr/lib/systemd/systemd-logind
Jun 25 22:39:24 epsilon systemd-logind[562]: Watching system buttons on /dev/input/event2 (Power Button)
Jun 25 22:39:24 epsilon systemd-logind[562]: Watching system buttons on /dev/input/event6 (Video Bus)
Jun 25 22:39:24 epsilon systemd-logind[562]: Watching system buttons on /dev/input/event0 (Lid Switch)
Jun 25 22:39:24 epsilon systemd-logind[562]: Watching system buttons on /dev/input/event1 (Sleep Button)
Jun 25 22:39:24 epsilon systemd-logind[562]: Watching system buttons on /dev/input/event7 (ThinkPad Extra Buttons)
Jun 25 22:39:25 epsilon systemd-logind[562]: New session 1 of user gdm.
Jun 25 22:39:25 epsilon systemd-logind[562]: Linked /tmp/.X11-unix/X0 to /run/user/42/X11-display.
Jun 25 22:39:32 epsilon systemd-logind[562]: New session 2 of user lennart.
Jun 25 22:39:32 epsilon systemd-logind[562]: Linked /tmp/.X11-unix/X0 to /run/user/500/X11-display.
Jun 25 22:39:54 epsilon systemd-logind[562]: Removed session 1.
처음 보면이 출력은 거의 변경되지 않았습니다. 그러나 자세히 살펴보면 이제 하나의 새 필드가 포함되어 있음을 알 수 있습니다: Docs에는 이 서비스의 문서에 대한 참조가 나열됩니다. 이 경우 두 개의 매뉴얼 페이지 URI와 하나의 웹 URL이 지정됩니다. 매뉴얼 페이지는 이 서비스의 목적과 구성을 설명하고 웹 URL에는 이 서비스의 기본 개념에 대한 소개가 포함되어 있습니다.
사용자가 최신 그래픽 터미널 구현을 사용하는 경우 표시된 URI를 클릭하여 각 문서를 가져 오는 것으로 충분합니다 [2]. 즉, 부팅의 특정 구성 요소가 무엇인지 알아내는 것이 그렇게 쉬운 일이 아닙니다: systemctl status 를 사용하여 자세한 정보를 얻고 표시된 링크를 클릭하여 설명서를 찾으십시오.
지난 며칠 동안 나는 man 페이지를 작성하고 systemd와 함께 제공되는 모든 단일 단위에 대해 이러한 참조를 추가했습니다. 즉, systemctl 상태를 사용하면 이제 핵심 OS의 모든 단일 서비스에 대해 더 많은 정보를 쉽게 찾을 수 있습니다.
그래픽 터미널 (URI를 클릭하기 만하면 됨)을 사용하지 않는 경우 systemctl status의 출력 중간에 있는 매뉴얼 페이지 URI는 가장 유용한 것이 아닙니다. 참조된 매뉴얼 페이지를 더 쉽게 읽을 수 있도록 새 명령도 추가했습니다:
systemctl help systemd-logind.service
아무 것도 클릭하거나 URI를 copy/paste 할 필요없이 나열된 맨 페이지가 바로 열립니다.
URI는 uri(7) 매뉴얼 페이지에 설명된 형식입니다. 단위는 http 및 https URL과 man 및 info 페이지를 참조할 수 있습니다.
물론 이 모든 것이 모든 것을 설명이 필요없게 만드는 것은 아닙니다. 사용자가 여전히 systemctl status에 대해 알아 내야하기 때문입니다. 그러나 이 기본 지식을 통해 특정 장치에 대한 추가 도움말을 쉽게 찾을 수 있습니다.
이러한 종류의 런타임 동작과 일치하는 문서의 상호 연결이 부팅을 이해하기 쉽게 만드는 큰 진전이 되기를 바랍니다.
이 기능은 Fedora 17에서 부분적으로 이미 사용 가능하며 Fedora 18에서 완전한 형태로 표시됩니다.
즉, 신용이 필요한 곳에 신용을 부여합니다: 서비스 설명에 있는 문서에 대한 이러한 종류의 참조는 새로운 것이 아니며 Solaris의 SMF는 꽤 오랫동안 유사한 기능을 가졌습니다. 그러나 우리는 이 새로운 시스템 기능이 리눅스에서 확실히 참신하다고 믿고 있으며, systemd를 통해 우리는 이제 가장 잘 문서화되고 가장 잘 설명되는 init 시스템을 제공합니다.
물론, 자신의 패키지에 대한 유닛 파일을 작성하는 경우 서비스 및 해당 구성의 문서에 대한 참조도 포함하는 것을 고려하십시오. 이것은 정말 간단합니다. 유닛 파일의 [Unit] 섹션에있는 새로운 Documentation= 필드에 URI를 나열하기 만하면됩니다. 자세한 내용은 systemd.unit(5)를 참조하십시오. 보다 포괄적으로 OS 서비스에 문서 링크를 포함할수록 관리자의 작업이 쉬워집니다. (Fedora가 이 기능을 포괄적으로 사용하도록하기 위해 FPC에 버그를 제출했습니다)
아, 그리고 BTW: systemd의 부팅 프로세스에 대한 대략적인 개요를 찾고 있다면 여기에 최근에 추가한 또 다른 새로운 man 페이지가 있습니다. 여기에는 부팅 프로세스와 관련된 단위에 대한 예쁜 ASCII 흐름도가 포함되어 있습니다.
[1] 어느 TBH가 꽤 엉뚱하고 이상한 것 입니다.
[2] 글쎄, 이 버그가 수정된 터미널 (이 버그가 수정된 도움말 브라우저와 함께 사용됨).
(원문: http://0pointer.de/blog/projects/watchdog.html)
systemd로 커버하려고 하는 세 가지 큰 타겟층이 있습니다: 임베디드/모바일 사용자, 데스크톱 사용자 및 서버 사용자. 임베디드/모바일에서 사용하는 시스템은 성능이 부족하고 사용 가능한 리소스가 거의 없지만 데스크톱은 훨씬 더 강력한 시스템인 경향이 있습니다 - 그러나 여전히 서버보다 훨씬 덜 자원을 갖췄습니다. 그럼에도 불구하고 이 축의 극단 (임베디드와 서버) 모두에 중요한 기능이 놀라울 정도로 많지만 중앙(데스크톱)에는 중요하지 않습니다. 그중에는 하드웨어 및 소프트웨어의 감시 장치에 대한 지원이 있습니다.
임베디드 장치는 흔히 소프트웨어가 응답하지 않는 경우(구체적으로는, 고정된 간격으로 하드웨어가 여전히 살아 있다는 신호를 보내는 것을 중지한 경우) 자동으로 리셋하는 와치독 하드웨어에 의존합니다. 이것은 신뢰성을 높이고 어떤 일이 발생하든 시스템이 다시 작동하도록 최선을 다하도록 시도하는데 필요합니다. 이와 같은 기능은 데스크톱에서 거의 의미가 없습니다 [1]. 그러나 고 가용성 서버에서는 워치독이 다시 자주 사용됩니다.
버전 183부터 systemd는 하드웨어 워치독 (/dev/watchdog 에서 사용자 공간에 노출됨)에 대한 완전한 지원과 개별 시스템 서비스에 대한 감독자(소프트웨어) 워치독 지원을 제공합니다. 기본 아이디어는 다음과 같습니다: 활성화된 경우 systemd는 정기적으로 감시 하드웨어를 ping합니다. systemd 또는 커널이 중단되면 이 핑은 더 이상 발생하지 않으며 하드웨어가 자동으로 시스템을 리셋 합니다. 이런 식으로 systemd와 커널은 하드웨어에 의해 무한한 중단으로부터 보호됩니다. 체인을 완성하기 위해 systemd는 개별 서비스에 대한 소프트웨어 감시 인터페이스를 노출하여 중단되기 시작하면 다시 시작할 수도 있습니다 (또는 다른 조치를 취함). 이 소프트웨어 감시 로직은 핑 빈도 및 수행할 작업에서 각 서비스에 대해 개별적으로 구성할 수 있습니다. 두 부분을 합치면 (즉, systemd와 커널을 감독하는 하드웨어 감시 장치와 다른 모든 서비스를 감시하는 systemd) 시스템의 모든 단일 구성 요소를 감시하는 신뢰할 수 있는 방법이 있습니다.
하드웨어 워치독을 사용하려면 /etc/systemd/system.conf에서 RuntimeWatchdogSec= 옵션을 설정하는 것으로 충분합니다. 기본값은 0 입니다 (즉, 하드웨어 와치독 사용안함). 20초와 같은 값으로 설정하면 워치독이 활성화됩니다. 연결 유지 핑이 없는 20초 후에 하드웨어가 자체적으로 리셋 됩니다. systemd는 지정된 간격의 절반, 즉 10초마다 하드웨어에 ping을 보냅니다. 그리고 그게 이미 전부입니다. 이 간단한 단일 옵션을 활성화하면 systemd의 하드웨어와 그 아래에 있는 커널의 감독 기능을 켰습니다. [2]
하드웨어 감시 장치 (/dev/watchdog)는 단일 사용자 전용입니다. 즉, systemd에서 이 기능을 활성화하거나 적절한 이름의 워치독과 같은 별도의 외부 워치독 데몬을 사용할 수 있습니다.
ShutdownWatchdogSec= 는 /etc/systemd/system.conf에서 구성할 수 있는 또 다른 옵션입니다. 재부팅시 사용할 워치독 간격을 제어합니다. 기본값은 10분이며 시스템 재부팅 논리에 안정성을 추가합니다: 클린 재부팅이 불가능하고 종료가 중단되면 감시 하드웨어에 의존하여 시스템을 갑작스럽게 재설정합니다.
하드웨어 워치독 로직에 대한것들이 아주 많습니다. 이 두 가지 옵션은 실제로 하드웨어 감시 장치를 사용하는데 필요한 모든 것입니다. 이제 개별 서비스에 워치독 로직을 추가하는 방법을 살펴 보겠습니다.
우선, 소프트웨어 감시가 가능하도록 하려면 이벤트 루프에서 정기적으로 "I am alive" 신호를 보내도록 패치를 적용해야 합니다. 패치는 비교적 쉽습니다. 먼저 데몬은 WATCHDOG_USEC= 환경 변수를 읽어야합니다. 설정된 경우, 서비스에 대해 구성된대로 ASCII 텍스트 문자열로 형식화된 usec에 감시 간격이 포함됩니다. 그런 다음 데몬은 해당 간격의 절반마다 sd_notify("WATCHDOG=1") 호출을 수행해야 합니다. 이 방법으로 패치된 데몬은 환경 변수가 설정되었는지 확인하고 설정된 값을 준수하여 감시 기능을 투명하게 지원해야 합니다.
서비스(위에서 지적한 로직을 지원하도록 패치된)에 대한 소프트웨어 와치독 로직을 활성화하려면 WatchdogSec= 를 원하는 실패 대기 시간으로 설정하는 것으로 충분합니다. 이 설정에 대한 자세한 내용은 systemd.service(5)를 참조하십시오. 이로 인해 WATCHDOG_USEC= 가 서비스의 프로세스에 대해 설정되고 구성된 간격 내에 연결 유지 핑이 수신되지 않으면 서비스가 실패 상태로 전환됩니다.
워치독 로직이 정지를 감지하자마자 서비스가 실패 상태가 되면 이는 안정적인 시스템을 구축하기에 충분하지 않습니다. 다음 단계는 서비스를 다시 시작할지 여부와 빈도, 그래도 실패할 경우 수행할 작업을 구성하는 것입니다. 실패시 자동 서비스 다시 시작을 활성화 하려면 서비스에 대해 Restart=on-failure를 설정합니다. 서비스 재시작 시도 횟수를 구성하려면 StartLimitBurst= 및 StartLimitInterval= 의 조합을 사용하여 시간 간격 내에서 서비스를 재시작 할 수 있는 빈도를 구성 할 수 있습니다. 이 한계에 도달하면 특별한 조치를 취할 수 있습니다. 이 작업은 StartLimitAction= 으로 구성됩니다. 기본값은 none 입니다. 즉, 추가 작업이 수행되지 않고 서비스가 더 이상 다시 시작하지 않고 실패 상태로 유지됩니다. 다른 세 가지 가능한 값은 reboot, reboot-force 및 reboot-immediate입니다. reboot는 일반적인 깨끗한 종료 논리를 통해 깨끗한 재부팅을 시도합니다. reboot-force는 더 갑작 스럽습니다: 실제로 모든 서비스를 완전히 종료하려고 시도하지는 않지만 즉시 남아있는 모든 서비스를 종료하고 모든 파일 시스템을 마운트 해제한 다음 강제로 재부팅합니다 (이렇게 하면 모든 파일 시스템이 정리되지만 재부팅은 여전히 매우 빠름). 마지막으로 reboot-immediate는 프로세스를 종료하거나 파일 시스템을 마운트 해제하지 않습니다. 대신 지연없이 시스템을 하드 재부팅합니다. 따라서 reboot-immediate는 하드웨어 워치 독에 의해 트리거되는 재부팅에 가장 가깝습니다. 이러한 모든 설정은 systemd.service(5)에 설명되어 있습니다.
이 모든 것을 종합하면 이제 특정 서비스를 감시-감독하고 서비스가 중단될 경우 서비스의 자동 재시작을 구성하고 도움이 되지 않으면 궁극적인 조치를 취할 수 있는 매우 유연한 옵션이 있습니다.
다음은 유닛 파일의 예입니다:
[Unit]
Description=My Little Daemon
Documentation=man:mylittled(8)
[Service]
ExecStart=/usr/bin/mylittled
WatchdogSec=30s
Restart=on-failure
StartLimitInterval=5min
StartLimitBurst=4
StartLimitAction=reboot-force
This service will automatically be restarted if it hasn't pinged the system manager for longer than 30s or if it fails otherwise. If it is restarted this way more often than 4 times in 5min action is taken and the system quickly rebooted, with all file systems being clean when it comes up again.
이 서비스는 시스템 관리자에게 30초 이상 ping을 하지 않았거나 실패하면 자동으로 다시 시작됩니다. 이런식으로 다시 시작하면 5분 동안 4번 이상 작업이 수행되고 시스템이 빠르게 재부팅되고 다시 시작될 때 모든 파일 시스템이 정리됩니다.
그리고 그것이 이미 제가 여러분에게 말하고 싶었던 전부입니다! PID 1에서 하드웨어 워치독 지원과 개별 서비스에 대한 수퍼바이저 워치독 지원을 통해 대부분의 워치독 사용 사례에 필요한 모든 것을 제공해야합니다. 임베디드 또는 모바일 애플리케이션을 구축하고 있거나 고 가용성 서버로 작업하는 경우에 관계없이 시도해보십시오!
(오, 그리고 천국에서 PID 1 이 왜 /dev/watchdog을 처리해야하는지, 왜 이것이 별도의 데몬에 보관되지 않아야 하는지 궁금하다면, 이글을 다시 읽고 이것이 모두 감독자에 관한것임을 이해하려고 노력하십시오. 여기서 우리가 구축하고 있는 체인은 하드웨어 워치독이 systemd를 감독하고 systemd가 개별 서비스를 감독하는 곳입니다. 또한 응답하지 않는 서비스는 다른 서비스 오류와 유사한 방식으로 처리해야 한다고 믿습니다. 마지막으로 /dev/watchdog 핑은 OS에서 가장 사소한 작업 중 하나이며(기본적으로 ioctl() 호출보다 약간 많음) 이를 지원하는 것은 코드 몇 줄에 불과합니다. PID 1 (및 데몬) 간의 복잡한 IPC를 사용하여 외부적에서 이를 유지하는 것은 훨씬 더 복잡하고 오류가 발생하기 쉬우며 리소스 집약적 입니다)
systemd의 내장 하드웨어 와치독 지원은 기본적으로 다른 감시 소프트웨어와 충돌하지 않습니다. systemd는 기본적으로 /dev/watchdog을 사용하지 않으며, 필요에 더 적합한 경우 systemd와 함께 외부 감시 데몬을 사용할 수 있습니다.
그리고 마지막으로: 하드웨어에 감시 장치가 있는지 궁금하다면, 대답은 다음과 같습니다: 거의 확실히 그렇습니다 - 최근 몇 년이 지난 경우. 이를 확인하려면 최신 util-linux에서 wdctl 도구를 사용해보십시오. 이 도구는 감시 하드웨어에 대해 알아야 할 모든 것을 보여줍니다.
대부분의 워치독 로직에 기여해 주신 Pengutronix의 위대한 분들께 감사드립니다. 감사합니다!
[1] 실제로 대부분의 데스크탑에는 오늘날에도 워치독 하드웨어가 포함되는 경향이 있지만, 이것은 구축 비용이 저렴하고 대부분의 최신 PC 칩셋에서 사용할 수 있기 때문입니다.
[2] 따라서 핵심 OS를 해킹하는 경우 무료 팁이 있습니다: 해킹하는 동안 이 기능을 사용하지 마세요. 그렇지 않으면 gdb를 사용하여 PID 1을 추적하는 도중에 시스템이 갑자기 재부팅되어 잠시 중지되어 하드웨어 핑이 수행되지 않을 수 있습니다.
(원문: http://0pointer.de/blog/projects/serial-console.html)
요약: 직렬 콘솔을 사용하려면 커널 명령줄에서 console=ttyS0을 사용하면 systemd가 자동으로 getty를 시작합니다.
물리적 RS232 직렬 포트는 오늘날의 PC에서 이국적 이기는하지만 현대 서버와 임베디드 하드웨어에서 중요한 역할을 합니다. 네트워크가 연결되어 있거나 기본 UI가 응답하지 않는 경우에도 작동하는 장치 콘솔에 액세스하는 비교적 강력하고 최소한의 방법을 제공합니다. VM은 종종 직렬 포트도 에뮬레이트 합니다.
물론 Linux는 항상 직렬 콘솔을 잘 지원해 왔지만 systemd를 사용하면 직렬 콘솔 지원을 더 쉽게 사용하기 위해 노력했습니다. 다음 텍스트에서는 systemd에서 직렬 콘솔 getty가 작동하는 방식과 모든 종류의 TTY가 처리되는 방식에 대한 개요를 제공하려고 합니다.
핵심 요약부터 시작하겠습니다: 대부분의 경우 직렬 프롬프트에 로그인 프롬프트를 표시하기 위해 아무것도 할 필요가 없습니다. systemd는 선택한 커널 콘솔에 대한 커널 구성을 확인하고 단순히 직렬 getty를 생성합니다. 이렇게하면 커널 콘솔을 올바르게 구성하는 것만으로도 충분합니다 (예: 커널 명령줄에 console=ttyS0 추가). 그러나 세부 사항을 살펴 보겠습니다:
systemd 에서 두 개의 템플릿 단위는 텍스트 콘솔에 로그인 프롬프트를 표시하는 역할을 합니다:
getty@.service는 가상 터미널(VT) 로그인 프롬프트, 즉 /dev/tty1 및 유사한 장치에 표시되는 VGA 화면에 표시되는 프롬프트를 담당합니다.
serial-getty@.service는 /dev/ttyS0과 같은 직렬 포트를 포함하여 다른 모든 터미널을 담당합니다. getty@.service와는 몇 가지 차이점이 있습니다. 무엇보다도 $TERM 환경 변수는 Linux (VT에만 적합한 선택)가 아닌 vt102 (대부분의 직렬 터미널에 적합한 기본값)로 설정되어 있습니다. VT 스크롤 백 버퍼를 지우고 VT에서만 작동하는 특수 로직은 건너 뜁니다.
getty@.service가 시작되는 방식, 즉 가상 터미널 (즉, 비 직렬 TTY)에서 로그인 프롬프트가 작동하는 방식을 자세히 살펴 보겠습니다. 전통적으로 Linux 시스템의 init 시스템은 부팅시 고정된 수의 로그인 프롬프트를 생성하도록 구성되었습니다. 대부분의 경우 처음 6개의 VT, tty1에서 tty6까지 6개의 getty 프로그램 인스턴스가 생성되었습니다.
시스템화된 세계에서 우리는 이것을보다 동적으로 만들었습니다: 보다 효율적인 로그인 프롬프트를 만들기 위해 이제는 요청시에만 시작됩니다. VT로 전환하면 getty 서비스가 getty@tty2.service, getty@tty5.service 등으로 인스턴스화 됩니다. 더 이상 getty 프로세스를 무조건 시작할 필요가 없기 때문에 약간의 리소스를 절약할 수 있고 시작을 조금 더 빠르게 할 수 있습니다. 이 동작은 대부분 사용자에게 투명합니다. 사용자가 VT를 활성화하면 getty가 즉시 시작되므로 사용자는 항상 실행되고 있지 않다는 사실을 거의 알아 차리지 못할 것입니다. 그런 다음 로그인하고 ps를 입력하면 getty 인스턴스가 지금까지 전환한 VT에 대해서만 실행되고 있음을 알 수 있습니다.
기본적으로 이 자동 생성은 VT6까지의 VT에 대해서만 수행됩니다 (리눅스 시스템의 기존 기본 구성에 가깝게하기 위해) [1]. getty의 자동 생성은 다른 하위 시스템이 아직 VT를 소유하지 않은 경우에만 시도됩니다. 보다 구체적으로, 사용자가 GNOME을 통해 빠른 사용자 전환을 자주 사용하는 경우 사용 가능한 가장 낮은 VT가 각 세션에 할당되기 때문에 처음 6개의 VT에서도 X 세션을 받게됩니다.
두 개의 VT는 자동 생성 로직에 의해 특별히 처리됩니다: 먼저 tty1은 특별 대우를 받습니다: 그래픽 모드로 부팅하면 디스플레이 관리자가이 VT를 차지합니다. 다중 사용자 (텍스트) 모드로 부팅하면 getty가 시작됩니다. - 무조건, 주문형 로직[2]없이.
둘째, tty6는 특히 자동 생성된 gettys용으로 예약되어 있으며 X[3]와 같은 다른 하위 시스템에서는 사용할 수 없습니다. 이는 빠른 사용자 전환으로 인해 X가 5개 이상의 VT를 소유한 경우에도 항상 텍스트 로그인을 얻을 수 있는 방법이 있는지 확인하기 위해 수행됩니다.
직렬 터미널 (및 기타 모든 종류의 비 VT 터미널)에서 로그인 프롬프트 처리는 VT와 다릅니다. 기본적으로 systemd는 가상 터미널이 아닌 경우 기본 커널 [4] 콘솔에서 serial-getty@.service 하나를 인스턴스화 합니다. 커널 콘솔은 커널이 자체 로그 메시지를 출력하는 곳이며 일반적으로 console=ttyS0 [5]와 같은 인수를 통해 부트 로더의 커널 명령 줄에서 구성됩니다. 이 로직은 사용자가 커널에 특정 직렬 터미널로 출력을 리디렉션하도록 요청할 때 부팅이 완료될 때 자동으로 로그인 프롬프트를 받게됩니다 [6]. systemd는 시스템이 이러한 장치를 제공하는 VM에서 실행되는 경우 첫 번째 특수 VM 콘솔 (즉, /dev/hvc0, /dev/xvc0, /dev/hvsi0)에 로그인 프롬프트를 표시합니다. 이 로직은 부팅시 초기에 실행되고 실행 환경에 따라 필요한 서비스를 가져오는 systemd-getty-generator라는 생성기에서 구현됩니다.
대부분의 경우 이 자동 논리는 systemd의 특정 구성없이 필요할 때 로그인 프롬프트를 표시하기에 충분합니다. 그러나 때로는 serial getty를 수동으로 구성해야하는 경우가 있습니다. 예를 들어 둘 이상의 직렬 로그인 프롬프트가 필요하거나 커널 콘솔이 로그인 프롬프트가 아닌 다른 터미널로 리디렉션 되어야하는 경우입니다. 이를 용이하게 하려면 실행하려는 각 직렬 포트에 대해 serial-getty@.service를 인스턴스화하는 것으로 충분합니다 [7]:
# systemctl enable serial-getty@ttyS2.service
# systemctl start serial-getty@ttyS2.service
그게 다입니다. 이렇게하면 모든 후속 부팅에서 선택한 포트에 대한 로그인 프롬프트가 표시되고 바로 시작됩니다.
때로는 로그인 프롬프트를 더 자세히 구성해야하는 경우가 있습니다. 예를 들어, 커널에 의해 구성된 기본 전송 속도가 올바르지 않거나 다른 agetty 매개 변수를 변경해야하는 경우입니다. 이 경우 기본 유닛 템플릿을 /etc/systemd/system에 복사하고 편집하기만 하면됩니다:
# cp /usr/lib/systemd/system/serial-getty@.service /etc/systemd/system/serial-getty@ttyS2.service
# vi /etc/systemd/system/serial-getty@ttyS2.service
.... now make your changes to the agetty command line ...
# ln -s /etc/systemd/system/serial-getty@ttyS2.service /etc/systemd/system/getty.target.wants/
# systemctl daemon-reload
# systemctl start serial-getty@ttyS2.service
이것은 직렬 포트 ttyS2에 특정한 유닛 파일을 생성하므로 이 포트와 이 포트만 특정 변경을 할 수 있습니다.
그리고 이것은 직렬 포트, VT 및 로그인 프롬프트에 대해 말할 수 있는 거의 모든 것입니다. 이 내용이 흥미로웠기를 바라며 다음 시리즈를 위해 곧 다시 방문해주세요!
[1] logind.conf에서 NAutoVTs= 를 변경하여 쉽게 수정할 수 있습니다.
[2] VT1의 getty가 on-demand로 시작되는지 여부는 거의 차이가 없습니다. VT1이 기본 활성 VT이기 때문에 어쨌든 부팅시 수요가 존재하기 때문입니다.
[3] logind.conf에서 ReserveVT= 를 수정하여 이 특별 예약된 VT를 쉽게 변경할 수 있습니다.
[4] 여러 커널 콘솔이 동시에 사용되는 경우 주 콘솔은 커널 명령줄에 나열된 마지막 콘솔인 /sys/class/tty/console/active에 맨 처음 나열된 콘솔입니다.
[5] 이 커널 명령줄 옵션에 대한 자세한 내용은 kernel-parameters.txt를 참조하십시오.
[6] 여기서는 agetty -s가 사용되므로 커널 명령 줄에서 구성된 전송 속도가 변경되지 않고 로그인 프롬프트에서 계속 사용됩니다.
[7] 이 systemctl enable 구문은 systemd 188 이상 (예: F18)에서만 작동합니다. 이전 버전에서는 ln -s /usr/lib/systemd/system/serial-getty@.service /etc/systemd/system/getty.target.wants/serial-getty@ttyS2.service를 사용하십시오. 대신 systemctl daemon-reload 실행이 필요합니다.
(원문: http://0pointer.de/blog/projects/journalctl.html)
얼마 전에 저는 이미 저널의 일부 기능과 systemctl에 노출되는 방식을 소개하는 블로그 스토리를 게시했습니다. 이 에피소드에서는 저널의 몇 가지 용도를 더 설명하고 어떻게 활용할 수 있는지 설명하고 싶습니다.
저널이 무엇인지 궁금하다면 여기에 몇 마디로 설명해 드리겠습니다. 저널은 systemd의 구성 요소로, Syslog 메시지, 커널 로그 메시지, 초기 RAM 디스크 및 초기 부팅 메시지뿐만 아니라 모든 서비스의 STDOUT/STDERR에 기록된 메시지는 색인을 생성하고 이를 사용자가 사용할 수 있도록 합니다. 병렬로 사용하거나 rsyslog 또는 syslog-ng와 같은 기존 syslog 데몬 대신 사용할 수 있습니다. 자세한 내용은 초기 공지를 참조하십시오.
이 저널은 F17부터 Fedora의 일부였습니다. Fedora 18에서는 이제 로그를 처리 할 수 있는 안정적이고 강력한 도구로 성장했습니다. 그러나 F17 및 F18에서 저널은 기본적으로 /run/log/journal의 작은 링 버퍼에만 로그를 저장하도록 구성됩니다. 물론 이것은 그 유용성을 상당히 제한하지만 systemctl status에서 최근 로그 기록을 표시하기에 충분합니다. Fedora 19의 경우 이를 변경하고 기본적으로 영구 로깅을 활성화 할 계획입니다. 그런 다음 저널 파일은 /var/log/journal에 저장되고 훨씬 더 커질 수 있으므로 저널을 훨씬 더 유용하게 만들 수 있습니다.
그 동안 F17 또는 F18에서 journald의 영구 저장소를 수동으로 활성화 할 수 있습니다.
# mkdir -p /var/log/journal
그 후에는 재부트하여 유용한 구조화된 데이터를 저널로 가져 와서 사용할 수 있도록 하는 것이 좋습니다. 아, 그리고 지금 저널이 있으므로 더 이상 syslog가 필요하지 않습니다 (텍스트 파일로 /var/log/messages가 필요한 경우가 아니라면). 따라서 rsyslog를 제거하도록 선택할 수 있습니다:
# yum remove rsyslog
이제 갈 준비가 되었습니다. 다음 텍스트는 Fedora 18 [1]에 포함될 systemd 195의 많은 기능을 보여줍니다. F18을 기다려 주십시오. 먼저 몇 가지 기본 사항부터 시작하겠습니다. 저널 로그에 액세스하려면 journalctl(1) 도구를 사용하십시오. 로그를 먼저 보려면 다음을 입력하십시오:
# journalctl
루트로 실행하면 로그인한 사용자와 동일한 방식으로 시스템 구성 요소에서 시스템에 생성된 모든 로그를 볼 수 있습니다. 당신이 얻게될 출력은 전통적인 /var/log/messages 형식의 픽셀 단위 사본처럼 보이지만 실제로는 몇 가지 개선 사항이 있습니다:
이 블로그 스토리에서는 실제로 생성되는 출력을 보여주지 않을 것이며 간결성을 위해 잘라 냈으며 systemd 195를 사용하는 F18 개발 버전의 현재 이미지로 직접 시도해 볼 이유를 제공합니다. 하지만 어쨌든 당신이 아이디어를 얻길 바랍니다.
이 방법으로 로그를 검색하는 것은 이미 꽤 좋습니다. 하지만 루트 권한을 요구하는 것은 당연히 짜증이 납니다. 요즘에는 관리자 조차도 대부분의 작업을 권한없는 사용자로 수행하는 경향이 있습니다. 기본적으로 저널 사용자는 루트 또는 adm 그룹이 아닌 경우 자신의 로그만 볼 수 있습니다. 시스템 로그를 보다 재미있게 보기위해 adm에 추가해 보겠습니다:
# usermod -a -G adm lennart
로그 아웃한 후 lennart로 다시 로그인하면 시스템 및 모든 사용자의 전체 저널에 액세스 할 수 있습니다:
$ journalctl
매개 변수없이 호출되면 journalctl은 현재 로그 데이터베이스를 표시합니다. 때로는 로그가 커짐에 따라 로그를 관찰해야 합니다. 이전에 tail -f /var/log/messages를 사용했습니다:
$ journalctl -f
예, 이것은 당신이 기대하는대로 정확히 수행합니다: 마지막 10개의 로그 줄을 보여주고 변경을 기다렸다가 변경 사항이 발생하면 보여줍니다.
매개 변수없이 journalctl을 호출하면 저장된 가장 오래된 메시지부터 시작하여 전체 로그 집합을 볼 수 있습니다. 물론 많은 데이터가 될 수 있습니다. 훨씬 더 유용한 것은 현재 부팅의 로그를 보는 것입니다:
$ journalctl -b
앞서 언급한 모든 수법(gimmicks)이 언급된 현재 부팅의 로그만 표시됩니다. 그러나 때때로 이것은 처리하기에 너무 많은 데이터입니다. 따라서 관심을 가져야 할 모든 실제 문제를 나열하는 것은 어떻습니까? 현재 부팅에서 우선 순위 수준이 ERROR 이상인 모든 메시지를 나열합니다:
$ journalctl -b -p err
재부팅하는 경우 -b가 거의 의미가 없는 경우 시간 기준 필터링이 훨씬 더 유용합니다:
$ journalctl --since=yesterday
그리고 전날 오전 00:00부터 지금까지 모든 로그 메시지가 표시됩니다. 대박! 물론 이것을 -p err 또는 유사한 match와 결합할 수 있습니다. 하지만 흠, 우리는 10월 15일에 일어난 일을 찾고 있습니다. 아니면 16일 이었나요?
$ journalctl --since=2012-10-15 --until="2011-10-16 23:59:59"
Yupp, 갑시다. 우리가 찾고 있던 것을 찾았습니다. 하지만 아파치의 일부 CGI 스크립트가 오늘 초반에 작동하고 있다는 것을 알았습니다. 당시 아파치가 기록한 내용을 살펴 보겠습니다:
$ journalctl -u httpd --since=00:00 --until=9:30
오, 예, 찾았습니다. 하지만 그 디스크 /dev/sdc에 문제가 없었나요? 거기에서 무슨 일이 일어 났는지 알아 봅시다:
$ journalctl /dev/sdc
OMG, 디스크 오류! [2] 흠, 데이터가 손실되기 전에 디스크를 빠르게 교체합시다. 완료! 다음! --흠, vpnc 바이너리가 booboo를 만든 것을 보지 않았습니까? 확인해 보겠습니다.
$ journalctl /usr/sbin/vpnc
흠, 나는 이것을 얻을 수 없습니다. 이것은 dhclient와의 이상한 상호 작용인 것 같습니다. 두 출력을 인터리브 처리해 보겠습니다:
$ journalctl /usr/sbin/vpnc /usr/sbin/dhclient
해냈습니다! 발견했어요!
아휴! 이미 굉장했지만 한 단계 더 올려 보겠습니다. 내부적으로 systemd는 암시적 메타 데이터 집합과 함께 각 로그 항목을 저장합니다. 이 메타 데이터는 환경 블록과 비슷해 보이지만 실제로는 좀 더 강력합니다. 값은 이진, 큰 값을 취할 수 있으며 (이는 예외이며 일반적으로 UTF-8 만 포함 함) 필드에는 여러 값이 할당될 수 있습니다. (예외도 있지만 일반적으로 하나의 값만 있습니다). 이 암시적 메타 데이터는 사용자 개입없이 각각의 모든 로그 메시지에 대해 수집됩니다. 데이터가 거기에 있으며 귀하가 사용하기를 기다립니다. 이것이 어떻게 보이는지 봅시다:
$ journalctl -o verbose -n
[...]
Tue, 2012-10-23 23:51:38 CEST [s=ac9e9c423355411d87bf0ba1a9b424e8;i=4301;b=5335e9cf5d954633bb99aefc0ec38c25;m=882ee28d2;t=4ccc0f98326e6;x=f21e8b1b0994d7ee]
PRIORITY=6
SYSLOG_FACILITY=3
_MACHINE_ID=a91663387a90b89f185d4e860000001a
_HOSTNAME=epsilon
_TRANSPORT=syslog
SYSLOG_IDENTIFIER=avahi-daemon
_COMM=avahi-daemon
_EXE=/usr/sbin/avahi-daemon
_SYSTEMD_CGROUP=/system/avahi-daemon.service
_SYSTEMD_UNIT=avahi-daemon.service
_SELINUX_CONTEXT=system_u:system_r:avahi_t:s0
_UID=70
_GID=70
_CMDLINE=avahi-daemon: registering [epsilon.local]
MESSAGE=Joining mDNS multicast group on interface wlan0.IPv4 with address 172.31.0.53.
_BOOT_ID=5335e9cf5d954633bb99aefc0ec38c25
_PID=27937
SYSLOG_PID=27937
_SOURCE_REALTIME_TIMESTAMP=1351029098747042
(나는 여기서 많은 잡음을 차단했습니다. 이 이야기를 너무 길게 만들고 싶지는 않습니다. -n 매개 변수가 없으면 마지막 10 개의 로그 항목이 표시되지만 마지막 로그 항목을 제외하고 모두 잘라냅니다)
'-o verbose' 스위치를 사용하여 자세한 출력을 활성화 했습니다. 사용 가능한 최소한의 하위 집합만 포함하는 고전적인 /var/log/messages의 픽셀 단위 사본을 표시하는 대신 이제 저널이 각 항목에 대해 가지고 있는 모든 세부 정보를 볼 수 있습니다. 그러나 매우 흥미 롭습니다. 사용자 자격 증명 정보, SELinux 비트, 머신 정보 등이 있습니다. 일반적이고 잘 알려진 필드의 전체 목록은 man 페이지를 참조하십시오.
이제 저널 데이터베이스는 이러한 모든 필드에 의해 즉시 인덱싱됩니다. 이것을 시도해 봅시다:
$ journalctl _UID=70
그러면, Linux 사용자 ID 70에서 기록된 모든 로그 메시지가 표시됩니다. 결과적으로 이러한 일치 항목을 쉽게 결합할 수 있습니다.
$ journalctl _UID=70 _UID=71
동일한 필드에 대해 두 개의 일치 항목을 지정하면 일치 항목의 논리적 OR 조합이 생성됩니다. 둘 중 하나와 일치하는 모든 항목, 즉 UID 70 또는 71의 모든 메시지가 표시됩니다.
$ journalctl _HOSTNAME=epsilon _COMM=avahi-daemon
짐작했듯이, 다른 필드 이름에 대해 두 개의 일치 항목을 지정하면 논리적 AND로 결합됩니다. 둘 다 일치하는 모든 항목이 이제 표시됩니다. 즉, avahi-daemon 및 호스트 epsilon이라는 프로세스의 모든 메시지가 표시됩니다.
그러나 물론 그것은 우리에게 충분하지 않습니다. 우리는 결국 컴퓨터 괴짜이고 논리적인 표현으로 살고 있습니다. 더 깊이 들어가야합니다!
$ journalctl _HOSTNAME=theta _UID=70 + _HOSTNAME=epsilon _COMM=avahi-daemon
'+'는 동일한 필드를 두 번 일치시킬 때 암시된 OR에 추가하여 사용할 수있는 명시적 OR입니다. 따라서 위의 줄은 다음을 의미합니다: UID 70을 사용하는 호스트 theta 또는 프로세스 이름이 avahi-daemon 인 호스트 epsilon의 모든 것을 표시합니다.
(이제 마법이됩니다!)
이미 꽤 멋 있었죠? 맞습니다! 하지만 필드가 저널에서 취할 수 있는 모든 가치를 기억할 수 있는 사람이 누가있겠습니까? 진지하게 말하면 누가 사진에 대한 기억을 가지고 있습니까? 글쎄요, 저널은 가지고 있습니다:
$ journalctl -F _SYSTEMD_UNIT
이렇게하면 _SYSTEMD_UNIT 필드가 데이터베이스에서 사용하는 모든 값, 즉 저널에 로그인한 모든 systemd 서비스의 이름을 보여줍니다. 이렇게하면 멋진 매치를 쉽게 만들 수 있습니다. 그러나 잠깐, 이 모든 것이 실제로 bash에서 쉘 완성과 연결되어 있는 것으로 밝혀졌습니다! 이것은 훨씬 더 멋집니다: 일치 표현식을 입력하면 잘 알려진 필드 이름 목록과 그들이 취할 수 있는 값들이 표시됩니다! SELinux 레이블을 다시 필터링하는 방법을 알아 봅시다. 필드 이름이 SELINUX와 함께 있었던 것을 기억합니다. 시도해 보겠습니다:
$ journalctl _SE<TAB>
그리고 yupp, 즉시 완료됩니다:
$ journalctl _SELINUX_CONTEXT=
멋지지만 우리가 다시 매치시키고 싶었던 레이블은 무엇입니까?
$ journalctl _SELINUX_CONTEXT=<TAB><TAB>
kernel system_u:system_r:local_login_t:s0-s0:c0.c1023 system_u:system_r:udev_t:s0-s0:c0.c1023
system_u:system_r:accountsd_t:s0 system_u:system_r:lvm_t:s0 system_u:system_r:virtd_t:s0-s0:c0.c1023
system_u:system_r:avahi_t:s0 system_u:system_r:modemmanager_t:s0-s0:c0.c1023 system_u:system_r:vpnc_t:s0
system_u:system_r:bluetooth_t:s0 system_u:system_r:NetworkManager_t:s0 system_u:system_r:xdm_t:s0-s0:c0.c1023
system_u:system_r:chkpwd_t:s0-s0:c0.c1023 system_u:system_r:policykit_t:s0 unconfined_u:system_r:rpm_t:s0-s0:c0.c1023
system_u:system_r:chronyd_t:s0 system_u:system_r:rtkit_daemon_t:s0 unconfined_u:system_r:unconfined_t:s0-s0:c0.c1023
system_u:system_r:crond_t:s0-s0:c0.c1023 system_u:system_r:syslogd_t:s0 unconfined_u:system_r:useradd_t:s0-s0:c0.c1023
system_u:system_r:devicekit_disk_t:s0 system_u:system_r:system_cronjob_t:s0-s0:c0.c1023 unconfined_u:unconfined_r:unconfined_dbusd_t:s0-s0:c0.c1023
system_u:system_r:dhcpc_t:s0 system_u:system_r:system_dbusd_t:s0-s0:c0.c1023 unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
system_u:system_r:dnsmasq_t:s0-s0:c0.c1023 system_u:system_r:systemd_logind_t:s0
system_u:system_r:init_t:s0 system_u:system_r:systemd_tmpfiles_t:s0
아! 맞아요! PolicyKit의 보안 레이블 아래에 기록된 모든것을 보고 싶었습니다:
$ journalctl _SELINUX_CONTEXT=system_u:system_r:policykit_t:s0
와우! 그거 쉽습니다! SELinux와 관련된 어떤 것도 쉽게 할 수 있다는 것을 몰랐습니다! ;-) 물론 이런 종류의 완성은 SELinux 레이블 뿐만 아니라 모든 필드에서 작동합니다.
이제 너무 많이 했습니다. journalctl(1)에는 이것보다 훨씬 더 멋진 것이 있습니다. 예를 들어 JSON 출력을 생성합니다! 커널 필드와 일치시킬 수 있습니다! 간단한 /var/log/messages와 유사한 출력을 얻을 수 있지만 상대적인 타임 스탬프가 있습니다! 그리고 훨씬 더!
어쨌든, 다음 주에 저널이 당신을 위해 할 수 있는 모든 멋진 일들에 대한 더 많은 이야기를 게시하고 싶습니다. 이것은 시작에 불과합니다. 계속 지켜봐주십시오.
[1] systemd 195는 현재 Bodhi에 있지만 곧 F18이 제대로 적용되기를 바랍니다. 그리고 확실히 Fedora 18이 출시되기 전에.
[2] OK, 나는 여기에서 속임수를 썼습니다. 블록 장치에 의한 인덱싱은 아직 커널에 없지만 Hannes의 환상적인 작업으로 인해 진행 중이며 F18에 나타나기를 바랍니다.
(원문: http://0pointer.de/blog/projects/resources.html)
현대 컴퓨팅의 중요한 측면은 리소스 관리입니다. 단일 컴퓨터에서 둘 이상의 프로그램을 실행하는 경우 특정 정책을 적용하여 사용 가능한 리소스를 할당 할 수 있습니다. 이는 부족한 리소스가 주요 제약인 소형, 임베디드 또는 모바일 시스템에서 특히 중요합니다. 하지만 자원이 풍부한 반면 단일 노드에 있는 프로그램/서비스/컨테이너의 수는 훨씬 더 많은 클라우드 설정과 같은 대규모 설치의 경우에도 동일합니다.
전통적으로 Linux에서는 하나의 정책만 실제로 사용할 수 있었습니다: 모든 프로세스는 프로세스 nice 값을 통해 약간 변조된 거의 동일한 CPU 시간 또는 IO 대역폭을 얻었습니다. 이 접근 방식은 매우 간단하며 오랫동안 Linux의 다양한 용도를 다루었습니다. 그러나 다음과 같은 단점이 있습니다: 모든 프로세스가 균등할 자격이 있는 것은 아니며 많은 프로세스를 포함하는 서비스(CGI 쓰레드가 많은 Apache를 생각하십시오)가 아주 적은 프로세스를 같는 서비스(syslog를 생각하십시오) 보다 더 많은 리소스를 얻을 수 있습니다.
systemd를 위한 서비스 관리를 생각할 때, 우리는 자원 관리가 그것의 핵심 기능 이어야 한다는 것을 금방 깨달았습니다.서버 또는 임베디드 여부에 관계없이, 현대 사회에서 다양한 서비스의 CPU, 메모리 및 IO 리소스를 제어하는 것은 나중에 고려할 수 없지만 일류 서비스 설정으로 내장되어야합니다. 그리고 그것은 전통적인 nice 값이나 POSIX Resource Limits처럼 프로세스당(per-process)이 아니라 서비스당(per-service)이어야 합니다.
이 이야기에서는 시스템 서비스에 대한 리소스 정책을 시행하기 위해 할 수 있는 일에 대해 설명하고자 합니다. 이미 한동안 systemd에서 리소스 관리를 사용할 수 있었으므로 이제는 더 많은 청중에게 이를 소개할 때 입니다.
이전 블로그 게시물에서 레이블이 지정된 계층적 그룹화 메커니즘인 Linux Control Croup(cgroup)와 리소스 제어 하위 시스템인 Linux cgroup의 차이점을 강조했습니다. systemd에는 전자가 필요하지만 후자는 선택 사항입니다. 그리고 이 선택적 후반부는 이제 서비스별 리소스를 관리하는데 사용할 수 있습니다. (이 시점에서 cgroup이 무엇인지, 무엇을 성취하는지 최소한 기본적인 아이디어를 얻으려면 계속 읽기 전에 cgroup에 대해 읽어 보는 것이 좋습니다. 아래의 설명이 꽤 높은 수준이라고 생각하더라도 모든 것이 배경을 조금 더듬으면 훨씬 더 의미가 있습니다)
리소스 관리를 위한 주요 Linux cgroup 컨트롤러는 cpu, memory 및 blkio 입니다. 이를 사용하려면 커널에서 활성화 해야하며, 많은 배포판 (Fedora 포함)이 수행합니다. systemd는 까다로운 커널 세부 정보에 대해 너무 많은 지식을 요구하지 않고도 이러한 컨트롤러를 사용할 수 있도록 몇 가지 고급 서비스 설정을 제공합니다.
기본적으로 CPU 컨트롤러가 커널에서 활성화되어 있으면 systemd는 시작할때 각 서비스에 대해 cgroup을 생성합니다. 추가 구성이 없으면 이미 한 가지 좋은 효과가 있습니다. systemd 시스템에서 모든 시스템 서비스는 구성 되어있는 프로세스 수에 관계없이 CPU의 양이 균등합니다. 즉, 웹서버에서 MySQL은 Apache와 거의 동일한 양의 CPU를 얻습니다. 비록 후자가 1000 개의 CGI 스크립트 프로세스로 구성되어 있지만 전자는 몇 가지 작업자 작업중 하나 일뿐입니다. (이 동작은 끌 수 있습니다. /etc/systemd/system.conf의 DefaultControllers= 를 참조하십시오)
이 기본값 외에도 CPUShares= 설정을 사용하여 서비스가 가져 오는 CPU 공유를 명시적으로 구성할 수 있습니다. 기본값은 1024입니다. 이 숫자를 늘리면 1024에서 변경되지 않은 CPU보다 더 많은 CPU를 서비스에 할당하고 줄이면 더 적게 할당합니다.
이것을 어떻게 활용할 수 있는지 더 자세히 살펴 보겠습니다. 기본값인 1024 대신 Apache 1500 CPU 공유를 할당한다고 가정해 보겠습니다. 이를 위해 /etc/systemd/system/httpd.service에 Apache용 새 관리자 서비스 파일을 생성하고 공급 업체가 제공한 /usr/lib/systemd/system/httpd.service를 오버라이딩 합니다. 하지만 CPUShares= 매개 변수를 변경해 보겠습니다:
.include /usr/lib/systemd/system/httpd.service
[Service]
CPUShares=1500
첫 번째 줄은 공급 업체 서비스 파일을 가져옵니다. 이제 systemd의 구성을 다시로드하고 Apache를 다시 시작하여 새 서비스 파일을 고려합니다:
systemctl daemon-reload
systemctl restart httpd.service
그리고 예~, 이미 완료 되었습니다.
(유닛 파일에서 CPUShares= 를 설정하면 cpu가 DefaultControllers= 에 포함되지 않은 경우에도 특정 서비스가 cpu 계층 구조에서 자체 cgroup을 가져옵니다)
물론, 질문에서 서비스의 리소스 사용량을 실제로 이해하지 않고 리소스 할당을 변경하는 것은 장님 비행(맹목적인 비행)과 같습니다. 모든 서비스의 리소스 사용량을 이해하는데 도움이 되도록 시스템의 모든 cgroup을 열거하고 해당 리소스 사용량 (CPU, 메모리 및 IO)을 결정하고 최상위 방식으로 표시하는 systemd-cgtop 도구를 만들었습니다. systemd 서비스가 cgroup에서 관리된다는 사실을 바탕으로 이 도구는 프로세스에 대해 가장 많이 표시되는 서비스를 제공할 수 있습니다.
안타깝게도 기본적으로 cgtop은 서비스별 CPU 사용량만 차트로 표시할 수 있으며 IO 및 메모리는 전체 시스템에 대한 총계로만 추적됩니다. 그 이유는 기본적으로 blkio 및 메모리 컨트롤러 계층에 서비스별 cgroup이 없지만 리소스 사용량을 결정하는데 필요하기 때문입니다. 모든 서비스에 대해 이 데이터를 얻는 가장 좋은 방법은 단순히 메모리와 blkio 컨트롤러를 system.conf의 앞서 언급한 DefaultControllers= 설정에 추가하는 것입니다.
메모리에 제한을 적용하기 위해 systemd는 서비스에 대한 MemoryLimit= 및 MemorySoftLimit= 설정을 제공하여 모든 프로세스의 메모리를 합산합니다. 이러한 설정은 서비스의 총 메모리 제한인 메모리 크기 (바이트)를 사용합니다. 이 설정은 킬로바이트, 메가 바이트, 기가 바이트, 테라 바이트에 대한 일반적인 K, M, G, T 접미사 (1024 기준)를 이해합니다.
.include /usr/lib/systemd/system/httpd.service
[Service]
MemoryLimit=1G
(위의 CPUShares= 와 유사하게 이 옵션을 설정하면 서비스가 메모리 cgroup 계층 구조에서 자체 cgroup을 얻습니다)
블록 IO를 제어하기 위해 여러 설정을 사용할 수 있습니다. 우선 특정 서비스에 IO 가중치를 할당하는 BlockIOWeight= 를 사용할 수 있습니다. 동작에서 가중치 개념은 CPU 리소스 제어의 공유 개념과 다르지 않습니다 (위 참조). 그러나 기본 가중치는 1000 이고 유효한 범위는 10에서 1000까지입니다:
.include /usr/lib/systemd/system/httpd.service
[Service]
BlockIOWeight=500
선택적으로 장치별 가중치를 지정할 수 있습니다:
.include /usr/lib/systemd/system/httpd.service
[Service]
BlockIOWeight=/dev/disk/by-id/ata-SAMSUNG_MMCRE28G8MXP-0VBL1_DC06K01009SE009B5252 750
실제 장치 노드를 지정하는 대신 파일 시스템의 경로도 지정합니다:
.include /usr/lib/systemd/system/httpd.service
[Service]
BlockIOWeight=/home/lennart 750
지정된 경로가 장치 노드를 참조하지 않는 경우 systemd는 블록 장치 /home/lennart가 켜져 있는지 확인하고 여기에 대역폭 가중치를 할당합니다.
장치별 및 일반 줄을 동시에 추가할 수도 있습니다. 그러면 장치에 대한 장치별 가중치가 설정되고 다른 값은 다른 모든 항목에 대한 기본값으로 설정됩니다.
또는 BlockIOReadBandwidth= 및 BlockIOWriteBandwidth= 설정을 사용하여 명시적 대역폭 제한을 제어할 수 있습니다. 이러한 설정은 한 쌍의 장치 노드 및 대역폭 속도 (초당 바이트) 또는 파일 경로 및 대역폭 속도를 사용합니다:
.include /usr/lib/systemd/system/httpd.service
[Service]
BlockIOReadBandwith=/var/log 5M
이는 /var/log를 지원하는 블록 장치의 최대 읽기 대역폭을 5Mb/s로 설정합니다.
(CPUShares= 및 MemoryLimit= 와 유사하게 이 세 가지 설정중 하나를 사용하면 서비스가 blkio 계층 구조에서 자체 cgroup을 가져옵니다)
위에 설명된 옵션은 다양한 Linux 컨트롤 그룹 컨트롤러가 노출하는 사용 가능한 컨트롤의 일부만 포함합니다. 우리는 이것들이 대부분의 사람들에게 가장 관련성이 있고 유닛을 적절하게 처리하고 블록 장치 이름을 확인할 수 있는 멋진 인터페이스가 정말로 필요하다고 가정했기 때문에이를 선택하고 고급 옵션을 추가했습니다.
대부분의 경우 위에서 설명한 옵션은 사용 사례에 충분하지 않을 수 있지만 낮은 수준의 커널 cgroup 설정이 도움이 될 수 있습니다. 시스템 단위 파일에서 이러한 옵션을 높은 수준의 설정으로 다루지 않고도 쉽게 사용할 수 있습니다. 예를 들어, 때때로 서비스의 교체를 설정하는 것이 유용할 수 있습니다. 커널은 memory.swappiness cgroup 속성을 통해 이를 제어할 수 있지만 systemd는 이를 고급 옵션으로 노출하지 않습니다. 그럼에도 불구하고 낮은 수준의 ControlGroupAttribute= 설정을 사용하여 사용하는 방법은 다음과 같습니다:
.include /usr/lib/systemd/system/httpd.service
[Service]
ControlGroupAttribute=memory.swappiness 70
(다른 경우와 유사하게 이것 역시 서비스가 메모리 계층 구조에 추가되도록합니다)
나중에 다양한 cgroup 속성에 대해 더 높은 수준의 컨트롤을 추가할 수 있습니다. 실제로 자주 사용하고 더 집중할 가치가 있다고 생각하는 경우 우리에게 핑해주세요. 그런 다음 고급 옵션을 추가하는 것을 고려할 것입니다. (더 나은 방법: 패치를 보내주세요!)
고지 사항: 다양한 리소스 컨트롤러를 사용하면 시스템의 런타임에 영향을 미칩니다. 리소스 제한을 적용하려면 대가가 따릅니다. 이를 사용하면 특정 작업이 느려집니다. 특히 메모리 컨트롤러는 성능 저하로 인해 나쁜 평판을 얻었습니다.
이 모든 것에 대한 자세한 내용은 언급된 유닛 설정과 cpu, 메모리 및 blkio 컨트롤러에 대한 문서를 참조하십시오.
이제 여기까지 입니다. 물론이 블로그 스토리는 서비스별 리소스 설정에만 중점을 둡니다. 여기에 더 전통적이고 잘 알려진 프로세스별 리소스 설정을 설정할 수도 있습니다. 그러면 다양한 하위 프로세스에서 상속되지만 항상 프로세스별로 만 적용됩니다. 보다 구체적으로 IOSchedulingClass=, IOSchedulingPriority=, CPUSchedulingPolicy=, CPUSchedulingPriority=, CPUAffinity=, LimitCPU= 및 관련 항목입니다. 이들은 cgroup 컨트롤러를 사용하지 않으며 성능 비용이 훨씬 낮습니다. 나중에 기사에서 더 자세히 다룰 수 있습니다.
(원문: http://0pointer.de/blog/projects/detect-virt.html)
systemd에서 작업을 시작했을때 우리는 Linux에서 실제로 사용되는 다양한 기존 초기화 스크립트가 무엇을 사용하는지 자세히 살펴 보았습니다. 무엇보다도 우리는 가상화된 환경 (예: kvm, VMWare, LXC 게스트 등)에서 실행 중인지 여부를 명시 적으로 확인하는 많은 사람들이 있음을 발견했습니다.일부 초기화 스크립트는 이러한 경우 자체적으로 비활성화되고 [1], 다른 스크립트는 이러한 경우에만 활성화 되었습니다 [2]. 종종 명시적으로 가상화를 확인하는 것보다 다른 조건을 확인하는 것이 더 나은 생각이었을 것입니다. 그러나 이를 모든 측면에서 살펴본 결과 많은 경우에 발견된 가상화를 기반으로 명시적으로 서비스를 조건화하는 것이 유효한 일이라는 결론에 도달했습니다. 결과적으로 다음과 같이 서비스를 조건화 하는데 사용할 수 있는 새로운 구성 옵션을 systemd에 추가했습니다: ConditionVirtualization; 또한 셸 스크립트에서 가상화를 감지하는데 사용할 수 있는 작은 도구를 추가했습니다: systemd-detect-virt(1); 마지막으로 다른 애플리케이션에서 이를 쿼리하기 위해 최소 버스 인터페이스를 추가했습니다.
코드가 가상화된 환경에서 실행되는지 여부를 감지하는 것은 실제로 그렇게 어렵지 않습니다. 정확히 감지하려는 항목에 따라 CPUID 명령을 실행하고 /sys 및 /proc에서 몇 개의 파일을 확인하는 것 이상입니다. 복잡성은 대부분 찾을 문자열을 알고 이 목록을 최신 상태로 유지하는 것입니다. 현재 systemd의 가상화 감지 코드는 다음 가상화 시스템을 감지할 수 있습니다.
Hardware virtualization (i.e. VMs):
Same-kernel virtualization (i.e. containers):
이 기능을 사용할 수 있는 방법을 살펴 보겠습니다.
단위 파일의 [Unit] 섹션에 ConditionVirtualization을 추가하면 어떤 가상화가 사용되는지 또는 전혀 사용되는지 여부에 따라 조건화하기에 충분합니다. 예를 들면 다음과 같습니다:
[Unit]
Name=My Foobar Service (runs only only on guests)
ConditionVirtualization=yes
[Service]
ExecStart=/usr/bin/foobard
"yes" 또는 "no"를 지정하는 대신 특정 가상화 솔루션(예: "kvm", "vmware", ...)의 ID를 지정하거나 "container" 또는 "vm"을 지정하여 커널이 가상화되었는지 또는 하드웨어인지 확인할 수 있습니다. 또한 체크 앞에 느낌표 ("!")를 붙여 체크를 반전시킬 수 있습니다. 자세한 내용은 매뉴얼 페이지를 참조하십시오.
쉘 스크립트에서는 systemd-detect-virt(1) 도구를 사용하여 가상화된 시스템을 쉽게 확인할 수 있습니다. 예를 들면 다음과 같습니다.
if systemd-detect-virt -q ; then
echo "Virtualization is used:" `systemd-detect-virt`
else
echo "No virtualization is used."
fi
이 도구를 실행하면 가상화 솔루션이 발견되면 종료 코드 0 (성공)이 반환되고 그렇지 않으면 0이 아닙니다. 또한 -q로 억제할 수 있는 사용된 가상화 솔루션의 짧은 식별자를 인쇄합니다. 또한 -c 및 -v 매개 변수를 사용하면 커널만 감지하거나 하드웨어 가상화 환경만 감지 할 수 있습니다. 자세한 내용은 매뉴얼 페이지를 참조하십시오.
가상화 사용 가능 여부는 시스템 버스에서도 내 보냅니다:
$ gdbus call --system --dest org.freedesktop.systemd1 --object-path /org/freedesktop/systemd1 --method org.freedesktop.DBus.Properties.Get org.freedesktop.systemd1.Manager Virtualization
(<'systemd-nspawn'>,)
이 속성에는 가상화가 감지되지 않은 경우 빈 문자열이 포함됩니다. 일부 컨테이너 환경은 권한이 없는 코드에서 직접 감지 할 수 없습니다. 이것이 우리가 라이브러리를 제공하는 대신 버스에 이 속성을 노출하는 이유입니다. 버스는 암시적으로 권한 문제를 아주 훌륭하게 해결합니다.
이 모든 것은 "가장 내부" 가상화 솔루션에 대한 정보만 감지하고 반환합니다. 가상화를 스택하면 ("우리는 더 깊이 들어가야합니다!") 이러한 인터페이스는 코드가 가장 직접적으로 연결하는 인터페이스를 노출합니다. 특히 VM 내부에서 컨테이너 솔루션을 사용하는 경우 일반적으로 컨테이너만 감지되어 반환됩니다.
[1] 예: 물리적 하드웨어에 액세스 할 수 없는 컨테이너 환경에서 특정 장치 관리 서비스를 실행하는 것은 의미가 없습니다.
[2] 예: 일부 VM 솔루션은 어떤 방식으로든 게스트를 호스트와 연결하는 특정 공급 업체별 사용자 공간 구성 요소가 실행중인 경우 가장 잘 작동합니다.
(원문: http://0pointer.de/blog/projects/socket-activated-containers.html)
(소켓 활성화 인터넷 서비스 및 OS 컨테이너)
소켓 활성화는 systemd의 중요한 기능입니다. 처음 systemd를 발표했을 때 우리는 이미 소켓 서비스의 병렬화와 견고성을 높이고 부팅의 종속성 논리를 단순화 하는데 소켓 활성화가 얼마나 훌륭한지 지적하려고 했습니다. 이 에피소드에서는 소켓 활성화가 동일한 리소스 사용량으로 단일 시스템에서 실행할 수 있는 서비스와 컨테이너 수를 대폭 개선하는데 중요한 도구 인 이유를 설명하고 싶습니다. 즉, 시스템에서 고객 사이트의 밀도를 높이고 새 하드웨어에 대한 지출을 줄이는 방법입니다.
(소켓 활성화 인터넷 서비스)
먼저 한 발 뒤로 물러서 봅시다. 소켓 활성화는 무엇입니까? - 기본적으로 소켓 활성화는 단순히 systemd가 서비스를 대신하여 listening 소켓 (IP 또는 기타)을 설정한 다음 (아직 실행되지 않음) 첫 번째 연결이 들어 오자마자 서비스를 시작 (활성화)하는 것을 의미합니다. 기술에 따라 서비스는 연결 및 가능한 후속 연결을 처리한 후 잠시 유휴 상태가 될 수 있으므로 systemd는 소켓에서 다시 listen 대기하고 다음에 연결될때 서비스를 다시 활성화합니다. 클라이언트의 경우 관심있는 서비스가 현재 실행 중인지 여부가 표시되지 않습니다. 서비스의 IP 소켓은 계속 연결할 수 있으며 연결 시도가 실패하지 않으며 모든 연결이 즉시 처리됩니다.
이와 같은 설정은 리소스 사용량을 줄입니다: 서비스는 필요할 때만 실행되므로 필요할 때만 리소스를 소비합니다. 많은 인터넷 사이트와 서비스가 그 혜택을 누릴 수 있습니다. 예를 들어, 웹 사이트 호스팅 업체는 인터넷에 있는 수많은 웹 사이트중 극히 일부만이 지속적인 요청 스트림을 받는다는 사실을 알게 될 것입니다: 대부분의 웹 사이트는 여전히 항상 사용 가능해야하지만 요청을 매우 드물게 받습니다. 소켓 활성화와 같은 체계를 사용하면 이점을 얻을 수 있습니다. 이와 같은 단일 시스템에서 이러한 많은 사이트를 호스팅하고 필요한 경우에만 서비스를 활성화하면 상당한 수준의 오버 커밋이 허용됩니다. 사용 가능한 리소스가 실제로 허용하는 것보다 더 많은 사이트를 시스템에서 실행할 수 있습니다. 물론 사용량이 많을 때 경합을 피하기 위해 너무 많이 할당해서는 안됩니다.
이와 같은 소켓 활성화는 systemd에서 사용하기 쉽습니다. 많은 현대 인터넷 데몬은 이미 기본적으로 소켓 활성화를 지원합니다 (아직 추가하기가 어렵지 않은 경우). systemd의 인스턴스화된 유닛 지원과 함께 서비스 및 소켓 템플릿 쌍을 쉽게 작성할 수 있으며, 각 사이트에 대해 한 번씩 여러번 인스턴스화 할 수 있습니다. 그런 다음 (선택 사항) systemd의 일부 보안 기능을 사용하여 고객의 사이트 서비스를 서로 분리하면 됩니다. (think: 각 고객의 서비스는 고객의 홈 디렉토리만 볼 수 있어야하며 다른 모든 디렉토리는 보이지 않아야합니다): 이제 최소한의 리소스로 최대한의 안전한 샌드 박스 서비스를 제공하고 OS의 기본 제공 기술로 훌륭하게 수행되는 확장성과 안정성이 뛰어난 서버 시스템을 갖게 되었습니다.
이러한 종류의 설정은 이미 많은 회사에서 프로덕션 용도로 사용되고 있습니다. 예를 들어 Pantheon의 위대한 사람들은 이와 유사한 설정에서 확장 가능한 인스턴트 Drupal 시스템을 실행하고 있습니다. (사실, 판테온의 David Strauss가 이 계획을 개척했습니다. David, 당신은 멋져요!)
(소켓 활성화 OS 컨테이너)
위의 모든 작업은 이전 버전의 systemd에서 이미 수행할 수 있습니다. systemd 기반의 배포를 사용하는 경우 위에서 설명한 것과 같은 시스템을 즉시 설정할 수 있습니다. 그러나 이것을 한 단계 더 나아 갑시다. systemd 197 (Fedora 19에 포함될 예정)을 사용하여 개별 서비스뿐만 아니라 전체 OS 컨테이너를 활성화하는 소켓 활성화에 대한 지원을 추가했습니다. 그리고 저는 이 시점에서 정말로 말해야 합니다: 이것은 제가 정말 흥분되는 것입니다. ;-)
기본적으로 소켓 활성화 OS 컨테이너를 사용하면 호스트의 systemd 인스턴스가 컨테이너를 대신하여 여러 포트 (예: SSH용, 웹용, 데이터베이스용)를 수신하고 첫 번째 연결이 들어 오자마자, 이것이 의도한 컨테이너를 스폰하고 세 소켓 모두에 전달합니다. 컨테이너 내부에서 다른 systemd가 실행 중이며 소켓을 수락한 다음 일반 소켓 활성화를 사용하여 컨테이너 내부에서 실행되는 서비스에 더 배포합니다. SSH, 웹 및 데이터베이스 서비스는 원래 호스트에서 생성된 소켓에 의해 활성화 되었더라도 컨테이너 내부만 볼 수 있습니다! 다시 말하지만, 클라이언트에게는 이 모든 것이 보이지 않습니다. 전체 OS 컨테이너가 생성되고 간단한 네트워크 연결에 의해 트리거되는 것은 클라이언트 측에 완전히 투명합니다. [1]
OS 컨테이너에는 (이름에서 알 수 있듯이) 전체 운영 체제가 포함될 수 있으며, 이는 호스트에서 실행되는 것과 다른 배포 일 수도 있습니다. 예를 들어 Fedora에서 호스트를 실행할 수 있지만 그 안에서 여러 Debian 컨테이너를 실행할 수 있습니다. OS 컨테이너는 자체 시스템 초기화 시스템, 자체 SSH 인스턴스, 자체 프로세스 트리 등을 갖지만 호스트와 다른 여러 기능 (예: 메모리 관리)을 공유합니다.
현재로서는 systemd의 사소한 컨테이너 관리자인 systemd-nspawn 만 이러한 종류의 소켓 활성화를 지원하도록 업데이트 되었습니다. libvirt-lxc가 곧 유사한 기능을 갖게되기를 바랍니다. 이 시점에서 nspawn을 사용하여 이러한 설정이 systemd에서 구성되는 방법을 자세히 살펴 보겠습니다:
먼저 debootstrap 또는 yum의 --installroot와 같은 도구를 사용하여 컨테이너 OS tree[2]를 설정하세요. 이에 대한 세부 사항은 이 이야기에서 초점이 맞지 않습니다. 이를 수행하는 방법에 대한 많은 문서가 있습니다. 물론 컨테이너 내부에 systemd v197을 설치했는지 확인하십시오. 명령 줄에서 컨테이너에 액세스하려면 systemd-nspawn 자체를 사용하는 것이 좋습니다. 모든 것을 올바르게 구성한 후 systemd-nspawn의 -b 스위치를 사용하여 명령 줄에서 부팅 해보십시오.
이제 정상적으로 부팅되는 작업 컨테이너가 있다고 가정하고 해당 컨테이너를 시작 및 중지 할 수 있는 호스트의 시스템 서비스로 전환하기 위해 해당 컨테이너에 대한 서비스 파일을 작성해 보겠습니다. 호스트에 /etc/systemd/system/mycontainer.service를 생성해 보겠습니다:
[Unit]
Description=My little container
[Service]
ExecStart=/usr/bin/systemd-nspawn -jbD /srv/mycontainer 3
KillMode=process
이 서비스는 systemctl start 및 systemctl stop을 통해 이미 시작 및 중지 할 수 있습니다. 그러나 실제로 컨테이너 내부에서 쉘 프롬프트를 얻는 좋은 방법은 없습니다. 이제 SSH를 추가해 보겠습니다: 컨테이너의 SSH 포트에 대한 연결이 전체 컨테이너를 소켓 활성화하도록 SSH를 구성해 보겠습니다. 먼저, 호스트에게 컨테이너의 SSH 포트에서 수신 대기한다고 알려주는 것으로 시작하겠습니다. 호스트에 /etc/systemd/system/mycontainer.socket을 생성해 보겠습니다:
[Unit]
Description=The SSH socket of my little container
[Socket]
ListenStream=23
호스트에서 systemctl start로 이 장치를 시작하면 포트 23에서 수신 대기하고 연결이 들어 오자마자 위에서 정의한 컨테이너 서비스를 활성화합니다. 호스트의 SSH가 이미 수신 중이므로 일반적인 22 대신 포트 23을 선택합니다. nspawn은 프로세스 목록과 파일 시스템 트리를 가상화하지만 실제로 네트워크 스택을 가상화하지 않으므로 여기서 호스트와 다양한 컨테이너에 대해 다른 포트를 선택합니다.
물론 컨테이너 내부의 시스템은 소켓 활성화로 인해 전달되는 소켓을 어떻게 처리할지 아직 알지 못합니다. 이제 포트에 연결하려고하면 컨테이너가 시작되지만 컨테이너가 아직 처리할 수 없기 때문에 들어오는 연결이 즉시 닫힙니다. 그것을 고쳐 봅시다!
이를 위해 필요한 것은 컨테이너 소켓 활성화 내부에서 SSH를 가르치는 것입니다. 이를 위해 SSH 용 소켓 및 서비스 장치 쌍을 작성해 보겠습니다. 컨테이너에 /etc/systemd/system/sshd.socket을 생성해 보겠습니다:
[Unit]
Description=SSH Socket for Per-Connection Servers
[Socket]
ListenStream=23
Accept=yes
그런 다음 컨테이너에 일치하는 SSH 서비스 파일 /etc/systemd/system/sshd@.service를 추가해 보겠습니다:
[Unit]
Description=SSH Per-Connection Server for %I
[Service]
ExecStart=-/usr/sbin/sshd -i
StandardInput=socket
그런 다음 sshd.socket을 sockets.target에 연결하여 컨테이너가 부팅 될 때 장치가 자동으로 시작되도록 합니다:
ln -s /etc/systemd/system/sshd.socket /etc/systemd/system/sockets.target.wants/
그리고 그게 답니다. 이제 호스트에서 mycontainer.socket을 활성화하면 호스트의 systemd가 소켓을 바인딩하고 연결할 수 있습니다. 이렇게하면 호스트의 systemd가 컨테이너를 활성화하고 소켓을 컨테이너에 전달합니다. 그런 다음 컨테이너의 systemd가 소켓을 가져와 컨테이너 내부의 sshd.socket과 일치시킵니다. 여전히 들어오는 연결이 대기열에 있으므로 즉시 sshd@.service 인스턴스를 트리거하고 로그인을 갖게됩니다.
그리고 그걸로 이미 모든게 다 된겁니다. mycontainer.socket을 listen할 추가 소켓을 쉽게 추가할 수 있습니다. 여기에 나열된 모든 것은 활성화시 컨테이너로 전달되며 컨테이너 내부에 구성된 모든 소켓 유닛과 가능한 한 잘 일치합니다. 일치할 수 없는 소켓은 닫히고 전달되지 않았지만 수신하도록 구성된 소켓은 컨테이너의 시스템 인스턴스가 됩니다.
자, 다시 한 걸음 물러서 봅시다. 이 모든 것을 통해 우리는 무엇을 얻었습니까? 이제 기본적으로 단일 호스트에서 여러 개의 전체 OS 컨테이너를 제공할 수 있으며 컨테이너는 지속적으로 실행되지 않고 서비스를 제공할 수 있습니다. 따라서 호스트에서 OS 컨테이너의 밀도를 크게 높일 수 있습니다.
물론 이것은 하드웨어 가상화가 아닌 커널 기반 가상화에서만 작동합니다. 즉, 이와 같은 것은 libvirt-lxc 또는 nspawn과 같은 시스템에서만 구현할 수 있지만 qemu/kvm에서는 구현할 수 없습니다.
이와 같이 여러 개의 컨테이너를 설정한 경우 저널에서 할 수 있는 멋진 일이 있습니다. -m 을 호스트의 journalctl에 전달하면 모든 로컬 컨테이너의 저널을 자동으로 검색하고 디스플레이에 인터리브합니다. 멋지죠?
systemd 197을 사용하면 자체 소켓 활성화 OS 컨테이너를 온보드로 설정할 수 있습니다. 그러나 곧 추가 할 몇 가지 개선 사항이 있습니다: 예를 들어, 지금 당장은 컨테이너 내부의 모든 서비스가 유휴 상태에서 종료하더라도 컨테이너는 여전히 주변에 남아 있으며, 모든 서비스가 종료되고 로그인이 없는 경우 실제로 유휴 상태에서도 종료되도록 해야합니다. 밝혀진 바와 같이 우리는 이미 이를 위한 많은 인프라를 가지고 있습니다: 랩톱에 추가한 자동 일시 중지 기능을 재사용 할 수 있습니다: 랩톱이 유휴 상태일 때를 감지하고 일시 중단하는 것은 컨테이너가 유휴 상태일 때를 감지하고 종료하는 것과 매우 유사한 문제입니다.
어쨌든,이 블로그 이야기가 너무 길어졌습니다. 가상화, 소켓, 서비스, 다양한 OS 및 기타 항목에 대한 이 모든 이야기로 인해 이미 절반을 잃지 않았기를 바랍니다. 이 블로그 스토리가 강력하고 확장성이 뛰어난 서버 시스템을 설정하는 좋은 출발점이되기를 바랍니다. 더 알고 싶다면 문서를 참조하고 IRC 채널을 방문하십시오. 감사합니다!
[1] 그리고 BTW, 이것이 systemd가 제공하는 방식의 빠른 부팅 시간이 실제로 서버에서도 정말 좋은 이유입니다.
[2] 쉽게하려면: Fedora를 설치하기위해 yum --releasever=19 --nogpg --installroot=/srv/mycontainer/ --disablerepo='*' --enablerepo=fedora install systemd passwd yum fedora-release vim-minimal과 같은 명령 줄이 필요합니다. 그리고 Debian에서는 debootstrap --arch = amd64 unstable /srv/mycontainer/를 사용하십시오. systemd-nspawn(1)의 하단도 참조하십시오. 또한 감사(auditing)는 현재 컨테이너에 대해 중단되었으며 커널에서 활성화되면 컨테이너에서 모든 종류의 오류가 발생합니다. 호스트의 커널 명령 줄에서 audit=0을 사용하여 해제합니다.
(원문: http://0pointer.net/blog/systemd-for-administrators-part-xxi.html)
한동안 컨테이너는 Linux에서 뜨거운 주제 중 하나였습니다. libvirt-lxc, LXC 또는 Docker와 같은 컨테이너 관리자는 요즘 널리 알려져 있으며 사용됩니다. 이 블로그 스토리에서는 컨테이너 경계를 넘어 서비스를 원활하게 관리할 수 있도록 컨테이너 관리자와 systemd의 통합 지점에 대해 설명하고자 합니다.
여기서는 OS 컨테이너에 초점을 맞출 것입니다. 즉, 초기화 시스템이 컨테이너 내부에서 실행되고 따라서 컨테이너는 대부분의 경우 자체 독립 시스템처럼 보입니다. 여기에서 설명하는 내용의 대부분은 libvirt-lxc를 포함하여 여기에 설명된 논리를 구현하는 거의 모든 컨테이너 관리자에서 사용할 수 있습니다. 그러나 작업을 쉽게하기 위해 systemd 자체와 함께 제공되는 미니 컨테이너 관리자인 systemd-nspawn에 중점을 둘 것입니다. systemd-nspawn은 다른 컨테이너 관리자와 동일한 커널 인터페이스를 사용하지만 모든 낮은 수준의 세부 사항을 구성할 수 있는 일반적인 도구가 되려고하지 않고 가능한 한 사용하기 쉽고 "그냥 작동하는" 컨테이너 관리자로 설계 되었기 때문에 유연성이 떨어집니다. systemd를 개발할 때 systemd-nspawn을 광범위하게 사용합니다.
어쨌든, 우리의 실행을 시작합시다. 하위 디렉토리에 Fedora 컨테이너 트리를 생성하여 시작하겠습니다:
# yum -y --releasever=20 --nogpg --installroot=/srv/mycontainer --disablerepo='*' --enablerepo=fedora install systemd passwd yum fedora-release vim-minimal
이것은 최소한의 Fedora 시스템을 다운로드하고 /srv/mycontainer에 설치합니다. 이 명령줄은 Fedora 전용이지만 대부분의 배포판은 어떤식 으로든 유사한 기능을 제공합니다. systemd-nspawn(1) 매뉴얼 페이지의 예제 섹션에는 다른 배포를 위한 다양한 명령줄 목록이 포함되어 있습니다.
이제 새 컨테이너가 설치되었으므로 초기 루트 암호를 설정하겠습니다:
# systemd-nspawn -D /srv/mycontainer
Spawning container mycontainer on /srv/mycontainer
Press ^] three times within 1s to kill container.
-bash-4.2# passwd
Changing password for user root.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.
-bash-4.2# ^D
Container mycontainer exited successfully.
#
여기서 systemd-nspawn을 사용하여 컨테이너에서 셸을 가져온 다음 passwd를 사용하여 루트 암호를 설정합니다. 그 후 초기 설정이 완료되었으므로 부팅하고 새 암호를 사용하여 루트로 로그인하겠습니다:
$ systemd-nspawn -D /srv/mycontainer -b
Spawning container mycontainer on /srv/mycontainer.
Press ^] three times within 1s to kill container.
systemd 208 running in system mode. (+PAM +LIBWRAP +AUDIT +SELINUX +IMA +SYSVINIT +LIBCRYPTSETUP +GCRYPT +ACL +XZ)
Detected virtualization 'systemd-nspawn'.
Welcome to Fedora 20 (Heisenbug)!
[ OK ] Reached target Remote File Systems.
[ OK ] Created slice Root Slice.
[ OK ] Created slice User and Session Slice.
[ OK ] Created slice System Slice.
[ OK ] Created slice system-getty.slice.
[ OK ] Reached target Slices.
[ OK ] Listening on Delayed Shutdown Socket.
[ OK ] Listening on /dev/initctl Compatibility Named Pipe.
[ OK ] Listening on Journal Socket.
Starting Journal Service...
[ OK ] Started Journal Service.
[ OK ] Reached target Paths.
Mounting Debug File System...
Mounting Configuration File System...
Mounting FUSE Control File System...
Starting Create static device nodes in /dev...
Mounting POSIX Message Queue File System...
Mounting Huge Pages File System...
[ OK ] Reached target Encrypted Volumes.
[ OK ] Reached target Swap.
Mounting Temporary Directory...
Starting Load/Save Random Seed...
[ OK ] Mounted Configuration File System.
[ OK ] Mounted FUSE Control File System.
[ OK ] Mounted Temporary Directory.
[ OK ] Mounted POSIX Message Queue File System.
[ OK ] Mounted Debug File System.
[ OK ] Mounted Huge Pages File System.
[ OK ] Started Load/Save Random Seed.
[ OK ] Started Create static device nodes in /dev.
[ OK ] Reached target Local File Systems (Pre).
[ OK ] Reached target Local File Systems.
Starting Trigger Flushing of Journal to Persistent Storage...
Starting Recreate Volatile Files and Directories...
[ OK ] Started Recreate Volatile Files and Directories.
Starting Update UTMP about System Reboot/Shutdown...
[ OK ] Started Trigger Flushing of Journal to Persistent Storage.
[ OK ] Started Update UTMP about System Reboot/Shutdown.
[ OK ] Reached target System Initialization.
[ OK ] Reached target Timers.
[ OK ] Listening on D-Bus System Message Bus Socket.
[ OK ] Reached target Sockets.
[ OK ] Reached target Basic System.
Starting Login Service...
Starting Permit User Sessions...
Starting D-Bus System Message Bus...
[ OK ] Started D-Bus System Message Bus.
Starting Cleanup of Temporary Directories...
[ OK ] Started Cleanup of Temporary Directories.
[ OK ] Started Permit User Sessions.
Starting Console Getty...
[ OK ] Started Console Getty.
[ OK ] Reached target Login Prompts.
[ OK ] Started Login Service.
[ OK ] Reached target Multi-User System.
[ OK ] Reached target Graphical Interface.
Fedora release 20 (Heisenbug)
Kernel 3.18.0-0.rc4.git0.1.fc22.x86_64 on an x86_64 (console)
mycontainer login: root
Password:
-bash-4.2#
이제 우리는 systemd의 컨테이너 통합을 가지고 놀 준비가되었습니다. 첫 번째 도구인 machinectl을 살펴 보겠습니다. 매개 변수없이 실행하면 로컬에서 실행중인 모든 컨테이너 목록이 표시됩니다:
$ machinectl
MACHINE CONTAINER SERVICE
mycontainer container nspawn
1 machines listed.
"status"하위 명령어는 컨테이너에 대한 세부 정보를 표시합니다:
$ machinectl status mycontainer
mycontainer:
Since: Mi 2014-11-12 16:47:19 CET; 51s ago
Leader: 5374 (systemd)
Service: nspawn; class container
Root: /srv/mycontainer
Address: 192.168.178.38
10.36.6.162
fd00::523f:56ff:fe00:4994
fe80::523f:56ff:fe00:4994
OS: Fedora 20 (Heisenbug)
Unit: machine-mycontainer.scope
├─5374 /usr/lib/systemd/systemd
└─system.slice
├─dbus.service
│ └─5414 /bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-act...
├─systemd-journald.service
│ └─5383 /usr/lib/systemd/systemd-journald
├─systemd-logind.service
│ └─5411 /usr/lib/systemd/systemd-logind
└─console-getty.service
└─5416 /sbin/agetty --noclear -s console 115200 38400 9600
이를 통해 제어 그룹 트리 (프로세스 포함), IP 주소 및 루트 디렉토리를 포함하여 컨테이너에 대한 흥미로운 정보를 볼 수 있습니다.
"login" 하위 명령은 컨테이너에 새 로그인 셸을 가져옵니다:
# machinectl login mycontainer
Connected to container mycontainer. Press ^] three times within 1s to exit session.
Fedora release 20 (Heisenbug)
Kernel 3.18.0-0.rc4.git0.1.fc22.x86_64 on an x86_64 (pts/0)
mycontainer login:
"reboot" 하위 명령은 컨테이너를 재부팅합니다:
# machinectl reboot mycontainer
The "poweroff" subcommand powers the container off:
# machinectl poweroff mycontainer
machinectl 도구에 대해 너무 많이 언급했습니다. 이 도구는 몇 가지 명령을 더 알고 있습니다. 자세한 내용은 man 페이지를 확인하십시오. 여기서는 systemd-nspawn을 컨테이너 관리자로 사용하더라도 여기에 설명된 논리를 구현하는 모든 컨테이너 관리자 (예: libvirt-lxc 포함)에 개념이 적용됩니다.
machinectl은 컨테이너와 함께 유용한 유일한 도구는 아닙니다. 많은 systemd의 자체 도구가 컨테이너를 명시적으로 지원하도록 업데이트 되었습니다! 이를 시도해 봅시다 (먼저 컨테이너를 다시 시작한 후 위에서 systemd-nspawn 명령을 반복합니다):
# hostnamectl -M mycontainer set-hostname "wuff"
이것은 로컬 컨테이너에서 hostnamectl(1)을 사용하고 호스트 이름을 설정합니다.
마찬가지로 로컬 컨테이너에 연결하기 위해 다른 많은 도구가 업데이트되었습니다. 다음은 systemctl(1)의 -M 스위치입니다:
# systemctl -M mycontainer
UNIT LOAD ACTIVE SUB DESCRIPTION
-.mount loaded active mounted /
dev-hugepages.mount loaded active mounted Huge Pages File System
dev-mqueue.mount loaded active mounted POSIX Message Queue File System
proc-sys-kernel-random-boot_id.mount loaded active mounted /proc/sys/kernel/random/boot_id
[...]
time-sync.target loaded active active System Time Synchronized
timers.target loaded active active Timers
systemd-tmpfiles-clean.timer loaded active waiting Daily Cleanup of Temporary Directories
LOAD = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB = The low-level unit activation state, values depend on unit type.
49 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.
예상대로 호스트가 아닌 지정된 컨테이너에 있는 활성 장치 목록이 표시됩니다. (여기서 출력은 짧아지고 블로그 스토리는 이미 너무 길어지고 있습니다).
이를 사용하여 컨테이너 내에서 서비스를 다시 시작해 보겠습니다:
# systemctl -M mycontainer restart systemd-resolved.service
systemctl은 -M 스위치보다 더 많은 컨테이너를 지원합니다. -r 스위치를 사용하면 호스트에서 실행중인 장치와 모든 로컬 실행 컨테이너의 모든 장치가 표시됩니다:
# systemctl -r
UNIT LOAD ACTIVE SUB DESCRIPTION
boot.automount loaded active waiting EFI System Partition Automount
proc-sys-fs-binfmt_misc.automount loaded active waiting Arbitrary Executable File Formats File Syst
sys-devices-pci0000:00-0000:00:02.0-drm-card0-card0\x2dLVDS\x2d1-intel_backlight.device loaded active plugged /sys/devices/pci0000:00/0000:00:02.0/drm/ca
[...]
timers.target loaded active active Timers
mandb.timer loaded active waiting Daily man-db cache update
systemd-tmpfiles-clean.timer loaded active waiting Daily Cleanup of Temporary Directories
mycontainer:-.mount loaded active mounted /
mycontainer:dev-hugepages.mount loaded active mounted Huge Pages File System
mycontainer:dev-mqueue.mount loaded active mounted POSIX Message Queue File System
[...]
mycontainer:time-sync.target loaded active active System Time Synchronized
mycontainer:timers.target loaded active active Timers
mycontainer:systemd-tmpfiles-clean.timer loaded active waiting Daily Cleanup of Temporary Directories
LOAD = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB = The low-level unit activation state, values depend on unit type.
191 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.
여기에서 먼저 호스트의 유닛들을 볼 수 있고 그 다음에는 현재 실행중인 하나의 컨테이너 유닛들을 볼 수 있습니다. 컨테이너의 유닛은 컨테이너 이름과 콜론(":")으로 시작됩니다. (간결성을 위해 출력이 다시 짧아졌습니다)
systemctl의 list-machines 하위 명령은 실행중인 모든 컨테이너의 목록을 표시하여 컨테이너 내의 시스템 관리자에게 시스템 상태 및 상태에 대해 문의합니다. 보다 구체적으로 컨테이너가 제대로 부팅되었는지 또는 실패한 서비스가 있는지 보여줍니다:
# systemctl list-machines
NAME STATE FAILED JOBS
delta (host) running 0 0
mycontainer running 0 0
miau degraded 1 0
waldi running 0 0
4 machines listed.
더 흥미롭게 만들기 위해 두 개의 컨테이너를 병렬로 더 시작했습니다. 그 중 하나에 서비스가 실패하여 시스템 상태가 저하됩니다.
journalctl(1)의 컨테이너 지원을 살펴 보겠습니다. 특정 컨테이너의 로그를 표시하기 위해 -M 도 지원합니다:
# journalctl -M mycontainer -n 8
Nov 12 16:51:13 wuff systemd[1]: Starting Graphical Interface.
Nov 12 16:51:13 wuff systemd[1]: Reached target Graphical Interface.
Nov 12 16:51:13 wuff systemd[1]: Starting Update UTMP about System Runlevel Changes...
Nov 12 16:51:13 wuff systemd[1]: Started Stop Read-Ahead Data Collection 10s After Completed Startup.
Nov 12 16:51:13 wuff systemd[1]: Started Update UTMP about System Runlevel Changes.
Nov 12 16:51:13 wuff systemd[1]: Startup finished in 399ms.
Nov 12 16:51:13 wuff sshd[35]: Server listening on 0.0.0.0 port 24.
Nov 12 16:51:13 wuff sshd[35]: Server listening on :: port 24.
그러나 호스트 및 모든 로컬 컨테이너의 결합된 로그 스트림을 표시하기 위해 -m 도 지원합니다:
# journalctl -m -e
(여기서 출력을 완전히 건너 뛰도록하겠습니다. 이것이 어떻게 보이는지는 기존것에 의해 추정할 수 있다고 생각합니다)
그러나 요즘 컨테이너 지원을 이해하는 것은 systemd의 자체 도구뿐만 아니라 procps 스포츠 지원도 있습니다:
# ps -eo pid,machine,args
PID MACHINE COMMAND
1 - /usr/lib/systemd/systemd --switched-root --system --deserialize 20
[...]
2915 - emacs contents/projects/containers.md
3403 - [kworker/u16:7]
3415 - [kworker/u16:9]
4501 - /usr/libexec/nm-vpnc-service
4519 - /usr/sbin/vpnc --non-inter --no-detach --pid-file /var/run/NetworkManager/nm-vpnc-bfda8671-f025-4812-a66b-362eb12e7f13.pid -
4749 - /usr/libexec/dconf-service
4980 - /usr/lib/systemd/systemd-resolved
5006 - /usr/lib64/firefox/firefox
5168 - [kworker/u16:0]
5192 - [kworker/u16:4]
5193 - [kworker/u16:5]
5497 - [kworker/u16:1]
5591 - [kworker/u16:8]
5711 - sudo -s
5715 - /bin/bash
5749 - /home/lennart/projects/systemd/systemd-nspawn -D /srv/mycontainer -b
5750 mycontainer /usr/lib/systemd/systemd
5799 mycontainer /usr/lib/systemd/systemd-journald
5862 mycontainer /usr/lib/systemd/systemd-logind
5863 mycontainer /bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation
5868 mycontainer /sbin/agetty --noclear --keep-baud console 115200 38400 9600 vt102
5871 mycontainer /usr/sbin/sshd -D
6527 mycontainer /usr/lib/systemd/systemd-resolved
[...]
프로세스 목록(단축)이 표시됩니다. 두 번째 열은 프로세스가 속한 컨테이너를 보여줍니다. "-"로 표시된 모든 프로세스는 호스트 자체에 속합니다.
하지만 여기서 멈추지 않습니다. systemd/kdbus 컨텍스트에서 준비한 새로운 "sd-bus" D-Bus 클라이언트 라이브러리도 컨테이너를 알고 있습니다. sd_bus_open_system()을 사용하여 로컬 호스트의 시스템 버스에 연결하는 동안 sd_bus_open_system_container()를 사용하여 모든 로컬 컨테이너의 시스템 버스에 연결할 수 있으므로 버스 메서드를 실행할 수 있습니다.
sd-login.h 및 machined의 버스 인터페이스는 다른 프로그램에도 컨테이너 지원을 추가하기위한 여러 API를 제공합니다. 그들은 컨테이너의 열거를 지원할 뿐만 아니라 PID 등에서 머신 이름을 검색합니다.
systemd-networkd는 컨테이너도 지원합니다. 컨테이너 내에서 실행되면 기본적으로 host0이라는 veth 네트워크 인터페이스에서 DHCP 클라이언트와 IPv4LL을 실행합니다 (이 인터페이스는 여기에 설명된 논리에 따라 특별함). networkd 호스트에서 실행되면 기본적으로 ve- 뒤에 컨테이너 이름이 따르게 명명된 veth 네트워크 인터페이스에 DHCP 서버 및 IPv4LL이 제공됩니다.
systemd의 컨테이너 통합의 마지막 측면을 살펴 보겠습니다: 이름 서비스 스위치와의 연결. 최신 시스템 버전에는 gethostbyname() 및 getaddrinfo()를 통해 모든 로컬 컨테이너의 이름을 확인할 수 있는 새로운 NSS 모듈 nss-mymachines가 포함되어 있습니다. 이는 자체 네트워크 네임 스페이스 내에서 실행되는 컨테이너에만 적용됩니다. 그러나 위에 표시된 systemd-nspawn 명령을 사용하면 컨테이너가 호스트와 네트워크 구성을 공유합니다. 따라서 이번에는 호스트와 컨테이너 사이의 가상 veth 네트워크 링크를 사용하여 컨테이너를 다시 시작하겠습니다:
# machinectl poweroff mycontainer
# systemd-nspawn -D /srv/mycontainer --network-veth -b
이제, (networkd가 컨테이너와 외부에서 사용된다고 가정) nss-mymachines의 간단한 마법으로 인해 이름을 사용하여 컨테이너를 이미 ping 할 수 있습니다:
# ping mycontainer
PING mycontainer (10.0.0.2) 56(84) bytes of data.
64 bytes from mycontainer (10.0.0.2): icmp_seq=1 ttl=64 time=0.124 ms
64 bytes from mycontainer (10.0.0.2): icmp_seq=2 ttl=64 time=0.078 ms
물론, 이름 확인은 ping과 함께 작동 할뿐만 아니라 libc gethostbyname() 또는 getaddrinfo()를 사용하는 다른 모든 도구와 함께 작동합니다.
이것이 제가 지금 다루고 싶은 전부입니다. 우리는 다양한 통합 지점을 간략하게 다루었으며 자세히 살펴보면 더 많은 것이 있습니다. 우리는 항상 더 많은 컨테이너 통합을 위해 노력하고 있으므로 시스템 릴리스마다 이 영역에서 더 많은 새로운 기능을 기대합니다.
전체 머신 개념은 실제로 컨테이너에 국한되지 않고 VM도 어느 정도 다룹니다. 그러나 VM의 내부에 대한 액세스는 일반적으로 직접 syscall 액세스를 허용하는 대신 네트워크 전송이 필요하기 때문에 컨테이너에 대한 액세스만큼 쉽지 않기 때문에 통합은 가깝지 않습니다.
어쨌든 이것이 유용하기를 바랍니다. 자세한 내용은 링크 된 매뉴얼 페이지 및 기타 문서를 참조하십시오.