systemd logo
2024년 4월 12일

systemd 를 사용하여 서비스 관리하기

linuxsystemd

systemd 는 리눅스 운영체제의 시스템 및 서비스 관리자입니다. 시스템 부팅시에 첫번째 프로세스 (PID 1) 로 실행하며, 고전적으로 사용하는 init 를 대체합니다. RHEL, CentOS, Ubuntu 등 다양한 Linux 배포판에서 채용하고 있습니다.

SSH 서버, 웹 서버 등과 같이 클라이언트와 직접 통신하기 위해 소켓을 사용하는 데몬을 작성하거나 백그라운 작업을 실행해야 하는 경우가 종종 발생합니다. 두번의 fork를 사용하여 데몬을 직접 만들수도 있지만 systemd를 사용하면 매우 쉽게 서비스를 만들 수 있습니다.

예제 프로그램

Python 으로 간단한 소켓 프로그램을 만들어 보겠습니다. echo-server.py 는 TCP 10000 번 포트로 메시지를 수신하고, 수신한 메시지를 그대로 반환합니다.

echo-server.py
#!/usr/bin/env python3
import socket

HOST = "0.0.0.0"
PORT = 10000

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
  s.bind((HOST, PORT))
  s.listen()
  while True:
    conn, addr = s.accept()
    with conn:
        print("connected: %s:%s" % (HOST, PORT))
        while True:
          data = conn.recv(1024)
          if not data:
            break
          print("received: %s" % data)
          conn.sendall(data)

스크립트를 바로 실행할 수 있도록 mode 를 변경하고, 서버를 시작하겠습니다.

$ chmod +x echo-server.py
$ ./echo-server.py

그리고 다른 터미널에서 telnet 을 사용하여 서버에 접속하여 잘 동작하는지 테스트 해 보겠습니다.

$ telnet localhost 10000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
HELLO WORLD
HELLO WORLD
^]
telnet> quit
Connection closed.

이제 우리는 이 스크립트가 항상 실행되기를 바랍니다. 오류가 발생(예치기 않은 종료)해도 다시 실행하고, 서버가 재시작하여도 실행하기를 바랍니다. 이것이 systemd 가 작동하는 방식입니다.

Unit 설정 파일

systemd 는 작업의 단위는 Unit 으로 관리합니다. 다음과 같이 서비스 Unit 파일을 만들어 보겠습니다. 실행 파일의 경로(/path/to)는 적절하게 변경합니다.

/etc/systemd/system/echo-server.service
[Unit]
Description=Echo Service
After=network.target

[Service]
Type=simple
ExecStart=/path/to/echo-server.py

[Install]
WantedBy=multi-user.target

Unit 파일은 ini 형식을 사용하며, Unit, Service, Install 의 세가지 섹션을 가집니다.

서비스 실행하기

서비스의 관리는 systemd 의 관리 명령인 systemctl 을 사용합니다.

'start' 명령을 사용하여 서비스를 시작합니다.

$ sudo systemctl start echo-server

'status' 명령을 사용하여 서비스의 상태를 확인합니다. 서버의 상태, PID, 메모리 사용량, CPU 사용량, 로그 등을 확인할 수 있습니다.

$ sudo systemctl status echo-server
? echo-server.service - Echo Service
     Loaded: loaded (/etc/systemd/system/echo-server.service; disabled; vendor preset: enabled)
     Active: active (running) since Fri 2024-04-12 02:40:09 KST; 1min 24s ago
   Main PID: 3297307 (python3)
      Tasks: 1 (limit: 38017)
     Memory: 3.6M
        CPU: 17ms
     CGroup: /system.slice/echo-server.service
             ??3297307 python3 /path/to/echo-server/echo-server.py

Apr 12 02:40:09 10b-server systemd[1]: Started Echo Service.

다시 서비스에 접속하여, 잘 동작하는지 테스트 하겠습니다.

$ telnet localhost 10000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello World!!!
Hello World!!!
^]
telnet> quit
Connection closed.

'stop' 명령을 사용하여 서비스를 종료합니다. 그리고 'status' 명령으로 상태를 확인합니다.

$ sudo systemctl stop echo-server
$ sudo systemctl status echo-server
? echo-server.service - Echo Service
     Loaded: loaded (/etc/systemd/system/echo-server.service; disabled; vendor preset: enabled)
     Active: inactive (dead)

Apr 12 02:40:09 10b-server systemd[1]: Started Echo Service.
Apr 12 02:49:43 10b-server systemd[1]: Stopping Echo Service...
Apr 12 02:49:43 10b-server systemd[1]: echo-server.service: Deactivated successfully.
Apr 12 02:49:43 10b-server systemd[1]: Stopped Echo Service.

이제 부팅시 자동으로 시작되도록 하겠습니다. 'enable' 명령을 사용하며, 자동시작이 되지 않게 하려면 'disable' 명령을 사용합니다.

$ sudo systemctl enable echo-server

좀 더 살펴보기

이제 서비스가 좀 더 세밀하게 동작하도록 몇 가지 구성 옵션에 대해 살펴보도록 하겠습니다.

특정 사용자, 그룹으로 시작하기

사용자와 그룹을 지정하지 않는다면, root 권한으로 서비스를 시작합니다. User=, Group= 지시어를 사용하여 실행 권한을 조정할 수 있습니다.

User=apache
Group=apache

올바른 순서로 시작하기

만약 mysqld.service 를 사용하는 서비스가 있다면, 이후에 실행해야 정상적으로 동작할 수 있습니다. 이런 경우 After= 지시어를 사용하여 실행하는 순서를 지정합니다.

After=mysqld.service

종료시 다시 시작하기

systemd 는 어떤 이유로든 프로그램이 종료되면, 서비스를 다시 시작하지 않습니다. Restart= 지시어를 사용하면, 항상 시작하도록 할 수 있습니다.

Restart=always

systemd 는 기본적으로 100ms 이후 다시 시작을 시도합니다. RestartSec= 지시어를 사용하여 대기 시간을 조정할 수 있습니다.

RestratSec=1

시작 제한하기

systemd 는 10초 내에 5회 이상 서비스 시작에 실패하면, 재시작을 포기합니다. StartLimitBurst=, StartLimitIntervalSec= 지시어를 변경하여 조정할 수 있습니다.

StartLimitBurst=5
StartLimitIntervalSec=10

참고

© 2023-2024 인포그라. All Rights Reserved.