[kor] How to troubleshoot problems with cron not working properly on EC2 Ubuntu Instance
목표
- AWS EC2 Ubuntu Instance에서 cron을 사용하여 정기적으로 프로그램을 실행시키는 방법을 알아봅니다.
순서
- cron이란?
- Instance 생성
- cron 첫 시도
- 오류의 원인
- 오류의 해결
- 결론
- 참고
1. cron이란?
cron은 유닉스 계열 컴퓨터 운영 체제의 시간 기반 잡 스케줄러입니다.
쉽게 말해서, 특정한 작업을 고정된 시간, 날짜, 간격에 주기적으로 실행할 수 있도록 스케줄링하기 위해 사용되는 기능입니다.
cron은 crontab(cron table) 파일에 의해 구동됩니다.
유저들은 자신들만의 개별 crontab 파일들을 가질 수 있으며, 시스템 관리자들만이 편집할 수 있는 시스템 전반에 영향을 미치는 crontab 파일이 존재하기도 합니다.
# ┌───────────── min (0 - 59)
# │ ┌────────────── hour (0 - 23)
# │ │ ┌─────────────── day of month (1 - 31)
# │ │ │ ┌──────────────── month (1 - 12)
# │ │ │ │ ┌───────────────── day of week (0 - 6) (0 to 6 are Sunday to Saturday, or use names; 7 is Sunday, the same as 0)
# │ │ │ │ │
# │ │ │ │ │
# * * * * * command to execute
crontab의 문법은 위와 같습니다.
기본적으로 명령어가 실행될 분, 시, 일, 월, 요일을 지정할 수 있습니다.
crontab의 분, 시, 일, 월, 요일에는 특수문자를 사용할 수 있습니다.
- ‘*’ : 모든 값을 뜻합니다.
- ’?’ : 특정한 값이 없음을 뜻합니다.
- ’-‘ : 범위를 뜻합니다. (10-20 : 10일부터 20일)
- ’,’ : 특정한 복수의 값을 뜻합니다. (5,7,10 : 5분, 7분 10분)
- ’/’ : 시작시간 / 단위 를 뜻합니다. (*/10 : 매 10분)
- ‘L’ : 일에서 사용하면 마지막 일, 요일에서는 마지막 요일(토요일)을 뜻합니다. (5L : 마지막 금요일)
- ‘W’ : 가장 가까운 평일을 뜻합니다. (15W : 15일에서 가장 가까운 평일(월~금))
- ’#’ : 몇째주의 무슨 요일을 표현합니다. (3#2 : 2번째주 수요일)
2. Instance 생성
우선 EC2 Instance를 생성하는 것 부터 시작합니다.
본 설명은 Ubuntu OS를 기반으로 설명합니다.
이름은 적절히 설정해준 이후, Ubuntu OS를 선택해줍니다.
이후 Instance Type, Disk 등의 옵션을 사용 목적에 맞게끔 설정해준 이후, 생성을 완료해줍니다.
3. cron 첫 시도
ssh를 사용하여 instance에 접속하면 다음과 같은 화면이 나타납니다.
EC2 Ubuntu Instance는 기본적으로 cron이 설치되어있으며, instance가 실행될 때 자동적으로 cron 역시 active 상태가 됩니다.
cron의 상태는 ‘service cron status’ 명령어를 통해 확인할 수 있습니다.
초록색으로 표시되어있는 active (running)은 현재 cron이 동작중이라는 의미입니다.
cronjob에 task를 등록시켜두었다면, 등록된 주기마다 자동으로 task가 실행됩니다.
cronjob에 task를 등록하려면 ‘crontab -e’ 명령어를 사용하면 됩니다.
vi, nano 등의 텍스트 에디터를 사용하여 task를 등록할 수 있습니다.
crontab -e 명령어를 처음 실행할 때, 다음과 같이 어떤 텍스트 에디터를 사용할 것인지를 선택할 수 있습니다.
본인에게 가장 익숙한 텍스트 에디터를 선택하시면 됩니다.
cron에서 추천하는 nano를 사용해보도록 하겠습니다.
본 글에서는 간단히 ~/ 디렉토리에 ‘crondir’이라는 하위 디렉토리를 생성하는 mkdir.sh 쉘 스크립트를 작성하여 cron에 등록시키겠습니다. 디렉토리 생성 코드 앞뒤로 echo를 작성하여 log에서 확인할 수 있도록 합니다.
첫 crontab에 task를 등록하기 위해 명령어를 실행하면, 다음과 같이 cron에 task를 등록하기 위한 간단한 문법을 설명해줍니다.
자세한 내용을 1번 문단에서 설명하였으므로, 주석들은 모두 제거해줍니다.
그리고, 미리 생성해둔 mkdir.sh 파일을 5분마다 실행할 수 있게끔 설정해둡니다.
그리고 출력된 문자나 에러를 확인할 수 있도록 log 파일을 생성합니다.
cron으로 task 실행 시, 터미널에 출력되는 문자들은 출력되지 않습니다.
때문에 따로 log를 확인할 수 있도록 하는 설정이 필요합니다.
‘*/5 * * * * bash /home/ubuntu/mkdir.sh > /home/ubuntu/log/mkdir.sh.log 2>&1’
*/5 * * * *는 매 5분마다 task를 실행시키겠다는 의미이고, 그 뒷부분은 일반적으로 터미널에서 사용하는 명령어입니다.
2>&1은 에러를 로그에 기록하기 위한 명령어입니다.
리눅스에서 0은 표준입력, 1은 표준출력, 2는 표준에러를 의미합니다.
따라서 2>&1은 에러가 발생하면 표준출력으로 에러를 표시해달라는 의미가 됩니다.
여기서 표준출력을 log에 기록하도록 설정해두었으므로, 위와 같이 명령어를 작성할 경우 에러까지 포함하여 log에 기록할 수 있습니다. (log 디렉토리는 미리 생성해두어야합니다.)
cron에 task 등록 시 주의해야 할 점은, 상대경로가 아닌 절대경로를 사용하는 것이 좋다는 것입니다.
crontab에 사용되는 경로부터, 실행되는 task에서 사용되는 경로 모두 절대경로로 통일해 두는 것이 좋습니다.
등록을 완료한 이후, ‘crontab -l’ 명령어를 통해 task가 제대로 등록되었는지 확인할 수 있습니다.
이제 5분을 기다려 디렉토리가 제대로 생성되는지만 확인하면 됩니다.
4. 오류의 원인
그런데 아무리 기다려봐도 디렉토리가 생성되지 않습니다.
‘sudo service cron stop’으로 cron을 정지한 후, ‘sudo service cron start’를 통해 다시 시작해봐도,
‘sudo service cron restart’로 cron을 재시작해보아도 디렉토리가 생성될 기미도 보이지 않습니다.
어찌된 일인지 log를 확인하려고 해도, log 파일 역시 생성되지 않습니다.
작성한 코드의 문제일까 싶어서 직접 터미널에서 실행해보면 정상적으로 실행되는 것을 확인할 수 있습니다.
그렇다면, 문제는 cron에 있습니다.
cron에서 어떤 에러가 발생했는지 확인해보기 위해서는 ubuntu os의 자체 log를 확인해보아야 합니다.
ec2 ubuntu의 system log는 /var/log/syslog에 위치해 있습니다.
syslog에는 cron 뿐만 아니라 전체 시스템 로그가 기록되므로, gerp을 이용해줍니다.
‘cat /var/log/syslog | grep CRON’ |
위 명령어를 통해 로그를 확인해 보면, 다음과 같은 에러가 눈에 띕니다.
MTA가 설치되지 않았다는 의미인데, MTA는 Mail Transfer Agent의 약자입니다.
MTA가 없어서 에러가 발생하는 이유는 다음과 같습니다.
cron의 로깅은 다른 데몬들의 로깅처럼 로그 파일을 /var/log와 같은 디렉토리에 작성하는 것이 아니라, MTA를 통해서 해당 크론탭을 소유한 각 유저들에게 로그 내용을 전달하는 방식입니다.
cron에 등록한 명령어에서 이 전달받은 로그 내용을 파일에 기록하도록 설정해 두었으므로 다른 로깅들처럼 파일로 된 로그가 작성되는 것처럼 보이는 것입니다.
리눅스는 여러 명의 유저들이 동시에 사용하는 것을 전제로 계정 시스템이 구현되어 있고, crontab 역시 각 유저별로 따로 작성되기 때문에 cron의 로그를 유저별로 따로 관리할 필요가 있습니다.
만약 타 데몬들처럼 정해진 디렉토리에 로그를 작성하도록 설계되어있었다면, 어떤 로그가 어떤 유저의 것인지 파악하기 매우 어려울 것입니다.
또한 /var/log와 같은 디렉토리에 로그를 기록한다면, 루트 계정이 아닌 일반 계정들은 로그를 확인할 수 없는 이상한 경우가 발생합니다.
그렇다면 이 에러를 해결할 수 있는 방법은 다음과 같습니다.
- 명령어에 로깅 기능을 제거한다. → (*/5 * * * * bash /home/ubuntu/mkdir.sh)
- MTA를 설치한다.
여기서 MTA를 설치하는 방법으로 오류를 해결하겠습니다.
5. 오류의 해결
- MTA를 설치하기 위해서는 ‘sudo apt-get install postfix’ 명령어를 실행해줍니다.
- Y를 입력하여 설치를 계속 진행해 줍니다.
- 설치가 진행되며 아래와 같은 화면이 나타납니다.
- Enter를 입력하여 Ok를 선택하면 다음과 같은 화면이 나타납니다. 목표는 Local directory에 로그를 작성하는 것이므로 방향키를 통해 Local Only를 선택한 후 Enter를 입력합니다.
- 그러면 다음과 같은 화면이 나타나는데, 이 부분은 크게 신경쓰지 않고 Ok를 선택한 후 Enter를 입력합니다.
- 설치가 완료됩니다.
- 이후 ‘sudo dpkg-reconfigure postfix’ 명령어를 입력한 후, 위의 과정을 다시 한 번 반복하면 System mail name을 입력하는 창에서 끝나는 것이 아니라, 다음 화면으로 넘어가집니다.
이 과정은 cron의 기본 로깅 디렉토리를 설정하는 화면으로, crontab에 별도의 로깅 설정을 해주지 않았을 때 로깅되는 위치를 의미합니다.
빈칸으로 넘어갈 시에는 /var/mail/nobody에 로그가 생성됩니다.
원하는 디렉토리로 설정해주면 됩니다.
- 다음 과정은 cron 로그를 수신하는 메일 도메인들을 입력하는 화면입니다.
Local Only이므로 기본 설정을 유지한 채 Ok를 입력하면 됩니다.
- 다음 과정은 메일 대기열에 동기식 업데이트를 적용할 것인지를 묻는 화면입니다.
별도의 백업 시스템을 사용하지 않는다면, 동기식 업데이트를 사용하는 것을 추천하고 있습니다.
- 다음 과정은 메일 릴레이 대역을 입력하는 화면입니다. 기본적으로 로컬 네트워크가 입력되어 있으므로 첫 화면에서 Local Only를 선택했다면 그냥 Ok하셔도 됩니다.
- 다음 과정은 mailbox 크기 제한을 설정하는 화면입니다. 본인의 로그 파일 사이즈 제한을 어느 정도로 설정해야 적당할지 판단한 후, 판단한대로 설정해주시면 됩니다.
0은 제한이 없음을 의미합니다.
- 다음 과정은 로컬 주소 확장 설정 화면입니다. 원하는 문자를 사용하시면 되며, 빈칸은 확장을 사용하지 않겠다는 의미입니다.
- 다음 화면은 어떤 인터넷 프로토콜을 사용할지에 대한 설정 화면입니다. 특별한 용도나 목적이 없다면 all을 선택합니다.
- 이후 모든 설정이 완료된 후, ‘sudo systemctl reload postfix’ 명령어를 입력합니다.
- 마지막으로 ‘sudo service cron restart’ 명령어를 입력하면, cron에서 로깅 기능이 있는 task 동작 시 MTA 에러 없이 정상적으로 동작하는 것을 확인할 수 있습니다.
6. 결론
결론적으로, 로깅 기능을 사용하지 않는다면 정상적으로 cron은 동작합니다.
하지만 특별히 아무런 설정도 하지 않은 AWS EC2 Ubuntu Instance에서 cron에 로깅 기능을 사용하고 싶다면, 별도로 MTA 기능을 설치 후 설정해야만 정상적으로 task가 수행된다는 것을 주의해야 합니다.
7. 참고
- cron - 위키백과, 우리 모두의 백과사전 (wikipedia.org)
- UNIX/Linux - 리눅스 Cron 이란 무엇인가 : 네이버 블로그 (naver.com)
- [Cron] 크론(cron) 표현식 정리 (tistory.com)
- Crontab에서 스크립트가 실행되지 않는 문제 해결하기 :: 초보 개발자의 메모장 (tistory.com)
- networking - Why does cron require MTA for logging? - Unix & Linux Stack Exchange
- How To Install and Configure Postfix on Ubuntu 20.04 - DigitalOcean