home search
OS
Linux
[Linux] Linux Admin (4): systemd
2022. 02. 26

systemd의 배경

init

init 프로세스란, SysV 유닉스에서 만들어진 PID 1번 Ancestor 프로세스로, 부팅 시의 초기화를 맡고 있다. 그러나 기능이 많이 부족하고, 최근 복수 코어를 가진 프로세스가 생겨남에 따라, init이 병렬처리가 되지 않는 문제는 부트 및 종료 시간의 직렬화를 일으켜 처리가 느린 단점이 되었다.

systemd

systemd는 시스템, 서비스, 자원 설정, 이벤트를 통합 관리하는 거대한 데몬이다. 또한 시스템의 기동과 종료를 통합 제어한다.

systemd에서 시스템을 관리하는 단위를 ‘unit’이라고 부른다. service(서비스를 관리), device(디바이스를 관리), socket, busname, path unit 등으로 나뉘어 있다.

systemd에 3가지 종류의 바이너리(실행파일)가 있다.

  • system configuration: hostnamectl(호스트 이름 제어), localectl, timedatectl 등
  • system monitoring / querying: systemd-analyze, journalctl(로그), loginctl(로그인 감지) 등
  • system controlling: systemctl

systemd unit

systemd --type help 혹은 systemd -t help 명령어로 유닛의 종류를 확인할 수 있다.

# systemd --type help
# systemd --type <unit>

systemd에 사용되는 유닛 파일과 설정 파일(config files)의 위치를 알아보자.

(1) systemd 유닛 대한 설정 파일: 시스템마다 조금씩 다를 수 있다.
# pkg-config systemd --variable-systemdsystemunitdir

(2) systemd설정 디렉토리: 특정 유닛 설정 파일 중 실제 구동항 유닛들을 심볼릭 링크로 가리키고 있음
# pkg-config systemd --variable-systemdsystemconfidir

(3) 유닛 디렉터리를 읽어본다.
# ls $(pkg-config systemd --variable-systemdsystemconfidir) | head

(4) 유닛 디렉터리에 있는 유닛 파일을 읽어본다.
# cat $(pkg-config systemd --variable-systemdsystemconfidir)/NetworkManager.service

(3)에서 파일 타입이 ~~~.유닛타입 으로 나타난다. 사실 (4)는 따로 명령어가 존재한다. systemctl cat NetworkManager[.service] 이다. 뒤에 서비스 유닛 타입의 경우 디폴트 값이라 생략 가능하다.

이번엔 global config 디렉터리를 살펴본다.

# ls /etc/systemd/system/multi-user.target.wants/

해당 서비스가 실행될 때 필요로 하는 서비스들의 모임이다. 심볼릭 링크가 매우 많다. 대부분의 서비스는 심볼릭 링크로 이루어진다.


systemctl

systemctl 기초 명령

systemd를 제어 및 관리하기 위한 매니저 프로그램(명령)으로, CLI 명령에 속한다. 서비스 및 리소스의 상태를 질의하고, 서비스 제어를 수행하며, 서비스 unit의 동작과 설정 변경이 가능하다.

🍎 systemctl [command] [options]

인수 없이 명령을 수행하면 현재 loaded unit 리스트를 확인하는 ‘list-units’ 명령이 기본으로 작동한다.(systemctl list-units) 종료는 q를 입력한다.

🍎 systemctl [-t unittype] [-a] [–state=states] [-l]

자주 사용하는 옵션들이다.

서비스에 대해 보자.

# systemctl -t service
# systemctl -t service --all (또는 -a)

-a 옵션을 주게 되면 더 자세한 내용을 볼 수 있다.

서비스 유닛의 상태를 조건으로 사용할 수도 있다.

# systemctl --state=dead → 실행중인 것들에는 dead가 없으니 당연히 아무것도 안 나온다.
# systemctl --all --state=dead

-l 옵션으로 화면을 넓게 볼 수도 있다. 내용이 길면 잘릴 수 있으므로 오른쪽 화살표(right arrow) 혹은 ESC-)를 누르면 옆 열의 내용을 볼 수 있다. 다시 돌아가려면 왼쪽 화살표.

systemd 관련 유틸은 기본적으로 pager(less)을 사용해 검색 기능도 가능하다. /를 누르고 NetworkManager를 검색해보자. ignore-case를 켤려면 -i (toggle 명령어)를 쓴다

pager를 사용하지 않으려면 아래와 같이 환경 변수를 편집한다. --no-pager 옵션이 없는 경우, systemd 유틸은 SYSTEMD_PAGER 환경변수 설정 페이저를 호출하는 데, 생략 시 less가 사용된다. 공백으로 설정하면 화면 출력으로 끝난다.

$ export SYSTEMD_PAGER=

🍎 systemctl <command> <unitname>[.service]

command를 사용해 유닛의 status, start 등 명령을 내릴 수도 있다. 보통 status는 일반 유저도 볼 수 있지만, 시스템 서비스에 영향을 주는 start, stop, kill 등은 수퍼 유저나 sudo 허가된 유저만 가능하다.

systemd unit 실행 관련 명령어

🍎 systemctl <command> [arg…]

# systemctl status
# systemctl status NetworkManager

ngix를 설치해두고 is-active를 실습해본다.

# systemctl status ngix → loaded disabled, inactive 확인
# systemctl is-active nginx → unkown
# echo $?
3→ exit code가 non-zero로 세팅되어 있음. 실패. inactive

nginx를 시작하고 다시 보자

# systemctl start nginx
# systemctl status nginx
# systemctl is-active nginx
# echo $?
# systemctl is-failed nginx
# echo $?

만약 failed된 유닛이 있다면 reset-failed하기 전에는 재시작할 수 없다. 무한 재시작을 막기 위해서이다. 따라서 rest-failed 명령을 내려 실패된 보고를 모두 reset한다.

# systemctl --state=failed
# systemctl rest-failed
# systemctl --failed

이번에는 kill 명령을 살펴보자.

# systemctl start nginx
# systemctl status nginx
# systemctl kill nginx --signal=SIGABRT  → abot 시그널
# systemctl status nginx → core-dumped

다른 명령들도 쓸 수 있다.

# systemctl is-active nginx
active 

# systemctl reload nginx
# echo $?
0

# systemctl stop nginx 
# systemctl reload nginx
Job for nginx.service invalid. → inactive 상태에서 reload 명령은 실패

# systemctl restart nginx 
# systemctl is-active nginx 
active

systemd unit 부팅 시 자동 실행

이어서 다른 systemctl의 commad 중 enable/disable은 시스템을 부팅했을 때 자동으로 start할 것인지 말 것인지를 지정한다. 이들은 설정만 바꾸는 것이지 실제 실행을 하진 않는다. 그러나 enable하는데 start 까지 같이 하는 경우가 많아 --now 옵션을 붙을 수 있다.

# systemctl enable nginx → 수동으로 심볼릭 링크를 만드는 것은 지양하자. 대신 이렇게 enable로 만들자.

# systemctl is-enabled nginx → enable
# systemctl status ninx	→ enabled 확인. 부팅 시 자동으로 실행됨을 의미
	→ active(running)은 enabel의 영향이 아님. --now를 enabel 할 때 넣어주거나 start를 따로 시켜줘야 함
    
# systemctl reenable nginx → Removed, Created된다. 이는 disable 후 enable하는 것과 동일한 효과
# systemctl preset ningx
# systemctl is-enable nginx
# systemctl enable nignx
# reboot →  status에서 자동으로 nginx가 올라오는지(active) 확인하자

target 설정

systemd target과 SysV runlevel

target unit은 유닛들을 논리적으로 묶은 그룹으로, 시스템 시작 후에 단계별로 수행할 기능을 묶어두는 것이다. 과거의 SysV의 runlevel 기능을 대체하고, 더 체계화되어 만들어졌다.

동적 상태를 기준으로 하기 때문에 이벤트를 처리할 수 있고, 동작 순서를 paralled하게 작동시켜 의존성과 현재 작동 중인 동적 상태에 따라 실행 순서 변경 및 생략이 가능하다.

target의 종류는 아래 명령어로 알 수 있다.

# systemd -t target

target 관련 명령

🍎 systemctl isolate <target>

각 target을 switching 할 수 있는 매우 중요한 명령어이다. 더블 탭을 누르면 쓸 수 있는 타겟이 나온다.

# systemctl isolate graphical.target
→ 콘솔에서 실행 시 바로 X window로 전환됨
# systemctl isolate multi-user.target
→ X window에서 실행 시 console 로 전환되며 바로 꺼짐. 주의!

🍎 systemctl set-default <target>

default 타겟, 즉 부팅할 때 어떤 타켓을 쓸 것인가를 설정할 수 있는 명령어이다.

# systemctl set-default graphical.target
→ X window 로그인 + full networking 로그인 환경을 사용

# systemctl set-default multi-user.target
→ full networking 로그인 환경 + text user interface을 사용. 서버에서 주로 사용

# systemctl get-default
→ 현재 디폴트 타겟 확인. 중요한 명령어

systemd-analyze

🍎 system-analayze [optioins] [command]

systemd의 구동을 분석하는 기능을 가져, 각 서비스의 시간을 분석하고 시각화한다. 아무런 옵션 없이 실행하면 시스템 부팅 시 걸린 시각을 알려준다.

# systemd-analyze
→ kernel / initrd(디스크 드라이버 등이 묶여있는 곳)(이곳을 풀어 작동시킴) /  userspace(그 외 서비스 작동) 에 걸리는 시간 각각 나타냄
# systemd-analyze blame
# systemd-analyze critical-chain

아래서부터 시작해 graphical.target까지 도착하는 데 어떤 경로를 거쳤는지 볼 수 있다. critical path 형태로 출력한다. 뒤쪽에 ‘+##’가 그 단계에서 걸린 시간이다. 특히 오래 걸린 부분이 있다면 그곳의 로그파일을 분석하는 등의 처리를 할 수 있다.

# systemd-analyze plot > svgfile.svg
	→ output 파일을 같이 적어주어야 한다. 

시각화하여 svg로 돌려주어 크롬 웹 브라우저 등에서 열어볼 수 있다. x축이 시간, y축이 서비스 유닛들이다. 색깔별로 의미하는 바가 다르다.

시스템에서 로그를 기록하는 레벨도 설정할 수 있다. 너무 많은 로그가 쌓이면 부담이기 때문이다. 기본으로 systemd에서는 ‘info’로 지정되어 있다. 아래는 현재 레벨을 확인하는 법이다.

(1) grep
# grep -i loglevel /etc/systemd/system.conf
-- 출력 확인

(2) systemctl
# systemctl -p LogLevel show

(3) systemd-analyze: 구버전 작동 안될 수도
# systemd-analyze log-level

🍎 system-analayze set-log-level <로그 레벨>

레벨을 바꾸는 방법은 set-log-level 명령어를 쓴다. 쓸 수 있는 로그 레벨에는 emeg(=emergency)부터, alert, crit, err, warning, notice, info, debug까지 있다. 앞에서부터 뒤로 갈 수록 자세해진다.

# systemd-analyze set-log-level warning
# systemctl -p LogLevel show

systemd-journald (journal log)

systemd에서는 로그 관리를 위해 systemd-journald라는 데몬을 사용한다. 저널 데이터는 런타임 시 쌓이기 때문에 저널 디렉터리는 /run/log/journal에 있다.

journalctl

🍎 journalctl [options]

저널은 데몬에서 관리하나 이를 우리가 보기 위해서는 위 명령을 통한다.

# journalctl

# journalctl -o json
# journalctl -o verbose

# journalctl -e

# journalctl -o short -n
# journalctl -o short -n --no-pager
# journalctl -o short -n 50 --no-pager

# journalctl -f
→ tail -f logfile 방식과 유사
→ -p와 자주 쓰임

# journalctl -u nginx
→ journalctl -u ningx.service와 동일

# journalctl -k
→ 커널 메시지를 보여주는 옵션. dmesg -T 라는 옛 명령어와 동일
# journalctl -k -b 1
→ 이전 부트에서의 커널 메시지

priority(system log level) 설정도 할 수 있었다. 기본은 info로 되어 있지만 에러만 보고 싶다면 loglevel을 warning으로 바꾸면 된다.

30분 이내의 로그만 보고 싶다면

# journalctl -r --since 30m

오늘 발생한 로그 중 에러만 보고 싶다면, p 옵션까지 붙여 쓸 수 있다.

# journalctl -rp err --since today

최근 사건에 대해 자세히 보고를 받고 싶을 때는

# journalctl -xe

다른 옵션까지 결합해 10분 안에 발생한 에러만 자세히 보고 싶다면

# journalctl -xe -p err --since -10m

journal-disk

저널은 기본적으로 메모리 기반 수집이다. 따라서 영구적으로 저널 데이터를 저장하려면 디렉터리를 생성해야 한다. /var/log/journal 을 생성하고 권한을 맞춰줘야 한다.

# mkdir /var/log/journal
# chown root:systemd-journal !$
→ !$는 Alt-. 과 동일 기능
# chmod g+s !$
→ 그룹에 권한 줌
# systemctl restart systemd-journal

저널이 차지하는 용량을 확인하고 삭제하는 것은 위에서 본 명령어를 쓸 수 있다.

# journalctl --disk-usage
# journalctl --vacuum-size=30M
# journalctl --disk-usage

실습

조금 복잡한 상황을 가정해 실습을 해보자. 터미널을 두 개를 열고 둘 다 루트 유저로 로그인해둔다. (로그 레벨은 다시 info로 돌려놓자) 1번 터미널에서는 계속 저널을 팔로잉한다(journalctl -f). 2번 터미널에서는 systemctl restart nginx로 명령을 실행해본다. 그와 동시에 1번 터미널에서 로그를 볼 수 있다.

이번에는 priority를 warning으로 바꿔서 반복해본다. nginx 재시작은 단순 정보(info)이므로 warning에서는 보이지 않는다.

# journalctl -f -p warning

# systemctl restart nginx

그러나 루트 유저를 로그아웃한 뒤(exit) 다시 로그인 했을 때(su -) 패스워드가 틀렸다면 로그인 실패 로그 일부는 warning에 해당하므로 1번 터미널에 로그가 보인다. 로그인 실패 일부는 notice 레벨이나, 앞서 journalctl의 warning으로 filtering을 걸어두었으므로 보이진 않는다.

[사진]

이번엔 systemd-analyze로 로그 레벨을 notice로 변경해본다.

# systemd-analyze set-log-level notice
# journalctl -f

2번 터미널에서 패스워드를 올바르게 입력하면 이번엔 notice 레벨이 되었으므로 그 역시 출력될 것이다. 반면 systemctl restart nginx는 보이지 않는다.

arrow_upward arrow_downward
loading