anacron, 일반 사용자 권한으로 설정/실행

** ArchLinux 는 상황이 약간 다르다!

아래 글은 Ubuntu 환경을 가정했다. ArchLinux 에선, Cron/Anacron 부터 설치해줘야 한다.
설치하고 나서 아래 내용대로 설정해주면 되겠다.


이전에 쓴 꽃삽질기를 이은 cron 과 anacron 의 환상 조합 그 두번째.
이번에는 root 가 아닌 ‘일개’ 사용자가 anacron 을 사용하는 방법에 관해 정리한다.

그냥 crontab -e 로 원하는 작업을 설정하면 되긴 하지만, cron 의 한계인, 정해진 시간에 ‘꺼져 있을 때’의 문제가 첫번째고, crontab 설정의 backup 이 불편하다는게 두번째다. (crontab -l > crontab.backup 으로 해줘야 한다.)

이 글에선, cron 이 /etc/cron.daily 등을 사용하는 방법을 흉내내어 본다. 그리하면, 파일 관리가 조금은 더 쉬워질 수 있다.

다음 글에서 큰 도움을 얻었다.

StackExchange : How can I run anacron in user mode?


Anacron 설정

anacron 은 그냥 실행시키면 /etc/anacrontab 과 /var/spool/cron/crontabs/userid 밑의 파일들을 사용한다.
그러나, 이 파일들은 일반 사용자가 접근할 수 없으므로, 사용자 홈디렉토리에 저 파일들을 만들어줘야 한다.

어느 디렉토리를 택해서 만들지는 사용자 맘이고, 나는 ~/.anacron 에 만들기로 했다.
여기에, /etc/cron.daily 역할을 할 디렉토리도 만든다. 역시 맘대로 해도 되고, jobs_todo 라고 정했다. 그리고 각각 daily, weekly, monthly 용 프로그램을 넣을 디렉토리도 만든다.
마지막으로, spool 용 디렉토리도 만든다.

mkdir ~/.anacron
mkdir ~/.anacron/jobs_todo
mkdir ~/.anacron/jobs_todo/anacron.daily
mkdir ~/.anacron/jobs_todo/anacron.weekly
mkdir ~/.anacron/jobs_todo/anacron.monthly
mkdir ~/.anacron/spool

다시 말하지만, 위 디렉토리명은 모두 원하는대로 정하면 된다.

다음, 이 위치에 anacrontab (이름은 달리 정해도 된다.) 을 만든다. 그냥 편하게 /etc/anacrontab 을 복사한다.

cp /etc/anacrontab ~/.anacron/

그리고 이 파일을 편집한다.

# /etc/anacrontab: configuration file for anacron

# See anacron(8) and anacrontab(5) for details.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:$HOME/bin:$HOME/.local/bin

# These replace cron's entries
1	5	my_anacron.daily	run-parts --report $HOME/.anacron/jobs_todo/anacron.daily
7	10	my_anacron.weekly	run-parts --report $HOME/.anacron/jobs_todo/anacron.weekly
@monthly	15	my_anacron.monthly	run-parts --report $HOME/.anacron/jobs_todo/anacron.monthly

굳이 필요는 없을 듯 하지만, PATH 에 ~/bin 과 ~/.local/bin 을 추가했다.
job-identifier 로는 원래 있던 값인 cron.* 를 my_anacron.* 로 바꿨다. 이 설정으로 인해, ~/.anacron/spool/my_anacron.daily 파일 등이 생긴다.
이 파일들은 anacron 이 사용하는 timestamp 다.

command 로는 run-parts 를 사용하기로 했는데, 사실 이 기능을 사용하고 싶어서 길을 다소 돌아온 셈이다. run-parts 는 지정한 디렉토리에 있는 파일을 모두 실행해주는 명령으로, 여기서는 .anacron/jobs_todo/anacron.daily(weekly, monthly) 등에 있는 파일들을 돌리게끔 했다.

즉, anacron 에 의해 실행되게끔 하고 싶은 파일들을 저 디렉토리들에 넣어놓으면, 자동 실행이 된다.
이 방식이 아니면, crontab 에 한 줄씩 명령을 넣어놓든가, 아니면 거기에 run-parts 를 넣어야 하는데, 그렇게 되면 역시나 ‘PC가 꺼져 있을 때 문제’를 해결할 수가 없다.

anacron(정확히는 run-parts) 용 실행파일명은 반드시!

왜 그런지는 모르겠으나, .anacron/jobs_todo/anacron.daily(weekly, monthly) 에 들어갈 파일, 즉 run-parts 가 실행할 파일들의 파일명에는 확장자(.sh)가 있어선 안된다. runme 는 되지만, runme.sh 는 안된다. runme.py 도 마찬가지. run-parts --test <dir> 로 확인해보면, 저런 파일명을 가진 파일들은 출력되지 않음을 확인할 수 있다.

왜 안되는 걸까..?
찾아보니, 파일명을 찾는 regex 때문으로 보인다. (man page 에도 이 내용이 나와있다.)
글쓴이는 regex 를 적절히 바꾸라고 하는데, 그러기엔 복잡하니, 심볼릭 링크를 사용하는 방법이 좋아 보인다.

따라서, 이 디렉토리에 실제로 파일을 넣기 보다는, 심볼릭 링크를 만들되, sh 등 확장자를 빼주면 되겠다.
이런 식으로.

ln -s ~/.local/bin/program-to-run1.sh ~/.anacron/jobs_todo/anacron.daily/program-to-run1
ln -s ~/.local/bin/program-to-run2.py ~/.anacron/jobs_todo/anacron.daily/program-to-run2

이러면 설정이 끝난 듯 한데.. 정말로?
뭔가 빠진게 있다.

설정만 했지, 실행하는 명령은 넣지 않았다.

Anacron 실행

진짜(?) anacron 은, anacron.timer 에 의해 매 시간 실행된다.
그러나 사용자에 의해 설정된 anacron 은, 매시간 알아서 돌아가질 않는다.

사용자 anacron 이 시스템 anacron 과 동일한 기능을 가지려면, 매시간 돌려주는 기능을 강제 추가해줘야 한다.

이걸 어떻게 할까?
답은 cron, 정확히는 crontab.
사용자용 crontab(crontab -e)을 편집하여, 매시간 anacron 을 돌리게 만든다.

# Edit this file to introduce tasks to be run by cron.
# 
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
# 
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').# 
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
# 
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
# 
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
# 
# For more information see the manual pages of crontab(5) and cron(8)
# 
# m h  dom mon dow   command

# Anacron 실행 (조금 복잡하다.)
@hourly /usr/sbin/anacron -sdq -t $HOME/.anacron/anacrontab -S $HOME/.anacron/spool
  • @hourly 는 “0 * * * *” 와 같다. 즉, 매시 정각에 실행된다.
  • -sqd 는 anacron.service 에 있는 내용을 그대로 따라 했다. (man anacron 참고)
  • -t 는 anacrontab 파일의 위치,
  • -S 는 spool 디렉토리의 위치를 가리킨다.

모든 설정 끝.

모든 과정(공정?)을 정리해보면 다음과 같다.

  • crontab 으로, 매시간(@hourly) 사용자 지정 anacron 을 실행하게 한다.
  • anacron 은, $HOME/.anacron/spool 에서 timestamp 를 확인한 후,
  • anacrontab 에서 지정한 디렉토리(.anacron/jobs_todo/anacron.daily 등)에 있는 모든 파일을 실행한다.

위 작업은 매시간 반복된다.

또, 확실하진 않지만, 이 작업과 시스템의 anacron 이 충돌할 가능성은 없다. 각각 독자로 실행되기 때문이다. 인위로 두 anacron 을 돌려봤는데, 동시에 두개가 작동하고 있었다.

$ ps aux | grep -i anacron
....
root     31313  0.0  0.0   8760   748 pts/5    S+   23:07   0:00 anacron -sd
myuserid 31337  0.0  0.0   8760   748 pts/6    S+   23:07   0:00 anacron -sd -t /home/myuserid/.anacron/anacrontab -S /home/myuserid/.anacron/spool

Anacron 실행 확인

시스템 anacron 은 systemd 로 확인할 수 있다. sudo 는 없어도 된다.

$ systemctl status anacron.service
● anacron.service - Run anacron jobs
   Loaded: loaded (/lib/systemd/system/anacron.service; enabled; vendor preset: enabled)
   Active: inactive (dead) since Fri 2020-05-22 23:00:24 KST; 11min ago
     Docs: man:anacron
           man:anacrontab
  Process: 30154 ExecStart=/usr/sbin/anacron -dsq (code=exited, status=0/SUCCESS)
 Main PID: 30154 (code=exited, status=0/SUCCESS)

 5월 22 23:00:24 kdeneon systemd[1]: Started Run anacron jobs.
 5월 22 23:00:24 kdeneon anacron[30154]: Anacron 2.3 started on 2020-05-22
 5월 22 23:00:24 kdeneon anacron[30154]: Normal exit (0 jobs run)

이렇게 상황을 볼 수 있다. anacron.timer 로 조회하면 다음 실행 시간도 알 수 있다.

개인용 anacron 은 서비스가 아니므로 이 방식을 사용할 순 없고, 대신 cron 을 조회하면 된다.

$ systemctl status cron.service                                                                                                                                ~
● cron.service - Regular background program processing daemon
   Loaded: loaded (/lib/systemd/system/cron.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2020-05-22 19:37:06 KST; 3h 35min ago
     Docs: man:cron(8)
 Main PID: 1049 (cron)
    Tasks: 1 (limit: 4915)
   CGroup: /system.slice/cron.service
           └─1049 /usr/sbin/cron -f

 5월 22 22:00:01 kdeneon anacron[23411]: Anacron 2.3 started on 2020-05-22
 5월 22 22:00:01 kdeneon anacron[23411]: Will run job `my_anacron.daily' in 5 min.
 5월 22 22:00:01 kdeneon anacron[23411]: Jobs will be executed sequentially
 5월 22 22:05:01 kdeneon anacron[23411]: Job `my_anacron.daily' started
 5월 22 22:05:01 kdeneon anacron[23411]: Job `my_anacron.daily' terminated
 5월 22 22:05:01 kdeneon anacron[23411]: Normal exit (1 job run)
 5월 22 22:17:01 kdeneon CRON[24569]: pam_unix(cron:session): session opened for user root by (uid=0)
 5월 22 22:17:01 kdeneon CRON[24569]: pam_unix(cron:session): session closed for user root
 5월 22 23:00:01 kdeneon CRON[30088]: pam_unix(cron:session): session opened for user myuserid by (uid=0)
 5월 22 23:00:01 kdeneon CRON[30088]: pam_unix(cron:session): session closed for user myuserid

이 정도면 훌륭할 듯…?

Author: 아무도안

안녕하세요. 글 남겨주셔서 고맙습니다.