cron job scheduler 대신 사용할 수 있는 systemd timer에 대해 알아 본다.

Systemd Timer 컨셉


동작 순서

Systemd Timer 역활

systemd timer unit은 Linux에서 작업을 예약하는 메커니즘을 제공한다.
이러한 작업의 실행 시간은 시간과 날짜 또는 이벤트에 따라 달라질 수 있다.

Systemd Timer 구성

.timer 파일 이름 확장자로 식별 됨.
각 timer 파일에는 제어하는 ​​해당 service 파일이 필요하다. 즉, timer 파일은 해당 서비스 파일을 활성화하고 관리한다.

Systemd Timer 가 지원하는 기능 및 특징

  • 타이머 단위는 일반 systemd 서비스로 처리되므로 systemctl로 관리할 수 있다.
  • 타이머는 real-time(캘린더 이벤트에서 트리거됨)이거나 monotonic(특정 시작 지점에서 지정된 시간이 경과하면 트리거됨)일 수 있다.
  • 시간 단위는 system journal에 기록되므로 모니터링하고 문제를 해결하기가 더 쉽다.
  • 타이머는 중앙 집중식 systemd 관리 서비스를 사용한다.
  • 예상 실행 시간 동안 시스템이 꺼져 있는 경우, 시스템이 다시 실행되면 타이머가 실행된다.
  • cron과 대비해서 더 디테일한 스케줄 설정이 가능하다. (초 단위까지 가능)

Systemd Timer 사용


간단한 예제를 통해 사용하는 방법을 설명한다.
여기서는 btrbk-snap 이라는 임의의 서비스명으로 설명하였으나, 본인 시스템에 맞게 다른 이름으로 변경하여 사용하면 된다.


1. Timer 작성

1.1 service 파일 작성

# vim /usr/lib/systemd/system/btrbk-snap.service
[Unit]
Description=Run to btrbk snapshot

[Service]
ExecStart=/usr/local/etc/btrbk-snap.sh

[Install]
WantedBy=multi-user.target

1.2 script 작성
service 파일의 [Service] 부분에 선언된 스크립트를 작성한다.

# vim cat /usr/local/etc/btrbk-snap.sh

#!/bin/bash
/sbin/btrbk -c /etc/btrbk/btrbk_backup_remote.conf run

-> ExecStart= 에 스크립트가 아니라 명령어를 직접 선언해도 된다.

1.3 timer 파일 작성

# vim /usr/lib/systemd/system/btrbk-snap.timer
[Unit]
Description=Performing btrbk-snap.service

[Timer]
OnBootSec=3min
OnCalendar=*-*-* *:0/10:00
Unit=btrbk-snap.service

[Install]
WantedBy=timers.target

-> OnBootSec : 시스템이 부팅된 후 얼마 후부터 동작할지에 대한 옵션. 여기서는 3분 후로 설정
-> OnCalendar : 실행 주기를 설정. 여기서는 매 10분 마다 실행되도록 설정
-> [Timer] 내의 Unit 인자는 service와 timer 파일명이 서로 일치할 경우 생략해도 무관하다.

1.4 작성된 파일 검사

# systemd-analyze verify /usr/lib/systemd/system/btrbk-snap.*

-> 아무런 메시지도 출력되지 않으면 설정에 문제가 없는 것임

1.5 캘린더 포맷 검사

# systemd-analyze calendar --iterations 5 "*-*-* *:0/10:00"
  Original form: *-*-* *:0/10:00
Normalized form: *-*-* *:00/10:00
    Next elapse: Tue 2024-08-27 17:00:00 KST
       (in UTC): Tue 2024-08-27 08:00:00 UTC
       From now: 9min left
       Iter. #2: Tue 2024-08-27 17:10:00 KST
       (in UTC): Tue 2024-08-27 08:10:00 UTC
       From now: 19min left
       Iter. #3: Tue 2024-08-27 17:20:00 KST
       (in UTC): Tue 2024-08-27 08:20:00 UTC
       From now: 29min left
       Iter. #4: Tue 2024-08-27 17:30:00 KST
       (in UTC): Tue 2024-08-27 08:30:00 UTC
       From now: 39min left
       Iter. #5: Tue 2024-08-27 17:40:00 KST
       (in UTC): Tue 2024-08-27 08:40:00 UTC
       From now: 49min left

-> 포맷이 정상적이면 위와 같이 service가 실행되는 주기(--iterations 5 의해 5회)에 따라 출력될 것이다.
-> cron과 포맷이 상이하고, 좀 더 복잡하다. 따라서 위와 같이 OnCalendar포맷을 꼭 검사해 볼 것

1.6. 캘린더 포맷 예시

- FORMAT
OnCalendar=요일 년-월-일 시:분:초

- 매주 금요일 오후 7시에 실행 (반복)
OnCalendar=Fri *-*-* 19:00:00

- 매일 오전 6시에 실행 (반복)
OnCalendar=Mon..Sun *-*-* 6:00:00

- 매주 월요일과 화요일 오전 1시와 오전 4시에 실행 (반복)
OnCalendar=Tue,Sun *-*-* 01,04:00:00

- 2024년 8월 23일 00시 00분 01초에 실행 (1회성)
OnCalendar=Mon..Sun 2024-08-23 00:00:01
또는
OnCalendar=2024-08-23 00:00:01
-> 좌측 맨 앞을 생략 시, 매 요일로 지정됨

- 하나의 timer 파일에 한 개 이상의 OnCalendar를 지정하기
OnCalendar=2024-08-23 02:00      (2024년 8월 23일 오전 2시에 1회 실행)
OnCalendar=Mon..Fri *-*-* 10:00  (월 ~ 금요일 사이 오전 10:00에 반복 실행)
OnCalendar=Sat,Sun *-*-* 22:00   (토, 일요일에 오후 10:00에 반복 실행)
-> 1회성 1개 실행, 반복성 2개 실행. 즉, 한 가지 timer에 의해 3가지 스케줄이 실행.
-> 우측 끝의 00 생략 시 00초로 세팅 됨

-> systemd-analyze calendar --iterations N "FORMAT" 명령을 통해 꼭 검증을 할 것
-> cron과 다른 점은 일부 필드 값을 생략해도 된다. 예를 들어 OnCalendar=00:00 로 설정하면 매일 자정에 반복 실행 된다.

2. Timer 동작

2.1 서비스 시작 및 등록

# systemctl enable --now btrbk-snap.timer

-> btrbk-snap.timer 서비스를 시작 및 등록

2.2 서비스 동작 및 등록 여부 확인

# systemctl status btrbk-snap.timer | grep Active
    Active: active (waiting) since Mon 2024-08-26 17:14:45 KST; 23h ago

# systemctl is-enabled btrbk-snap.timer
enabled

2.3 서비스 컨트롤 및 확인

- 시작 / 정지 / 재시작
# systemctl start btrbk-snap.timer
# systemctl stop btrbk-snap.timer
# systemctl restart btrbk-snap.timer

- 서비스 상태 확인
# systemctl status btrbk-snap.timer

- timer / service 파일 설정을 변경 후 반영하기
# systemctl daemon-reload

- btrbk-snap.timer/service 설정 파일 내용 확인
# systemctl cat btrbk-snap.timer
# systemctl cat btrbk-snap.service

2.4 타이머 스케줄링 확인

- 특정 타이머의 상태 확인
# systemctl list-timers btrbk-snap.timer
NEXT                        LEFT      LAST                        PASSED  UNIT             ACTIVATES
Tue 2024-08-27 21:50:00 KST 5min left Tue 2024-08-27 21:44:21 KST 26s ago btrbk-snap.timer btrbk-snap.service
-> NEXT: 다음번 실행될 시각, LEFT: 다음번 실행 시각까지 남은 시간, LAST: 마지막 실행되었던 시간,
PASSED: 마지막 실행으로부터 흐른 시간, UNIT: timer, ACTIVATES: timer에 연결된 Service

- 패턴 매치로 검색된 타이머의 상태 확인
# systemctl list-timers btrbk*

- 모든 타이머의 상태를 출력
# systemctl list-timers --all

- timer 파일의 캘린더 시간을 변경 후 적용 / 적용 확인하기
# systemctl daemon-reload
# systemctl list-timers btrbk-snap.timer

2.5 기타 (tmp 디렉토리 자동 삭제 정리)

# systemctl list-timers --all
NEXT                        LEFT         LAST                        PASSED       UNIT                         ACTIVATES
Wed 2024-08-28 17:29:46 KST 19h left     Tue 2024-08-27 17:29:46 KST 4h 20min ago systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
-> systemd가 적용된 리눅스 시스템이라면 기본적으로 systemd-tmpfiles-clean.timer 가 확인될 것이다.

systemd-tmpfiles-clean.timer의 내용을 살펴보면 부팅 후 15분 후, 그리고 매일 하루에 한번씩 수행되도록 설정되어 있다.
-> 타이머에 의해 systemd-tmpfiles-clean.service 가 호출되고, Service 부분에 선언된 ExecStart=systemd-tmpfiles --clean 에 의해 tmp 디렉토리를 정리하는데 이 때 아래 설정을 참고하여 /tmp와 /var/tmp를 clean-up 하게 된다.

# cat /usr/lib/tmpfiles.d/tmp.conf | grep -v ^#
q /tmp 1777 root root 10d
q /var/tmp 1777 root root 30d
-> 첫 번째 라인은 /tmp 디렉토리 내의 데이터가 변경된지 10일이 넘었을 경우 삭제
-> 두 번째 라인은 /var/tmp 디렉토리 내의 데이터가 변경된지 30일이 넘었을 경우 삭제

그런데 이 기본 설정에서는 애플리케이션이 실행되는 동안에 애플리케이션이 사용하는 연관된 하위 디렉토리(/tmp 내)의 데이터가 의도치 않게 삭제될 수 있는 맹점이 있다. (아래 github 이슈 확인)
https://github.com/NixOS/nixpkgs/issues/86600

따라서 데이터가 의도치 않게 삭제되는 것을 방지하기 위해 부팅시에만 삭제될 수 있도록 아래와 같이 수정/적용하는 방법을 고려해 볼 필요가 있다.
q! /tmp 1777 root root 10d
q! /var/tmp 1777 root root 30d

또한 될 수 있는한 /tmp와 /var/tmp에는 저장 용도의 데이터를 두지 않는 습관을 갖도록 한다.

2.6 기타 (일회성 작업 예약 실행)

at와 비슷한 1회성(transient) 예약 실행 방법

- 예약 실행 설정
현재 시각이 13시 25분 이라고 할 때 1분 뒤 실행
# systemd-run --on-active=60 touch /tmp/abc         (60초 후 실행, --on-active=1min 으로 설정해도 된다.)
또는
# systemd-run --on-calendar='13:26' touch /tmp/abc    (13시26분에 실행, 사실 이 방법은 정확히 지금으로부터 60초 뒤가 아닐 가능성이 크다.)

- 예약 실행 확인
# systemctl list-timers --all
NEXT                        LEFT          LAST                        PASSED   UNIT                                        ACTIVATES
Thu 2024-08-29 13:26:00 KST 11s left      -                           -        run-rdf1b7a72a88341129a8611a6304440e4.timer run-rdf1b7a72a88341129a8611a6304440e4.service

- 예약 내용 확인
# systemctl cat run-rdf1b7a72a88341129a8611a6304440e4.timer
# /run/systemd/transient/run-rdf1b7a72a88341129a8611a6304440e4.timer
# This is a transient unit file, created programmatically via the systemd API. Do not edit.
[Unit]
Description=/usr/bin/touch /tmp/abc

[Timer]
OnCalendar=13:26 (또는 on-active으로 설정 시 OnActiveSec=1min)
RemainAfterElapse=no

- 예약 실행 중단
# systemctl stop run-rdf1b7a72a88341129a8611a6304440e4.timer
# systemctl daemon-reload

systemd timer

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다