서버를 안전하게 관리하려면 상당한 관심을 집중해야 하죠. 그렇다고 매번 수작업을 진행하기는 어렵기 때문에 사전에 일정 규칙과 명령어를 입력해 서버에서 자동 실행토록 만들기 위해서 crontab(크론탭)을 이용하는데요. 여기서는 크론탭 설정 방법에 대해서 살펴보도록 하겠습니다.
정말 서버를 운영하기 위해서 알아야 하는 게 너무 많습니다. 전문적인 서버 운영자도 아니기 때문에 어지간하면 그냥 넘어가고 싶은데 이 세계는 타협이라는 게 없습니다. 세상의 모든 일이 다 그렇죠
제가 가상서버호스팅(VPS)를 운영하고 있는 이상 이 쪽 동네에서 사용하는 최소한 알고 있어야하는 기초적인 지식이 아주 많습니다. 오늘 이야기하려는 크론탭(Crontab)도 마찬가지 입니다.
며칠 전 인터넷나야나가 랜섬웨어에 걸렸다는 소식에 자극받아 자동으로 dropbox로 백업하는 방법에 대해서 포스팅했는데요.
이 포스팅의 마지막 부분에 crontab(크론탭) 설정방법이 나옵니다. 이 crontab(크론탭)을 설정하는 방법은 대부분 딱 몇 줄로 소개하고 말았는데요. 솔직히 그냥 따라 하면 되는 간단한 것이므로.
그런데 이 crontab(크론탭)이 작동하지 않는 것입니다. 왜 작동하지 않을까 고민하고 이런 저런 자료를 찾아보면서 이 crontab(크론탭) 설정 방법을 조금 자세하게 정리해야 겠다는 생각이 들었습니다.
1. Cron(크론)과 Crontab(크론탭)에 대해서
유닉스/리눅스 계열에서 특정 시간에 특정 작업을 하는 데몬은 Cron(크론)이라고 하고, 이 Cron(크론)이 언제 무슨 일을 하도록 설정해 특정 파일에 저장하는 Crontab(크론탭)이라고 합니다.
즉 Cron(크론)이라는 데몬이 원하는 시간에 원하는 명령(프로그램)을 수행하도록 만든 명령 리스트를 Crontab(크론탭)이라고 하고, 이러한 명령 리스트를 만드는 작업을 Crontab(크론탭) 작업이라고 할 수 있습니다.
이는 윈도우즈의 스케줄러와 비슷한 컨셉이라고 할 수 있죠.
서버가 24시간 가동되고 있으므로 적절한 시간에 적절한 명령어를 주어서 자동으로 실행시킬 수 있는 툴이죠.
예를 들어, 새벽 4시에 데이타베이스 백업 받아 줘라든지, 아침 7시에 서버의 사용량을 리포트하도록 한다든지 등등 적절하게 사용하면 아주 편리하게 성과를 낼 수 있는 방법입니다.
2. Crontab(크론탭) 설정하는 방법
crontab(크론탭)을 설정하는 방법은 두가지 방법이 있습니다.
첫째는 제가 앞서 소개한 포스팅에서 설명한 것 처럼 crontab -e 명령어를 사용해서 등록하는 것이구요.
둘째는 /etc/crontab에 직접 등록하는 방법입니다. 이경우는 vi, nano와 같은 편집기로 crontab 파일을 열어서 직접 편집을 합니다.
이 두가지 방법은 같은 듯 하면서도 조금은 다르다고 합니다.
2.1. crontab -e 명령어를 사용해 등록
그러면 crontab -e 명령어를 사용해서 등록하는 방법을 간단히 알아봅니다.
- 먼저 터미날(shell)에서 접속합니다. 그래야 명령을 내릴 수 있으므로.
- crontab -e 명령어 입력
- 아마 처음으로 시스템에서 crontab -e 명령어를 사용하면 no crantab for root라는 메세지가 나오면서 편집기를 선택하하고 나옵니다.
- 편집기는 ed, nano, vim basic, vim tiny 중에서 선택할 수 있습니다. 전는 easiest라고 쓰여진 nano편집기를 선택했습니다.
이 편집기는 GUI 편집기 특징을 어느 정도 갖추고 있어서 접근성이 좋았습니다.
▽ nginx 우분투에서 크론탭 등록시 처음 사용 할 편집기 선택 화면
- 편집기에서 명령어를 입력합니다.
. 30 4 * dbbackup.sh 와 같은 것 - 저장해서 빠져나옵니다.
. nano 편집기에서 저장 명령어는 CTRL+O이죠
. 빠져 나오는 명령은 CTRL+X - 편집기를 빠져나오면 ‘crontab: installing new crontab’이라는 메세지 뜹니다.
그러면 성공한 것이죠 - 이 명령이 등록되면 /var/spool/cron/crontabs/ 폴더에 root라는 파일이 생성됩니다.
▽ nginx 우분투에서 크론탭 등록 시 나노(nano) 편집 시용 모습
여기에서 crontab -e 명령어를 사용해 등록을 했다면 이와 관련된 다른 명령어가 있을 것입니다. crantab에는 crontab -e옵션 외 -l, -r옵션이 있는데요.
- crontab -e : 명령을 등록, 편집 – 맨 처음에 사용 시 편집기를 선택할 수 있다.
- crontab -d : 등록된 명령을 삭제
- crontab -l : 현재 등록된 리스트 출력
- crontab -l -u otheruser : otheruser 사용자가 등록한 crontab 리스트 출력
- crontab -r : 현재 사용자가 등록한 crontab 전체 삭제
crontab -e로 크론 명령어를 등록했다면 다 끝난 후 정상적으로 등록되었는지 알기 위해 crontab -l 명령을 사용해 list-up을 해볼 수 있겠습니다.
2.2. 편집기 또는 FTP에서 직접 편집(추천하지 않는 방식)
두번째 방법은 nano, vi 편집기를 이용해 터미널(shell)에서 /etc/crontab 파일을 직접 수정하는 것입니다.
예를 들어, FTP 열어놓고 서브라임 편집기로 연결해 편집할 수 있습니다. 굳이 터미널(shell)까지 열 필요가 없을 것 같다는 판단이 들기 때문에, 다른 작업 조중 FTP에서에서 작업 가능하기 때문에 선호될 수 있습니다.
그렇지만 이런 방식으로 크론탭 설정 시 작동하지 않는다는 이야기가 많습니다. 저도 한번 작동하지 않는 경험을 하고서는 이 방법은 사용하지 않고 있습니다. 아마도 크론탭 편집 저장하면 /etc/ 폴더에 crontab 파일과 /var/spool/cron/crontabs/ 폴더에 있는 root라는 파일에 동시에 저장이 되어야 하는데 FTP 작업 시 이런 작업이 제대로 작용하지 않는 것 같습니다.
- FTP로 연결하고
- /etc/crontab을 편집 선택해 오픈합니다.
- 서브라임 편집기에서 필요 내용을 입력합니다.
- 저장, FTP에서 업데이트 선택
▽ 서브라임 텍스트 편집기에서 crontab(크론탭) 편집 모습
그런데 이렇게 편집기로 /etc/crontab 파일을 직접 편집하는 경우 반드시 행위자가 root라는 것을 표기해 주어야 한다고 합니다.
그래서 명령어는 30 4 * root sh dbbackup.sh 와 같이 유저가 root라는 것을 명시해 주고 있습니다.
3. 크론탭 설정 가이드
크론탭 겅정 시 고려해야 할 사항이나 팁을 먼저 살펴보시죠.
3.1. 한줄에 하나의 명령어만 적용합니다.
아래와 같이 적용 시간과 먕령어를 각기 다른 줄에 적용하면 당연히 제대로 작동하지 않습니다.
00 11,16 * * *
/home/ramesh/bin/incremental-backup
Code language: PHP (php)
당연히 이는 아래와 같은 방식으로 변경되어야 합니다.
00 11,16 * * * /home/ramesh/bin/incremental-backup
Code language: PHP (php)
3.2. #를 사용해 주석을 달 수 있습니다.
나중에 크론탭을 관리하려면, 특이한 크롭 명령이나 조건에 대해서는 주석을 달아놓아야 나중에 수정이나 문제점 발견에 유리할 수 있고, 특히 후배들의 업무 파악에 큰 도움이 됩니다.
# 이것은 주석입니다.#
#------------------------#
#주석을 여기에 입력합니다.#
#------------------------#
Code language: PHP (php)
3.3. 로그 남기기
크론 작업 결과를 로그로 남겨 나중에 분석하고 싶다면 아래와 같은 방법으로 로그를 남기라는 명령을 줍니다.
* * * * * doitnow.sh > /var/log/crontab.kog 2>%1
Code language: PHP (php)
3.4. 크론탭 백업
여러가지 이유로 설정한 크론탭이 지워지거나 변형되는 경우를 대비해서 크론탭을 백업할 필요가 있습니다.
크론 기능을 활용해 주기적으로 크론탭을 백업하는 것도 좋은 방법입니다. 매일 0시에 백업하도록하는 크론탭 명령입니다.
00 00 * * * crontab -l > /home/crontab_bak
Code language: PHP (php)
4. 크론탭 설정 시 유의 사항 몇가지
지금부터는 crontab(크론탭) 사용 시 주의점과 문제 해결 방법을 적어 봅니다.
4.1. 실행파일 sh는 복사하지 말것
crontab 설정 시 실행파일 sh 파일을 기존에 만들어 놓은 것을 FTP로부터 복사해 오는 경우가 있습니다 왜 그런지는 모르지만 이렇게 복사해오는 경우 제대로 작동하지 않습니다.
nano 편집기로 바로 만든 실행 파일은 정상적으로 작동하지만, 복사해온 실행 파일은 멀쩡히 해당 디렉토리에 존재하고 파일 권한도 충분하고 소유권도 root로 되어 있어 문제가 없어보이는데 Permission denied, not found같은 메세지를 내 보냅니다.
여러변 테스트를 통해서 내린 결론은 crontab 실행 파일은 서버 세팅 시 새로 만들어야겠다는 결론이었습니다.
조금 귀찮지만 sh 파일을 편지기를 사용해 다시 만들자구요.
4.2. 변경 후 반드시 cron 다시 실행시키기
crontab(크론탭) 명령을 등록 후 반드시 cron을 다시 실행해야 변경 내용에 제대로 반영됩니다.
service cron start # 가동
또는
service cron restart # 재가동
Code language: PHP (php)
4.3. 실행 파일은 일반 경로에 위치, path 설정 – not found
cron은 보안때문에 사용자 개인 설정 파일을 참조하지 않습니다. 즉 사용자의 쉘 초기화 파일(.bashrc, .bash_profile)을 읽지 않습니다.
그러므로 실행 프로그램(예를 들어 *.sh)들은 /usr/bin이나 /bin과 같은 일반 경로에 있어야 cron이 제대로 찾아서 실행시킬 수 있습니다. 이런 경로에 없다면 /bin/sh: 1: /bin/dbbackup.sh: not found 같은 메세지가 메일로 보내집니다.
물론 실행 파일을 root에 놓는다면 문제는 없지만 다른 경로에 놓는 경우는 반드시 참고해야 합니다.
From: root@root (Cron Daemon)
To: root@root
Subject: Cron <root@root> /bin/dbbackup.sh
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Cron-Env: <path=/bin:/usr/bin:/usr/local/bin:/home>
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/root>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=root>
/bin/sh: 1: /bin/dbbackup.sh: not found
Code language: PHP (php)
4.4. 실행 파일 권한 문제 – Permission denied
가끔 실행 파일에 제대로 권한이 성정되지 않았다면 아래와 같은 메세지가 메일로 보내집니다.
/bin/sh: 1: dbit.sh: Permission denied
Code language: PHP (php)
그렇기 때문에 충분한 권한을 줍니다.
chmod +x dbbackup.sh
Code language: PHP (php)
4.5. crontab 작동 확인 – service cron status
그리고 crontab이 제대로 작동하는지 확인하기 위해서 service cron status 명령을 사용합니다.
service cron status # checks if cron is running
Code language: PHP (php)
그러면 아래와 같은 메세지를 보여줍니다.
# service cron status
● cron.service - Regular background program processing daemon
Loaded: loaded (/lib/systemd/system/cron.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2018-01-17 03:17:19 KST; 17h ago
Docs: man:cron(8)
Main PID: 16188 (cron)
Tasks: 3 (limit: 4915)
Memory: 45.9M
CPU: 5min 9.772s
CGroup: /system.slice/cron.service
├─ 5389 /usr/sbin/CRON -f
├─ 5461 /usr/sbin/sendmail -i -FCronDaemon -B8BITMIME -oem root
└─16188 /usr/sbin/cron -f
Jan 17 20:35:03 root sendmail[5293]: w0HBZ3GQ005293: to=root, ctladdr=root (0/0), delay=00:00:00, xdelay=00:00:
Jan 17 20:35:03 root CRON[5221]: pam_unix(cron:session): session closed for user root
Jan 17 20:35:03 root sendmail[5380]: My unqualified host name (happist) unknown; sleeping for retry
Jan 17 20:36:01 root CRON[5389]: pam_unix(cron:session): session opened for user root by (uid=0)
Jan 17 20:36:01 root CRON[5390]: (root) CMD (dbit.sh)
Jan 17 20:36:03 root sendmail[5380]: unable to qualify my own domain name (happist) -- using short name
Jan 17 20:36:03 root sendmail[5380]: w0HBa3Jw005380: from=root, size=418, class=0, nrcpts=1, msgid=<20180117113
Code language: PHP (php)
5. 크론탭 설정 사례
1분마다 실행할 것
* * * * * doitnow.sh
Code language: PHP (php)
동일 프로세스를 10분마다 실행
*/10 * * * * doitnow.sh
Code language: PHP (php)
매시 15분마다 실행
15 * * * * doitnow.sh
Code language: PHP (php)
1시간마다 실행
0 * * * * doitnow.sh
Code language: PHP (php)
2시간마다 실행
0 */2 * * * doitnow.sh
Code language: PHP (php)
오전 11시와 오후 4시마다 실행
00 11,16 * * * /home/ramesh/bin/incremental-backup
Code language: PHP (php)
근무시간(9시 ~ 오후 6) 내 매시간 실행
특정 작업이 근무 시간에만 실행되도록 설정하기 위해서는 시간을 09-18과 같은 표현을 사용합니다.
00 09-18 * * * /home/ramesh/bin/check-db-status
Code language: PHP (php)
주말을 제외하고 근무 시간에만 매시간 실행
특정 작업을 주중 근무일, 근무 시간에만 실행되도록 하기 위해서는 09-18과 같은 시간 표현과 1-5와 같은 요일 표현을 사용합니다.
00 09-18 * * 1-5 /home/ramesh/bin/check-db-status
Code language: PHP (php)
5시간 후 크론 실행 자동 중단할 것
크론 명령어 중에는 특정한 사정으로 크론 명령 작업이 계속되는 경우도 있을 것 입니다. 24시간 계속 명령이 지속되면 시스템 부하에도 무리가 가기 때문에 일정 시간 후 중단하라고 옵션을 걸 수 있을 것입니다.
이는 크론 본연의 명령 옵션은 아니지만 크론 활용 시 유용할 것 같아 소개합니다.
아래는 크론 실행 후 5시간(18000 secs) 후에는 멈추라는 옵션을 timeout이란 명령어를 사용해 적용합니다.
30 23 * * * timeout 18000 /usr/bin/php /var/www/ul/prices_all.php >> /var/www/ul/log/prices_all.txt
Code language: PHP (php)
특정 크론 명령을 강제 중단
사용할 일은 많지는 않겠지만 크론 명령이 실행되었는데 보안 등의 이유로 제대로 실행되지 않고 계속 실행 대기 상태에 놓이면 이런 명령이 쌓여서 엄청난 메모리를 사용하게 됩니다.
그런 상황이 오지 않토록 크론 명령과 시스템 상황을 제어해야겠지만 아무튼 특정 명령이 수행하지 못하고 대기 상태에 엤다면 아래와 같은 명령으로 이를 프로세스를 죽일 수 있습니다.
pkill -f 'wget -q -O - https://happist.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1'
Code language: PHP (php)
5. 마무리
위에서 crontab(크론탭) 명령을 등록 방법 2가지를 소개했는데요.
많은 사람들이 /etc/crontab 파일을 직접 편집하는 경우 crontab(크론탭)이 제대로 작동하지 않는다고 합니다. 저도 마찬가지이구요.
그래서 가능하면 cron -e 명령어를 이용해 등록하라는 가이드가 있는 듯 합니다.
그리고 crontab(크론탭) 명령을 등록 후엔 cron을 실행하는 명령을 주는 게 좋다고 합니다.
service cron status # checks if cron is running
service cron start # 단순리 크론을 다시 시작하라는 명령으로 기존 아직 끝나지 않는 명령 리스트를 그대로 가지고 시작한다.
service cron restart # 기존 크론 작업 리스트를 버리고 새로운 작업 리스트로 작업
service cron stop # stops it
Code language: PHP (php)
참고
웹서버 자동 실행 crontab(크론탭) 적용 시 문제점과 해결 방안
우분투 서버 보안 자동 업데이트 및 업데이트 메일 통보 방법
리눅스 서버 root 사용 중지로 리눅스 서버 보안 강화하기
워드프레스 보안 진단 WPScan 사용법 및 이메일로 결과 받아보기