SSD Nodes Learn 🎉 VPS $5.50/월부터
가이드 Matt Connor작성자 Matt Connor · 업데이트됨 2026-08-13

리눅스 systemd가 SysV init을 대체하고 승리한 이유

SysV init의 의존성 관리 한계와 부팅 속도 문제를 systemd가 어떻게 해결했는지 분석합니다. cgroups와 소켓 활성화를 통한 프로세스 추적 방식, 그리고 리눅스 배포판들이 4년 만에 systemd로 전환하게 된 기술적 배경과 당시 제기된 타당한 반론들을 상세히 설명합니다.

systemd가 승리한 이유

systemd의 역사는 SysV init이 수행할 수 없었던 두 가지 기능에서 시작합니다. 리눅스가 AT&T Unix로부터 물려받은 시작 시스템인 SysV init은 서비스 간의 의존 관계를 정의할 방법이 없었고, 서비스가 실행된 후 어떤 프로세스가 해당 서비스에 속하는지 파악할 방법도 없었습니다. systemd는 셸 스크립트로는 접근할 수 없는 커널 기능을 활용하여 이 두 가지 문제를 해결했습니다. 프로세스 추적을 위한 control groups와 서비스 실행 순서 제어를 위한 미리 열린 리스닝 소켓이 그것입니다. 그 이후의 이야기는 이 두 가지 해결책이 사용자 공간의 나머지 영역으로 어떻게 확산되었는지에 관한 것이며, 바로 이 지점에서 반론이 제기되었습니다. 그리고 그 반론 중 상당수는 타당했습니다.

SysV init의 실제 동작 방식

SysV 시스템에서 PID 1(커널이 시작하는 첫 번째 프로세스인 프로세스 ID 1)은 /etc/inittab을 읽고 런레벨을 선택한 뒤 해당 런레벨의 스크립트를 실행했습니다. 스크립트는 /etc/init.d/에 위치했습니다. /etc/rc3.d/의 심볼릭 링크가 실행할 스크립트와 순서를 결정했으므로, /etc/rc3.d/S20nginx/etc/init.d/nginx를 가리켰고 start라는 인자와 함께 호출되었습니다.

#!/bin/sh
### BEGIN INIT INFO
# Provides:          nginx
# Required-Start:    $local_fs $remote_fs $network $syslog
# Required-Stop:     $local_fs $remote_fs $network $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
### END INIT INFO

case "$1" in
  start)
    start-stop-daemon --start --quiet --pidfile /run/nginx.pid \
      --exec /usr/sbin/nginx
    ;;
  stop)
    start-stop-daemon --stop --quiet --retry TERM/30/KILL/5 \
      --pidfile /run/nginx.pid
    ;;
esac

S20nginx에 있는 20은 의존성이 아닌 위치를 의미합니다. 이는 해당 스크립트가 S19 이후, S21 이전에 실행된다는 뜻입니다. 그 이유는 명시되지 않으므로 아무것도 이를 검증할 수 없으며, 사람이 안전하다고 판단하지 않는 한 서로 관련 없는 두 스크립트를 동시에 안전하게 실행할 방법이 없습니다.

rc 프로그램은 각 스크립트를 순차적으로 실행하고 종료를 기다렸습니다. 네트워크 주소를 기다리며 30초 동안 차단된 스크립트는 네트워크를 사용하지 않는 서비스까지 포함하여 전체 부팅 과정을 30초 동안 멈추게 했습니다.

스크립트 상단에 있는 LSB(Linux Standard Base) 헤더는 내부적으로 이 문제를 해결하려는 시도였습니다. 2011년 Debian 6.0은 insserv을 기본값으로 채택했습니다. 이는 모든 스크립트에서 Required-Start를 읽어 그래프를 구성하고 심볼릭 링크의 번호를 다시 매기는 방식이었습니다. 이를 통해 Debian은 startpar을 사용하여 독립적인 스크립트를 동시에 실행할 수 있게 되었습니다. 이는 도움이 되었으나 근본적인 문제는 해결하지 못했습니다. 의존성은 여전히 스크립트의 종료 여부에 달려 있었습니다. S20nginx가 0을 반환한다는 것은 셸 함수가 성공적으로 종료되었다는 의미일 뿐, nginx가 연결을 수락하고 있다는 뜻은 아닙니다.

init 스크립트로 해결할 수 없는 5가지 문제

  • 병렬 시작. 파일 이름순으로 정렬하는 방식은 시스템의 모든 서비스에 대해 순차적인 실행을 강제하므로, 부팅 속도가 각 서비스 실행 시간의 합만큼 느려집니다.
  • 준비 상태 확인. 시작 스크립트는 데몬을 포크(fork)한 시점에 종료될 뿐, 데몬이 실제 요청을 처리할 수 있는 상태가 되었는지는 알지 못합니다. 따라서 다음 스크립트가 너무 일찍 시작되는 경우가 잦습니다.
  • 감독(Supervision). 데몬이 두 번 포크하고 부모 프로세스가 종료되면, 데몬은 터미널에서 분리되어 PID 1의 자식 프로세스가 됩니다. init은 자식 프로세스의 종료만 감지할 뿐, 살아남은 실제 프로세스와의 신뢰할 수 있는 연결 고리를 갖지 못합니다.
  • 온디맨드 시작. inetd(인터넷 슈퍼 서버)는 연결이 들어올 때 데몬을 실행할 수 있었지만, 이는 별도의 설정 파일을 가진 독립적인 시스템이었으며 부팅 시 다른 서비스들의 실행 순서와는 무관하게 동작했습니다.
  • 자원 제어. init 스크립트에는 서비스의 메모리 사용량이나 CPU 점유율을 제한할 방법이 없었습니다. ulimit는 단일 프로세스에만 적용되었고 nice은 스케줄러에만 영향을 주었기에, 서비스에서 파생된 폭주 프로세스는 시스템의 다른 일반 프로세스와 구분되지 않았습니다.

감독 기능의 부재는 일상적인 운영에서 가장 큰 어려움이었습니다. PID 파일이 이에 대한 우회책이었는데, 데몬이 자신의 프로세스 ID를 /run/nginx.pid에 기록하고 종료 함수가 이 파일을 다시 읽어 들이는 방식이었습니다. 데몬이 강제로 종료되면 파일은 그대로 남게 됩니다. 커널이 해당 번호를 다른 프로세스에 재할당하면, start-stop-daemon --stop --pidfile은 엉뚱한 프로세스에 시그널을 보내게 됩니다. 오래된 PID 파일로 인해 init 스크립트가 잘못된 프로세스를 종료하는 사고가 발생하는 이유가 바로 이것입니다.

launchd가 소켓 문제를 먼저 해결했습니다

Apple은 2005년 Mac OS X 10.4에서 Dave Zarzycki가 작성한 launchd를 출시했습니다. 하나의 프로세스가 init, rc, xinetd, crond, watchdogd를 모두 대체했습니다.

복제할 가치가 있는 아이디어는 소켓 활성화(socket activation)였습니다. launchd는 모든 리스닝 소켓을 먼저 생성한 뒤 데몬을 시작합니다. 아직 시작되지 않은 데몬에 클라이언트가 연결을 시도해도 연결 거부(connection refused)가 발생하지 않습니다. 데몬이 accept()를 호출할 때까지 커널이 해당 소켓의 백로그 큐에 연결을 보관하기 때문입니다. 두 데몬 사이의 실행 순서를 사람이 명시할 필요가 없어졌습니다. 소켓이 이를 처리하기 때문입니다.

launchd는 Apple의 XNU 커널에 속하며 Linux에는 대응하는 기능이 없는 Mach IPC(프로세스 간 통신)를 기반으로 구축되었습니다. 따라서 코드를 이식하는 것은 현실적으로 불가능했습니다. 하지만 그 아이디어는 결국 다른 곳으로 전파되었습니다.

Upstart는 이벤트를 작업 단위로 설정했습니다

Canonical의 Upstart는 Scott James Remnant가 작성했으며 2006년 10월 Ubuntu 6.10에서 처음 출시되었습니다. Fedora 9부터 Fedora 14까지, 그리고 RHEL 6와 Chrome OS에서도 이 시스템을 사용했습니다. Upstart는 런레벨을 이벤트로 대체했으며, 각 작업(job)은 어떤 이벤트가 해당 작업을 시작하고 종료해야 하는지를 정의했습니다.

# /etc/init/example.conf
start on filesystem and net-device-up IFACE!=lo
stop on runlevel [!2345]
respawn
respawn limit 10 5
exec /usr/local/bin/exampled

작업 수가 증가함에 따라 두 가지 문제가 나타났습니다. 첫 번째는 방향성입니다. 작업은 "이런 일이 발생하면 나를 시작하라"고 명시합니다. 즉, 무엇이 무엇에 의존하는지에 대한 정보가 잘못된 파일에 위치하게 됩니다. 서비스는 자신이 무엇을 필요로 하는지는 알지만, 미래에 누가 자신을 필요로 할지는 알 수 없습니다. 서비스를 추가하려면 기존 작업을 수정하여 새로운 이벤트를 발생시키도록 해야 하는 경우가 많았습니다.

두 번째는 추적 문제입니다. Upstart는 fork() 호출을 ptrace로 계수하여 포킹 데몬을 추적했는데, 이를 expect fork 또는 expect daemon으로 설정해야 했습니다. 포크 횟수를 잘못 추측하면 Upstart는 이미 종료된 프로세스를 감독하거나 이미 발생한 포크를 기다리게 됩니다. 이로 인해 initctl start가 오류 메시지 없이 멈추는 현상이 발생하며, 작업 파일에서는 이를 설명할 방법이 없습니다.

또한 Upstart는 기여자들에게 Canonical의 기여자 계약에 서명할 것을 요구했습니다. 이는 공학적인 결함은 아니었으나, 누가 개발에 참여할지를 결정짓는 요인이 되었습니다.

PID 1에 대한 재고, 2010년 4월

2010년 4월 30일 Lennart Poettering은 "Rethinking PID 1"이라는 게시물을 발표했습니다. Kay Sievers가 그와 함께 이 프로젝트를 진행했습니다. 이 주장은 네 가지 부분으로 구성되었습니다.

  • 더 적게 시작하십시오. 많은 서비스는 실제로 요청이 들어올 때까지 기다릴 수 있습니다.
  • 소켓이 순서를 암시할 수 있는 경우 순서를 선언하지 마십시오. 모든 소켓을 한 번에 열고 모든 서비스를 동시에 시작하십시오.
  • PID 파일 대신 control groups를 사용하여 프로세스를 추적하십시오.
  • 선언적 파일로 서비스를 기술하여, 하나의 설명이 모든 배포판에서 작동하도록 하십시오.

그해 첫 번째 릴리스가 뒤따랐습니다. Fedora 14는 2010년 11월에 systemd를 선택 사항으로 제공했으며, Fedora 15는 2011년 5월에 이를 기본값으로 채택했습니다.

cgroup이 서비스 관리를 안정적으로 만든 이유

cgroup(control group)은 프로세스를 그룹화하기 위한 커널 기능으로, 2008년 Linux 2.6.24에 병합되었습니다. systemd는 모든 서비스를 각자의 cgroup에 배치합니다. 자식 프로세스는 부모의 cgroup을 상속하며, 권한이 없는 프로세스는 스스로 cgroup을 벗어날 수 없습니다. 따라서 더블 포킹(double forking)을 사용해도 프로세스를 숨길 수 없습니다. PID 1은 항상 특정 유닛에 속한 프로세스 집합을 정확하게 파악합니다. 서비스를 중지한다는 것은 해당 cgroup 내의 모든 프로세스를 종료한다는 의미이며, 이는 기본값인 KillMode=control-group가 수행하는 작업입니다.

systemctl status은 해당 그룹을 출력합니다:

● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled)
     Active: active (running) since Tue 2026-08-11 09:14:22 UTC; 3min ago
   Main PID: 1042 (nginx)
      Tasks: 3 (limit: 4653)
     Memory: 6.1M (peak: 7.4M)
     CGroup: /system.slice/nginx.service
             ├─1042 "nginx: master process /usr/sbin/nginx"
             ├─1043 "nginx: worker process"
             └─1044 "nginx: worker process"

이 블록이 부실해진(stale) PID 파일 문제에 대한 완전한 해결책입니다. 커널 상태를 직접 참조하므로 부실해질 파일 자체가 존재하지 않습니다.

cgroup은 원래 추적 용도가 아닌 자원 계산을 위해 설계되었으므로, 동일한 트리 구조를 통해 제한을 설정할 수 있습니다. MemoryMax=, CPUQuota=, TasksMax=는 각각 한 줄로 설정 가능합니다. 서비스에 메모리 및 CPU 하드 제한 설정하기는 오늘날 드롭인(drop-in) 파일 하나로 가능하지만, 2009년에는 아무도 작성하지 않았던 셸 스크립트 패치가 필요했습니다.

모든 배포판이 2011년에서 2015년 사이에 전환한 이유

  • Fedora 15, 2011년 5월.
  • openSUSE 12.1, 2011년 11월.
  • Mageia 2, 2012년 5월.
  • Arch Linux, 2012년 10월부터 신규 설치 시 기본값.
  • RHEL 7, 2014년 6월.
  • SLES 12, 2014년 10월.
  • Debian 8, 2015년 4월.
  • Ubuntu 15.04, 2015년 4월.

전환이 신속했던 이유는 대부분 지극히 실무적인 문제였기 때문입니다.

  • 하나의 unit 파일로 모든 배포판에서 동작하므로, 업스트림 프로젝트들이 .service 파일을 직접 제공하기 시작했고 배포판들은 패키지별, 릴리스별로 셸 스크립트를 유지보수할 필요가 없어졌습니다.
  • 2012년경 ConsoleKit의 유지보수가 중단되면서 데스크톱 세션 추적 기능이 systemd-logind로 이전되었습니다. GNOME은 logind를 필요로 했기에, systemd를 사용하지 않는 배포판은 대체재를 찾아야 했습니다. 그 대체재인 elogind는 systemd의 logind를 별도로 추출하여 유지보수하는 프로젝트입니다.
  • 장치 관리자인 udev는 2012년 4월 systemd 소스 트리로 병합되었습니다. udev를 제공하는 배포판들은 이제 systemd 저장소를 추적하게 되었습니다. Gentoo는 이에 대응하여 eudev을 포크했습니다.
  • 컨테이너 기술이 도입되면서 안정적인 프로세스 추적과 서비스별 제한 기능이 중요해졌으며, 이 두 가지 모두 cgroup의 기능입니다. 컨테이너 프로세스를 어떤 슈퍼바이저가 관리할 것인가 하는 문제는 재부팅 후 Docker Compose 스택을 복구하는 방법을 다룰 때 여전히 중요한 주제입니다.

Debian의 결정은 가장 큰 논란을 불러왔습니다. 2014년 2월 기술 위원회 투표 결과가 동률로 나오자, 위원장인 Bdale Garbee가 systemd를 선택하는 결정적인 투표를 했습니다. Ubuntu는 며칠 뒤 Upstart를 계속 사용하는 대신 Debian을 따르겠다고 발표했습니다. Debian 개발자 그룹은 2014년 11월 Devuan이라는 이름으로 배포판을 포크했고, 2017년 5월 Devuan 1.0을 출시했습니다.

공정하게 서술된 반대 의견

범위. 현재 한 프로젝트가 PID 1, 로깅 데몬, 로그인 세션 관리, 장치 관리자, 네트워크 설정 데몬, DNS(도메인 네임 시스템) 리졸버, NTP(네트워크 시간 프로토콜) 클라이언트, 컨테이너 런타임, 부트로더를 모두 포함하여 배포합니다. 이들은 별도의 바이너리이므로 설치하지 않아도 된다는 일반적인 방어 논리는 사실이지만, 반대 의견에 대한 답변은 되지 못합니다. 데스크톱 환경이 logind를 필요로 하게 되고 logind가 systemd 트리에서 분리되지 않는 이상, 선택의 자유는 더 이상 존재하지 않습니다. 이것이 논쟁에서 말하는 결합(coupling)의 의미이며, 실제로 발생한 일입니다.

바이너리 저널. journald는 일반 텍스트 대신 인덱싱된 바이너리 형식으로 로그를 기록합니다. 이를 통해 텍스트 파일에서는 불가능했던 단위별·우선순위별 필터링, 구조화된 필드, 그리고 전송 프로그램이 위조할 수 없는 메타데이터(journald가 직접 단위와 cgroup을 기록하기 때문)를 얻을 수 있습니다. journalctl -u nginx -p err --since "-1h"는 날짜 정규 표현식을 사용하는 grep을 대체합니다. 물론 대가도 따릅니다. 부팅되지 않는 시스템에서는 구조화된 로그를 less로 읽을 수 없습니다. 대신 마운트된 디스크를 journalctl로 지정해야 합니다:

sudo journalctl --directory /mnt/var/log/journal --boot -1 --priority err

여기에는 사용자가 한 번쯤 겪게 되는 두 번째 함정이 있습니다. /var/log/journal이 존재하지 않으면 journald는 로그를 /run/log/journal(메모리)에만 보관합니다. 해당 디렉터리가 없는 시스템에서는 재부팅 후 journalctl -b -1을 실행해도 아무것도 표시되지 않으며, 이는 로그가 가장 필요한 순간에 발생합니다. 다음 명령으로 확인하고 수정하십시오:

journalctl --disk-usage
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald

이제 journalctl --disk-usage를 실행하면 /var/log/journal 아래에 보관된 저널이 표시되어야 합니다. 일반 텍스트 로그도 함께 유지하려면 /etc/systemd/journald.conf에서 ForwardToSyslog=yes을 설정하고 rsyslog를 계속 설치해 두십시오.

부팅 디버깅. 단위(unit)가 멈추면 콘솔에는 다음과 같은 한 줄만 표시됩니다:

[  *** ] A start job is running for Wait for Network to be Configured (1min 32s / no limit)

더 자세한 정보를 얻기 위한 도구는 존재합니다. 멈춰 있는 동안에는 systemctl list-jobs을 사용하고, 이후에는 systemd-analyze blamesystemd-analyze critical-chain를 사용하며, 커널 명령줄에는 systemd.log_level=debug을 추가합니다. 이 불만에 대한 공정한 평가는 다음과 같습니다. 과거의 init 스크립트는 sh을 아는 사람이라면 누구나 위에서 아래로 읽을 수 있었지만, 멈춘 단위는 수십 개의 명령어 중 무엇을 사용해야 할지 알아야 한다는 점입니다. 이는 분명한 비용입니다. 관리자마다 한 번씩 치러야 하는 비용이며, 수많은 관리자가 동시에 겪었던 문제이기도 합니다.

모두에게 적용되는 기본값 변경. 2016년 systemd 230 버전은 logind의 기본값을 변경하여 로그아웃 시 남은 사용자 프로세스를 종료하도록 했습니다. 분리된 tmuxscreen 세션은 이를 시작한 세션이 종료될 때 함께 종료되었습니다. 각 배포판은 /etc/systemd/logind.confKillUserProcesses=no을 배포했으며, 권장되는 해결책은 loginctl enable-linger <user>입니다. 한 프로젝트의 기본값 하나가 수백만 명이 의존하던 습관을 바꾸어 놓았으며, 이것이 실무에서 말하는 "사용자 공간(userland)이 한곳에 너무 많이 모여 있다"는 의미입니다.

기본 의존성은 보안 표면입니다. 2024년 3월, xz-utils의 백도어는 Debian과 Ubuntu의 sshd를 표적으로 삼았습니다. 업스트림 OpenSSH는 libsystemd와 링크되지 않습니다. 해당 배포판들은 sshd가 systemd에 준비 상태를 보고할 수 있도록 패치를 적용했고, libsystemd는 백도어가 포함된 liblzma를 불러왔습니다. 준비 상태 프로토콜 자체는 $NOTIFY_SOCKET에 명시된 소켓으로 전송되는 단일 데이터그램일 뿐이므로, 이를 위해 라이브러리가 필요하지는 않았습니다. 이에 대한 systemd의 대응은 dlopen를 사용하여 압축 라이브러리를 동적으로 로드하도록 변경하는 것이었으며, 따라서 더 이상 기본적으로 링크되지 않습니다. 이와 유사한 유형의 버그가 또 있습니다. 2017년에는 숫자로 시작하는 User= 값을 잘못된 값으로 처리하여 단위가 실패하는 대신 root 권한으로 실행되는 문제가 있었고, 오타가 권한 상승으로 이어졌습니다. 이후 버전에서는 해당 단위의 시작을 거부합니다.

시스템의 systemctl 프롬프트에서 확인하는 기록

위에서 언급한 모든 문제는 이제 읽을 수 있는 파일 내의 지시어 하나로 정리됩니다.

  • 순차적 부팅은 After=Wants=이 되었으며, systemd-analyze critical-chain은 부팅을 실제로 지연시킨 원인을 보여줍니다.
  • 준비 상태는 Type=notify가 되었으며, 서비스가 요청을 처리할 수 있을 때 READY=1$NOTIFY_SOCKET에 기록합니다. 구형 데몬을 위한 Type=forkingPIDFile=은 여전히 존재하며, PID 파일이 생성되지 않을 때 start operation timed out. Terminating. 오류를 발생시키는 유형입니다.
  • 프로세스 관리는 cgroup이 담당하므로 Restart=on-failureRestartSec=이 래퍼 스크립트를 대체하며, StartLimitBurst=은 충돌 루프가 무한히 실행되는 것을 방지합니다.
  • inetd는 .service 유닛 옆에 위치하는 .socket 유닛이 되었습니다.
  • ulimitMemoryMax=, CPUQuota=, TasksMax=이 되었습니다.
  • init 스크립트의 su - appuser -c 라인은 User=, NoNewPrivileges=yes, ProtectSystem=strict이 되었으므로, 권한 없는 사용자로 서비스 실행하기는 추가 작업이 아닌 유닛의 기본 형태가 되었습니다.
[Unit]
Description=Example API
Wants=network-online.target
After=network-online.target postgresql.service
Requires=postgresql.service

[Service]
Type=notify
ExecStart=/usr/local/bin/exampled
Restart=on-failure
RestartSec=2
MemoryMax=512M
CPUQuota=50%
TasksMax=128
User=exampled
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
StateDirectory=exampled

[Install]
WantedBy=multi-user.target

해당 파일의 한 줄은 누구나 한 번쯤 저지르는 실수입니다. Requires=postgresql.service은 순서가 아닌 필수 요건입니다. 이는 Postgres가 실패하면 유닛도 실패한다는 의미이며, Postgres를 먼저 시작하라는 의미는 아닙니다. After=postgresql.service가 없으면 두 서비스가 동시에 시작되므로, 아무것도 수신 대기하지 않는 포트에 서비스가 연결을 시도하게 됩니다. 이 둘을 분리해 둔 이유는 때때로 하나만 필요할 때가 있기 때문입니다. ProtectSystem=strict은 이 서비스를 위해 파일 시스템을 읽기 전용으로 마운트하며, 이것이 StateDirectory=이 존재하는 이유입니다. 이는 서비스에 /var/lib 아래의 쓰기 가능한 경로 하나를 제공합니다.

2026년 서버에서 2005년의 방식을 확인하기 가장 좋은 예는 Ubuntu 24.04의 SSH이며, 2026년 8월 기준으로 systemd 255를 탑재하고 있습니다. ssh.service은 기본적으로 소켓 활성화 방식입니다. ssh.socket가 수신 소켓을 유지하며, 연결이 들어올 때 sshd가 시작됩니다. 따라서 /etc/ssh/sshd_configPort 2222는 아무런 효과가 없습니다. 포트를 연 프로세스가 sshd가 아니기 때문입니다. 변경 사항은 소켓 유닛에 적용해야 합니다.

sudo systemctl edit ssh.socket
[Socket]
ListenStream=
ListenStream=2222

비어 있는 ListenStream=은 패키지 유닛에서 상속된 값을 지웁니다. 이를 생략하면 systemd가 값을 대체하지 않고 리스트에 추가하기 때문에 두 포트 모두 사용하게 됩니다. 그런 다음 적용하고 확인하십시오. 이때 두 번째 SSH 세션을 계속 열어두어야 합니다.

sudo systemctl daemon-reload
sudo systemctl restart ssh.socket
sudo ss -lntp | grep 2222

sssshd이 아닌 systemd가 소유한 2222 포트의 소켓 하나를 표시해야 합니다. 이것이 20년이 지난 지금 여러분의 VPS에서 구현된 launchd 설계입니다. 이전 방식을 선호한다면 sudo systemctl disable --now ssh.socket 이후 sudo systemctl enable --now ssh.service를 실행하여 자체 설정에서 Port을 다시 읽어오는 상시 실행 sshd를 구성할 수 있습니다.

이러한 세부 사항 중 무엇을 마주하게 될지는 실행 중인 릴리스에 따라 다르므로, 업그레이드를 계획하기 전에 LTS 릴리스와 중간 Ubuntu 릴리스의 차이점을 알아두는 것이 좋습니다. 여러 대의 머신을 관리할 때 유닛 파일이 어디서나 동일하다는 사실은 한 곳에서 여러 서버 관리하기가 이제 셸 스크립팅 문제가 아닌 설정 문제로 다루어지는 이유입니다. 직접 유닛을 작성할 때는 서비스와 타이머 쌍이 2009년에 init 스크립트와 cron 라인으로 나누어 처리하던 작업을 대신 수행합니다.

FAQ

리눅스 배포판들은 왜 SysV init을 systemd로 교체했습니까?

두 가지 공학적 이유와 한 가지 유지보수적 이유 때문입니다. SysV init은 서비스 순서를 파일 이름에 따른 위치로 결정했는데, 이는 의존성 관계가 아니었습니다. 또한 부모 프로세스에서 분기된 데몬을 추적하지 못해, 잘못된 PID 파일을 참조하여 엉뚱한 프로세스를 종료하는 문제가 발생했습니다. systemd는 소켓 활성화와 의존성 지시어로 순서 문제를 해결했고, 컨트롤 그룹(cgroup)을 통해 프로세스 추적 문제를 해결했습니다. 유지보수적 이유는 속도와 관련이 있습니다. 하나의 유닛 파일이 모든 배포판에서 작동하므로, 업스트림 프로젝트는 .service 파일을 배포하고 배포판 관리자들은 패키지마다 셸 스크립트를 작성하는 일을 중단했습니다. Fedora 15가 2011년 5월에 전환했고, Ubuntu 15.04가 2015년 4월에 마지막으로 대규모 전환을 마쳤습니다.

systemd는 하나의 거대한 바이너리입니까?

아닙니다. 소스 트리에서 여러 개의 개별 프로그램을 빌드합니다. PID 1은 /usr/lib/systemd/systemd이며, journald, logind, udevd는 각각 고유한 바이너리를 가진 별도의 프로세스입니다. 직접 확인하려면 ls /usr/lib/systemd/을 실행하십시오. 여전히 존재하는 비판은 바이너리 크기가 아니라 릴리스 결합도에 관한 것입니다. 이 프로그램들은 함께 릴리스되고 내부 인터페이스를 공유하므로, 배포판들은 이를 하나의 세트로 취급하는 경향이 있으며 GNOME과 같은 소프트웨어는 logind를 명시적으로 요구하게 되었습니다.

systemd 없이 리눅스를 실행할 수 있습니까?

가능합니다. Devuan은 sysvinit을 제공하고, Gentoo는 기본값으로 OpenRC를 사용하며, Void는 runit을, Alpine은 OpenRC와 함께 busybox init을 사용하고, Slackware는 BSD 스타일 스크립트를 유지합니다. 그 대가는 호환성 작업입니다. logind를 요구하는 데스크톱 소프트웨어는 독립형 패키지로 유지 관리되는 systemd의 logind인 elogind이 필요합니다. 또한 점점 더 많은 서버 소프트웨어가 .service 파일만 제공하므로, 시작 스크립트를 직접 작성하고 유지 관리해야 합니다.

저널(journal)은 왜 일반 텍스트 파일이 아니라 바이너리입니까?

journald는 인덱스가 포함된 구조화된 필드를 저장하기 때문입니다. 이를 통해 유닛별 필터링, 우선순위 필터링, 그리고 전송 프로그램이 위조할 수 없는 메타데이터를 제공합니다. journald는 로그 라인을 신뢰하는 대신 유닛, cgroup, 실제 UID를 직접 기록합니다. 그 대가로 이를 읽으려면 journalctl가 필요하며, 복구 시스템에서 사용할 때는 journalctl --directory /mnt/var/log/journal을 사용하여 마운트된 디스크를 지정해야 합니다. 텍스트 파일도 필요하다면 /etc/systemd/journald.conf에서 ForwardToSyslog=yes을 설정하십시오.

/etc/init.d 스크립트를 수정하는 방식은 무엇으로 대체되었습니까?

드롭인(drop-in) 파일입니다. /usr/lib/systemd/system/에 있는 유닛을 직접 수정하지 마십시오. 패키지 업그레이드 시 덮어쓰이기 때문입니다. sudo systemctl edit nginx.service를 실행하면 systemd가 /etc/systemd/system/nginx.service.d/override.conf를 생성하며, 이는 패키지된 유닛 위에 병합됩니다. systemctl cat nginx.service은 병합된 결과를 보여주며, systemd-delta은 시스템의 모든 오버라이드 목록을 표시합니다. 수동으로 편집한 후에는 반드시 sudo systemctl daemon-reload을 실행하십시오. 그렇지 않으면 다음 명령 실행 시 Warning: The unit file, source configuration file or drop-ins of nginx.service changed on disk.라는 경고가 출력됩니다.

#systemd#linux#init#sysvinit#history