반응형
systemd란 무엇이고 언제 쓰일까?🐧
리눅스 시스템에서 systemd란 백그라운드에서 실행되는 프로그램인을 제어하는 도구이다.
일반적으로 프로그램을 터미널에서 직접 실행하면, 터미널이 종료될 때 프로그램도 같이 종료된다. 하지만 개발자가 프로그램 배포 시 원하는 형태는 다음과 같은 것이다.
- 사용자가 컴퓨터에 로그인하지 않아도 프로그램이 항상 동작해야 함.
- 프로그램이 실패나 오류로 종료되더라도 자동으로 다시 시작해야 함.
- 애플리케이션 실행 중에 발생한 에러와 상태 로그를 쉽게 추적할 수 있어야 함.
이런 요구사항을 해결해주는 것이 바로 systemd이다. 즉, 내가 개발한 애플리케이션이 백그라운드에서 안정적으로 실행되고 관리될 수 있도록 한다.
✓ 용어 정리
- 데몬 (Daemon) :
백그라운드에서 실행되는 프로그램 - 서비스 (Service) :
데몬을 관리하기 위한 단위. init 시스템에서 데몬 시작/중지/상태 확인 등 관리 작업을 하기 위해 사용하는 구성 단위로,systemd에서 서비스는 *.service 유닛 파일로 정의됨 - systemd :
현대적인 init 시스템이자 서비스 관리자. 시스템 부팅 시 프로세스를 초기화하고, 서비스(Unit)를 관리하는 역할을 함. *.service 파일로 정의된 서비스를 제어하며, 우분투 15.04 이후 기본 init 시스템으로 채택됨
1. 테스트 용 앱 준비
예제로 매 초마다 현재 시각(타임스탬프)을 파일에 기록하는 간단한 프로그램을 작성하였다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#define BASE_PATH "/var/lib/daemon_test/"
#define TMP_FILE "/var/lib/daemon_test/timestamp.tmp"
#define FINAL_FILE "/var/lib/daemon_test/timestamp"
void ensure_directory() {
struct stat st = {0};
if(stat(BASE_PATH, &st) == -1) {
mkdir(BASE_PATH, 0755);
}
}
void write_timestamp() {
time_t now = time(NULL);
struct tm *tm_info = localtime(&now);
char buffer[64];
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S\n", tm_info);
FILE *fp = fopen(TMP_FILE, "w");
if(!fp) {
perror("fopen tmp");
return;
}
fwrite(buffer, 1, strlen(buffer), fp);
fclose(fp);
if(rename(TMP_FILE, FINAL_FILE) != 0) {
perror("rename");
}
}
int main() {
ensure_directory();
while(1) {
write_timestamp();
sleep(1);
}
return 0;
}
해당 파일을 컴파일하여 실행 가능한 바이너리를 생성한다.
$ gcc -o daemon_test daemon_test.c
2. 바이너리 설치 및 실행 권한 부여
생성된 바이너리를 일반적으로 사용자나 관리자에 의해 설치된 바이너리를 배치하는 위치인 /usr/local/bin 아래로 복사하고, 실행 권한을 부여한다.
$ sudo cp daemon_test /usr/local/bin/
$ sudo chmod +x /usr/local/bin/daemon_test
3. 데이터 및 로그 저장용 디렉터리 생성
서비스 관련 데이터를 저장하거나 로그를 기록할 디렉터리를 미리 생성해 놓는다.
$ sudo mkdir -p /var/lib/daemon_test
$ sudo mkdir -p /var/log/daemon_test
4. systemd 서비스 파일 생성 및 설정
서비스를 systemd로 등록하기 위해 /etc/systemd/system 경로에 서비스 설정 파일(*.service)을 작성한다.
$ vim /etc/systemd/system/daemon_test.service
[Unit]
Description=Daemon Test Program
After=network.target
[Service]
ExecStart=/usr/local/bin/daemon_test
Restart=always
RestartSec=2
User=root
WorkingDirectory=/var/lib/daemon_test
StandardOutput=append:/var/log/daemon_test/daemon_test.log
StandardError=append:/var/log/daemon_test/daemon_test.err
[Install]
WantedBy=multi-user.target
- Description : 서비스에 대한 간단한 설명
- After : 서비스 시작 순서 결정
- network.target으로 설정하면 네트워크 관련 서비스들이 실행된 이후에 시작됨
- Type: 서비스의 실행 구조
- simple : 디폴트 값으로 생략 가능, main()에서 루프를 도는 구조
- oneshot : 실행 후 지속되지 않고 금방 끝나는 초기화 스크립트 같은 데 사용
- ExecStart : systemd가 서비스를 시작할 때 실행할 바이너리(실행파일)의 절대 경로를 지정
- Restart : 재시작 여부 결정
- always로 설정하면 서비스가 비정상적으로 종료되거나 정상 종료로 중단되었을 때 자동으로 항상 재시작됨
- on-failure로 설정하면 서비스가 비정상적으로 종료된 경우(exit(0)이 아닌경우)에만 재시작됨
- RestartSec : 서비스가 종료된 후 재시작까지 대기 시간 지정 (초 단위)
- User : 서비스를 실행할 때 사용되는 리눅스 사용자를 지정
- root : root 권한으로 실행됨
- WorkingDirectory : 서비스가 시작될 때 사용할 작업 디렉터리를 지정 (서비스 내에서 상대경로 쓰지 않으면 생략 가능)
- StandardOutput, StandardError : 프로그램이 출력하는 표준 출력(stdout), 표준 에러(stderr)의 내용을 지정된 로그 파일로 리다이렉션함
- append:/path/to/file로 설정하면 기존 파 뒤에 추가 기록함. 이 외에도 null, tty, kmsg 등 다양한 출력 옵션 존재
- 프로그램 로그 확인 및 디버깅 시 유용
- 디폴트 값은 journal+console
- RuntimeDirectory : /var/run/<디렉토리명> 경로에 런타임 전용 디렉토리를 자동 생성하고 서비스 종료 시 자동으로 삭제함. /var/run은 사실상 /run의 심볼릭 링크고, 해당 경로는 메모리 기반 tmpfs 파일시스템에 해당함
- WantedBy : 서비스 시작 타겟 설정
- multi-user.target으로 설정하면 시스템 부팅 시 해당 순서에 자동으로 시작됨. multi-user.target이 graphical.target의 선행 타겟이기 때문에 CLI 서버든 GUI 데스크탑이든 둘 다 실행되고, 만약 GUI 환경에서만 동작해야 하는 서비스라면 graphical.target으로 설정할 수 있음.
✓ systemd 부팅 시 Target 순서
- sysinit.target : mount, udev 등 핵심 OS 초기화 수행
- basic.target : timer, socket, filesystem 등 기타 기초 서비스 활성화
- network.target : 네트워트 인터페이스 활성화
- network-online.target : DHCP 완료, IP 할당 등 네트워크가 연결된 상태로 네트워크에 의존하는 서비스는 이 타겟 이후 시작되도록 설정함
- multi-user.target : 텍스트 기반 런레벨로 일반적인 대부분 시스템 서비스가 이 타겟 이후 실행됨
- graphical.target : GUI 환경 런레벨로 GNOME, KDE 등 디스플레이 매니저가 시작됨
- default.target : 기본으로 부팅 시 사용하는 타겟으로 보통 multi-user.target 또는 graphical.target 중 하나를 symlink로 지정
5. systemd 서비스 활성화 및 시작
$ sudo systemctl daemon-reexec
$ sudo systemctl daemon-reload
$ sudo systemctl enable daemon_test
$ sudo systemctl start daemon_test
- systemctl daemon-reexec : systemd 데몬 자체를 다시 실행(re-execute)
- systemctl daemon-reload : 설정 파일의 변경사항을 systemd에 알림
- systemctl enable <서비스명> : 부팅 시 자동 실행되도록 활성화함. (/etc/systemd/system/ 해당 타겟 폴더 안에 서비스에 대한 심볼릭 링크 생성)
- systemctl start <서비스명> : 서비스를 즉시 실행함
6. 기타 서비스 관리 명령어
$ sudo systemctl status daemon_test
$ sudo systemctl stop daemon_test
$ sudo systemctl restart daemon_test
$ sudo systemctl disable daemon_test
- systemctl status <서비스명> : 서비스 상태 확임
- systemctl stop <서비스명> : 서비스 중지
- systemctl restart <서비스명> : 서비스 재시작
- systemctl disable <서비스명> : 서비스 자동 실행 해제 (/etc/systemd/system/ 해당 타겟 폴더 안에 있는 서비스에 대한 심볼릭 링크 삭제)

✓ 보통 systemd 서비스 개발 시 자주 사용하는 경로
- /usr/local/bin/ : 로컬 사용자용 실행파일(스크립트, 바이너리)을 위치시키는 경로, PATH에 포함되어 바로 실행 가능함
- /etc/ : 시스템 및 서비스의 설정 파일
- /usr/lib/ : 패키지/서비스 관련 바이너리(실행파일, 라이브러리), 내부 정적 리소스
- /var/lib/ : 서비스의 상태 정보, 데이터베이스, flag 파일 등 지속적으로 유지관리하는 데이터 저장소
- /var/cache/ : 서비스의 캐시 데이터 저장소
- /var/log/ : 서비스의 로그 저장소
- /tmp/ : 임시 파일 저장소로 재부팅 시 초기화됨
반응형
'프로그래밍 > 리눅스 시스템 프로그래밍' 카테고리의 다른 글
| Linux ] Unix Domain Socket(UDS) - IPC (0) | 2025.09.24 |
|---|---|
| Ubuntu ] Custom MOTD(Message of the Day) 설정하기 (0) | 2025.09.18 |
| C, Linux ] pthread 사용해 보기 (0) | 2022.08.25 |
| C, Linux ] ls 명령어 구현 (0) | 2022.08.17 |
| C, Linux ] main 함수의 매개변수 사용해서 파일 입출력 하기 (0) | 2022.08.17 |