Crontab에 Python 스크립트를 등록했는데 수동 실행은 되지만 예약 실행은 실패한다면, 십중팔구 환경변수(PATH) 문제입니다. Cron은 로그인 셸이 아니기 때문에 .bashrc나 .bash_profile에 설정한 PYTHONPATH, ORACLE_HOME, LD_LIBRARY_PATH 등을 읽지 못하며, 이로 인해 ModuleNotFoundError나 DISPLAY 미설정 오류가 발생합니다. 이 글에서는 실전에서 마주친 사례를 바탕으로 원인 진단부터 로그 기반 디버깅, 그리고 완벽한 해결 방법까지 정리합니다.
| Crontab파이썬스크립트실행안될때환경변수PATH문제해결완벽정리 |
1. Crontab 파이썬 실행 실패의 3가지 주요 원인
Cron 환경에서 Python 스크립트가 동작하지 않는 이유는 크게 세 가지로 압축됩니다.
- 환경변수 미적용: Crontab은 최소한의 환경변수(PATH=/usr/bin:/bin 수준)만 로드하므로, 가상환경 경로나 라이브러리 경로를 인식하지 못합니다.
- 상대경로 사용: 스크립트 내부에서
./config.json같은 상대경로를 사용하면 Cron의 작업 디렉토리(보통/root또는/home/user)에서 파일을 찾지 못해 실패합니다. - GUI 의존성: Selenium, PyAutoGUI 등 GUI 라이브러리는
DISPLAY환경변수가 필요한데, Cron 환경에는 X11 디스플레이가 없어 오류가 발생합니다.
추가로 실행권한 부재(스크립트나 쉘에 chmod +x 미적용), 로그 디렉토리 권한 오류(로그 경로에 쓰기 권한 없음), 계정 패스워드 만료(PAM 인증 실패)도 빈번한 원인입니다.
2. 해결 방법: 환경변수 래퍼 쉘 스크립트 작성
가장 확실한 해결책은 환경변수를 export하는 쉘 스크립트를 만들어 Crontab에서 호출하는 방식입니다. 아래는 실전 예시입니다.
Step 1: 환경변수 설정 쉘 스크립트 작성 (path_set.sh)
#!/bin/bash # /home/user/scripts/path_set.sh export PYTHONPATH=/home/user/myproject export ORACLE_HOME=/opt/oracle/instantclient_19_8 export LD_LIBRARY_PATH=$ORACLE_HOME:$LD_LIBRARY_PATH export PATH=/usr/local/bin:/usr/bin:/bin # 작업 디렉토리 이동 (상대경로 문제 해결) cd /home/user/myproject # Python 스크립트 실행 (절대경로 사용) /usr/bin/python3 /home/user/myproject/crawler.py
Step 2: 실행권한 부여
chmod +x /home/user/scripts/path_set.sh
Step 3: Crontab 등록 (로그 리다이렉션 포함)
crontab -e
아래와 같이 등록합니다. 2>&1는 표준 에러(stderr)를 표준 출력(stdout)으로 리다이렉션하여 로그 파일에 함께 기록하는 옵션입니다.
# 평일 오전 10시에 실행, 로그는 /data/log/cron.log에 누적 0 10 * * 1-5 /bin/bash /home/user/scripts/path_set.sh >> /data/log/cron.log 2>&1
꿀팁: 로그 디렉토리(/data/log)가 존재하는지, 해당 경로에 쓰기 권한이 있는지 반드시 확인하십시오. mkdir -p /data/log && chmod 755 /data/log로 생성 및 권한 부여를 권장합니다.
3. Selenium 등 GUI 라이브러리 사용 시 추가 설정
Selenium이나 PyAutoGUI처럼 그래픽 환경이 필요한 라이브러리는 가상 디스플레이(Xvfb)를 사용해야 합니다.
가상 디스플레이 설치 및 적용
# Ubuntu/Debian 기준 sudo apt-get update sudo apt-get install xvfb # Python 패키지 설치 pip3 install pyvirtualdisplay
Python 스크립트 상단에 아래 코드를 추가합니다.
from pyvirtualdisplay import Display display = Display(visible=0, size=(1920, 1080)) display.start() # 이후 Selenium 등 GUI 코드 작성
또는 쉘 스크립트에서 DISPLAY 환경변수를 직접 지정할 수도 있습니다.
export DISPLAY=:99 Xvfb :99 -screen 0 1920x1080x24 & /usr/bin/python3 /home/user/myproject/crawler.py
주의: Xvfb 프로세스가 좀비 프로세스로 남지 않도록, 스크립트 종료 시 killall Xvfb나 display.stop()을 호출하는 것을 권장합니다.
4. 로그 기반 디버깅: syslog와 cron 상태 확인
Cron 실행 여부를 확인하려면 시스템 로그를 반드시 점검해야 합니다.
로그 위치
- Ubuntu/Debian:
/var/log/syslog - CentOS/RHEL:
/var/log/cron
Cron 실행 기록 확인
grep CRON /var/log/syslog | tail -20
정상적으로 실행되었다면 아래와 같은 로그가 남습니다.
Jan 15 10:00:01 server CRON[12345]: (user) CMD (/bin/bash /home/user/scripts/path_set.sh >> /data/log/cron.log 2>&1)
PAM 인증 오류 (패스워드 만료)
만약 아래와 같은 메시지가 보인다면, Cron 실행 계정의 패스워드가 만료된 상태입니다.
crond: (root) FAILED to authorize user with PAM (Authentication token is no longer valid; new one required)
해결 방법은 간단합니다.
# 패스워드 만료 여부 확인 chage -l root # 패스워드 갱신 passwd root # crond 재시작 systemctl restart cron # Ubuntu/Debian systemctl restart crond # CentOS/RHEL
Cron 데몬 상태 확인
systemctl status cron # Ubuntu/Debian systemctl status crond # CentOS/RHEL
데몬이 중지되어 있다면 systemctl start cron으로 재시작하십시오.
5. 자주 쓰는 Crontab 명령어 및 디버깅 체크리스트
Crontab 기본 명령어
crontab -e: 현재 사용자의 Crontab 편집crontab -l: 등록된 Cron 작업 목록 확인crontab -r: 모든 Cron 작업 삭제 (주의!)crontab -u username -e: 특정 사용자의 Crontab 편집 (root 권한 필요)
디버깅 체크리스트
- 절대경로 사용 여부: Python 인터프리터, 스크립트 경로, 로그 경로 모두 절대경로로 작성했는가?
- 환경변수 설정: 쉘 스크립트에 필요한 환경변수를 export했는가?
- 작업 디렉토리 명시:
cd /path/to/project로 작업 디렉토리를 이동했는가? - 실행권한: 쉘 스크립트와 Python 스크립트에 실행권한(
chmod +x)이 있는가? - 로그 디렉토리 권한: 로그 파일을 쓸 디렉토리에 쓰기 권한이 있는가?
- 로그 리다이렉션:
>> /path/to/log 2>&1로 표준 출력과 에러를 모두 기록하고 있는가? - Cron 데몬 상태:
systemctl status cron으로 데몬이 실행 중인지 확인했는가? - 계정 패스워드:
chage -l로 패스워드 만료 여부를 확인했는가?
정리
Crontab에서 Python 스크립트가 실행되지 않는 문제는 대부분 환경변수 미적용과 상대경로 사용에서 비롯됩니다. 환경변수를 export하는 쉘 래퍼 스크립트를 만들어 절대경로로 호출하고, 로그 리다이렉션(2>&1)으로 에러를 기록하며, grep CRON /var/log/syslog로 실행 여부를 확인하는 습관을 들이면 대부분의 문제를 예방할 수 있습니다. GUI 라이브러리를 사용한다면 Xvfb 가상 디스플레이를 반드시 설정하고, 패스워드 만료 여부도 정기적으로 점검하십시오.
Action Item: 지금 당장 crontab -l로 등록된 작업을 확인하고, 로그 리다이렉션이 없다면 >> /path/to/log 2>&1을 추가하십시오. 로그 없이는 디버깅이 불가능합니다.
# 함께 보면 좋은 글
댓글
댓글 쓰기