systemd timer?

Timer Unit

  • 저번에 리눅스의 부팅과정을 봤을 때 systemd 가 특정 타겟을 보고 그에 맞는 서비스를 실행시킨다고 했었음
  • 그리고 그 정보는 서비스 유닛에 작성되어 있다고 했음
  • 그거랑 비슷함. 어떤 서비스를 실행시킬 지에 대한 정보가 타이머 유닛에 작성됨

Cron과의 차이점

  • 이전 시간에는 Cron에 대해서 다뤘다 보니 차이점을 알아보고 싶어졌음
  • cron은 독립적이지만 Timer Unit을 쓰면 systemd에 종속됨
  • 그러다보니 기존에 systemd에서 처리해주던 일들과 관련해서 이득을 많이 봄
    • 예시 : 실행 실패 확인, 상태 확인, 서비스 의존성 체크 가능 등등

Timer Unit 문법

  • cron 보다 기능이 많지만 조건이 있는데, Service Unit이 작성되어 있어야 한다는 점임
  • 그리고 Service Unit과 같은 위치에 Timer Unit이 있어야 함
[Unit]
Description=설명
After=특정 타겟 이후에 실행하도록 
Requires=특정 타겟을 필요로
 
[Timer]
OnCalendar=정할 시간
Persistent=서버가 꺼져있는동안 작업을 실행하지 못했다면, 다시 켜졌을 이걸 실행할 것인지?
 
[Install]
WantedBy=특정 타겟에 도달했을 실행하도록
  • 예시
[Unit]
Description=Run backup daily at 02:00 
 
[Timer]
OnCalendar=*-*-* 02:00:00 # 매일 2시에 작동
Persistent=true # 서버 꺼진 사이에 두시 지나면 켜졌을때 얘 실행됨
 
[Install]
WantedBy=timers.target # timers 타겟에 포함됨

OnCalendar

  • 언제마다 작동할 것인지 지정하는 부분
  • cron에서 앞에 다섯 자리를 의미함
OnCalendar=YYYY-MM-DD HH:MM:SS
  • cron처럼 별표를 사용하면 와일드카드의 의미임

특수 문자열

  • 특수 문자열은 아래의 표 참고
systemd timer의미cron 대응
minutely매 분(직접 대응 없음)
hourly매 시간@hourly
daily매일@daily
weekly매주@weekly
monthly매월@monthly
yearly매년@yearly / @annually
annually매년@annually
quarterly분기마다 (3개월)❌ (cron에 없음)
semiannually반기마다 (6개월)❌ (cron에 없음)
  • 특수 문자열 사용 예시
OnCalendar=weekly Mon 09:00:00 # 매주 월요일 오전 9시에 실행
OnCalendar=monthly 12:00:00 # 매 달 1일 오후 12시에 실행

매달 마지막 “날?”

  • cron에는 없는 기능인데, 연-월-일의 “마지막”을 특정해서 쓸 수 있음

  • 예시

OnCalendar=*-*-~ 18:00:00 # 매달 "마지막 날" 오후 6시에 실행

언제부터 언제까지

  • cron에서는 - 로 사용되던 기능임

  • systemd timer에서는 점 두 개(..) 를 사용함

  • 예시

OnCalendar=Mon..Fri 09:00:00 # 월요일부터 금요일까지 오전 9시에 한 번씩 실행

반복

  • cron에서는 */주기 로 사용되던 기능임 (ex. */5 5분마다)

  • systemd timer에서도 비슷하게 / 를 쓰기는 함

  • 예시

OnCalendar=*:0/10:00 # 매 10분 마다
OnCalendar=*-*-* 0/2:00:00 # 매 2시간 마다

복수의 조건 설정

  • 한 줄에 확실한 조건이면 여러 개 달 수있음
  • 예시
OnCalendar=Mon..Fri *-*-* 09..18:0/10:00
# 월요일부터 금요일까지
# 매 주
# 오전 9시부터 저녁 6시까지
# 10분 간격으로 실행

참고

  • cron에서는 한 줄에 겹치는 조건이 있다면 or 로 판단되기 때문에 한 줄이 여러 번 실행될 때도 있었지만,
  • systemd timer는 한 줄에 확실한 한 가지 조건이 있어야 한다.
  • 그리고 OnCalendar 줄을 추가해서 or 처럼 쓸 수 있다.

꿀팁

  • systemd-analyze calendar “캘린더문법” 을 쓰면 적용되는 시간을 볼 수 있음
  • 근데 systemd-analyze 가 나온지 그렇게 오래되지는 않아서 CentOS 7.9에서는 사용 불가.

그 이후

  • Timer Unit을 만든 뒤에는 다음 두 가지 명령어를 작성한다.
systemctl daemon-reload # 유닛 파일 수정하면 해야됨 (캐싱)
systemctl enable <서비스이> # 컴퓨터 킬 때 자동으로 시작되게 함

실습

  • crontab이랑 다르게 설정해야 하는 파일이 두 개나 있어서, 직접 만들어봄
  1. Service 파일
# /usr/lib/systemd/system/lsblk-log.service
 
[Unit]
Description=Log lsblk output
 
[Service]
Type=oneshot
ExecStart=/bin/lsblk
StandardOutput=append:/data/main/log/lsblk.log
StandardError=append:/data/main/log/lsblk.log
  1. Timer 파일
[Timer]
OnCalendar=*:0/1:00 # 1분마다 실행되게
Persistent=true
 
[Install]
WantedBy=timers.target
  1. 적용
systemctl daemon-reload
systemctl enable lsblk-log.service
systemctl start lsblk-log.service
  • 잘 살아있는지 보는 법
systemctl status lsblk-log.service
systemctl status lsblk-log.timer
journalctl -u lsblk-log.service

그런데…

  • 오류가 자꾸 나서 파일에 아무것도 안적힘
  • 이유는 systemctl 버전 때문이었음
  • 낮은 버전에서는 append: 문법을 지원을 안한다고 함
  • 그래서 ExecStart에다가 cron마냥 직접 써줘야됨
  • 그래서 변경된 service 파일
# /usr/lib/systemd/system/lsblk-log.service
 
[Unit]
Description=Log lsblk output
 
[Service]
Type=oneshot
ExecStart=/bin/bash -c '/bin/date "+%F %T" >> /data/main/log/lsblk_log.log && /bin/lsblk >> /data/main/log/lsblk_log.log 2>&1'