Cron 문제 해결: 작업이 실행되지 않는 이유

조용히 실패하는 cron 작업은 답답하고 일반적입니다. 이 체계적인 문제 해결 가이드는 가장 빈번한 문제와 해결 방법을 안내하여 예약된 작업을 안정적으로 실행하는 데 도움을 줍니다.

먼저 기본 사항 확인

복잡한 디버깅에 들어가기 전에 기본 사항을 확인하세요. 많은 cron 문제는 확인하기 쉬운 간단한 실수에서 비롯됩니다.

먼저 crontab이 실제로 저장되었는지 확인하세요. "crontab -e"로 편집한 후 "crontab -l"로 crontab을 나열하여 확인하세요. 항목이 나타나지 않으면 저장되지 않은 것입니다. 일반적인 원인: 저장하지 않고 편집기를 닫음, 잘못된 사용자 계정(crontab은 사용자당), 또는 crontab이 거부되게 한 구문 오류.

Cron 데몬이 실행 중인지 확인하세요. 대부분의 Linux 시스템에서 "systemctl status cron" 또는 "systemctl status crond"를 사용하세요(데몬 이름은 배포판에 따라 다름). Cron이 실행되지 않으면 작업을 실행할 수 없습니다. "systemctl start cron" 또는 "service cron start"로 시작하세요.

Cron 구문이 유효한지 확인하세요. Crontab 생성기를 사용하여 표현식을 검증하고 실행 시기를 확인하세요. "0 0 * * 8"(8일이 없음) 또는 "60 0 * * *"(분 60이 존재하지 않음)과 같은 간단한 오타는 조용한 실패를 일으킵니다. Cron 데몬은 종종 구문 오류를 명확하게 보고하지 않습니다.

Cron 실행에 대한 시스템 로그를 확인하세요. Systemd 시스템에서 "journalctl -u cron" 또는 "journalctl -u crond"를 사용하세요. 이전 시스템에서 /var/log/syslog 또는 /var/log/cron을 확인하세요. 이러한 로그는 작업 자체가 실패하더라도 cron이 작업을 시작하는 시기를 보여줍니다. 작업이 시작되는 것을 보지 못하면 문제는 cron 일정에 있습니다. 시작하지만 실패하는 것을 보면 문제는 명령에 있습니다.

올바른 사용자의 crontab을 편집하고 있는지 확인하세요. Cron 작업은 crontab을 소유한 사용자로 실행됩니다. 루트 권한이 필요한 경우 사용자 crontab이 아니라 루트 crontab을 편집하려면 "sudo crontab -e"를 사용하세요. 일반 사용자로 "crontab -e"를 실행한 다음 루트 권한이 필요한 명령을 실행하려고 하면 권한 오류로 실패합니다.

명령이 존재하고 실행 가능한지 확인하세요. Crontab에서 정확한 명령을 터미널에서 수동으로 실행하세요. 대화식으로 실패하면 cron에서도 확실히 실패합니다. 대화식으로 성공하지만 cron에서 실패하면 문제는 환경 차이일 가능성이 높습니다(다음에 다룸).

환경 및 경로 문제

Cron 작업이 실패하는 가장 일반적인 이유는 대화형 셸과 cron의 최소 환경 간의 환경 차이입니다. 터미널에서 명령을 실행할 때 셸은 광범위한 설정을 제공합니다: 실행 파일을 찾을 위치가 있는 PATH, .bashrc 또는 .profile의 환경 변수, 홈 또는 프로젝트 디렉토리로 설정된 작업 디렉토리 및 언어/로케일 설정. Cron은 이 중 거의 아무것도 제공하지 않습니다.

Cron의 PATH는 일반적으로 "/usr/bin:/bin"만이므로 이 두 디렉토리에서만 실행 파일을 찾을 수 있습니다. 스크립트가 /home/user/bin에 있으면 cron은 찾을 수 없습니다. 작업이 "python"을 사용하고 python이 /usr/local/bin 또는 virtualenv에 있으면 cron은 찾을 수 없습니다. 항상 절대 경로를 사용하세요: "python3" 대신 "/usr/bin/python3", "backup.sh" 대신 "/home/user/scripts/backup.sh".

의존하는 환경 변수는 cron에 존재하지 않습니다. DATABASE_URL, API_KEYS, AWS 자격 증명 및 .bashrc의 다른 변수를 사용할 수 없습니다. Crontab 자체에서 명시적으로 설정하거나(맨 위, 작업 줄 앞에: "DATABASE_URL=...") 스크립트에서 설정하세요. 또는 환경 파일을 소스로 사용하세요: ". /home/user/.env && /home/user/script.sh".

작업 디렉토리는 cron에서 예측할 수 없습니다 - 종종 사용자의 홈 디렉토리이지만 보장되지 않습니다. 스크립트가 로컬 파일을 기대하는 "open('config.json')"을 수행하면 다른 디렉토리에서 실행될 때 실패합니다. 모든 파일 작업에 절대 경로를 사용하거나 필요한 디렉토리로 명시적으로 cd하세요: "cd /home/user/project && ./script.sh".

환경 문제를 디버그하려면 환경을 출력하는 테스트 cron 작업을 만드세요: "* * * * * env > /tmp/cron-env.txt". 실행되도록 하고 1분 기다린 다음 /tmp/cron-env.txt를 검사하여 cron이 제공하는 환경을 정확히 확인하세요. 대화형 셸의 "env"와 비교하여 누락된 것을 확인하세요.

Python 프로젝트의 경우 명시적으로 virtualenv를 활성화하세요: "*/5 * * * * cd /path/to/project && /path/to/venv/bin/python script.py". Virtualenv의 python 바이너리에는 환경 설정이 포함되어 있습니다. Node.js, Ruby 또는 다른 언어별 환경에도 마찬가지입니다.

로케일 문제는 미묘한 버그를 일으킵니다. Cron은 "POSIX" 로케일로 실행될 수 있지만 개발 환경은 "en_US.UTF-8"을 사용합니다. 이는 문자열 정렬, 날짜 구문 분석 및 문자 인코딩에 영향을 미칩니다. 필요한 경우 명시적으로 로케일을 설정하세요: "LC_ALL=en_US.UTF-8 /path/to/script".

환경을 일관되게 설정한 다음 실제 스크립트를 호출하는 래퍼 스크립트를 만드는 것을 고려하세요. 래퍼는 환경 파일을 소스로 사용하고, PATH를 설정하고, 올바른 디렉토리로 변경하고, 공통 설정을 처리합니다. 이렇게 하면 모든 crontab 항목에서 반복하는 대신 한 곳에서 환경 구성을 중앙 집중화합니다.

로깅 및 출력

출력 없이는 cron 작업 오류를 디버그하기 어렵습니다. 기본적으로 cron은 명령 출력과 오류를 사용자에게 이메일로 보내지만 대부분의 최신 시스템에는 로컬 이메일이 구성되어 있지 않으므로 이 출력이 사라집니다. 명시적 로깅이 이 문제를 해결합니다.

Stdout 및 stderr를 로그 파일로 리디렉션하세요: "0 2 * * * /path/to/script.sh > /var/log/myjob.log 2>&1". "> /var/log/myjob.log"는 표준 출력(stdout)을 파일로 리디렉션합니다. "2>&1"은 표준 오류(stderr)를 stdout이 가는 곳(로그 파일)으로 리디렉션합니다. 이제 작업이 실패하면 로그를 검사하여 무엇이 잘못되었는지 정확히 확인할 수 있습니다. 이 리디렉션이 없으면 오류가 조용히 사라집니다.

히스토리를 구축하려면 덮어쓰기 대신 추가하세요: "0 2 * * * /path/to/script.sh >> /var/log/myjob.log 2>&1". ">>"는 파일을 교체하는 대신 파일에 추가합니다. 각 실행은 로그에 추가되어 히스토리를 생성합니다. 로그 파일 증가를 주시하세요 - 로그 로테이션 또는 주기적인 정리를 구현하세요.

실행을 구별하려면 타임스탬프를 추가하세요: 스크립트에서 "date"를 사용하여 실행 시기를 출력하세요. 또는 항목에 자동으로 타임스탬프를 찍는 로깅 라이브러리를 사용하세요. 타임스탬프가 없으면 어떤 로그 항목이 어떤 실행에서 나온 것인지 구별하기 어렵습니다.

로그 로테이션은 무제한 증가를 방지합니다. Logrotate를 사용하여 이전 로그를 자동으로 아카이브, 압축 및 삭제하세요. /etc/logrotate.d/myjob를 구성하여 cron 작업 로그를 주간으로 또는 특정 크기에 도달하면 로테이션하세요.

중요한 작업의 경우 파일에 로깅하고 실패 시 경고하는 것을 모두 고려하세요. 로그에 출력을 캡처한 다음 종료 코드를 확인하세요: "0 2 * * * /path/to/script.sh >> /var/log/myjob.log 2>&1 || echo '작업 실패' | mail -s 'Cron 오류' [email protected]". "||"는 "또는"을 의미합니다 - 스크립트가 실패하면(0이 아닌 종료 코드) 이메일을 보냅니다.

정상 출력과 오류를 구별해야 하는 경우 stdout과 stderr를 분리하세요: "0 2 * * * /path/to/script.sh >> /var/log/myjob.out 2>> /var/log/myjob.err". 이제 정상 출력은 .out으로 가고 오류는 .err로 갑니다.

테스트를 위해 짧은 간격(2분마다)을 사용하고 로그를 자주 확인하세요: "*/2 * * * * /path/to/script.sh >> /tmp/test.log 2>&1". 작동하면 프로덕션 일정으로 변경하고 로그를 적절한 위치로 이동하세요.

리디렉션 없이 cron은 출력을 이메일로 보내려고 시도한다는 것을 기억하세요. 시스템이 로컬 메일을 생성하는 경우(/var/mail/사용자이름 확인) 거기에서 출력을 찾을 수 있습니다. 그러나 명시적 로깅이 로컬 메일에 의존하는 것보다 더 안정적입니다.

도구 사용해보기

Crontab Generator

Crontab Generator

관련 기사