조회수: 1
목차
크론에서는 돌지만 로그가 안 보이는 전형적인 상황
운영 중에 이런 경험을 한 번쯤 하게 된다
- 크론 잡이 예상한 시각에 동작해서 데이터도 처리되고 알림도 간다
- 그런데 지정한 로그 파일은 항상 비어 있거나 아예 생성되지 않는다
- 수동으로 같은 명령을 실행하면 로그가 잘 남는다
즉 작업 자체는 실행되지만 표준 출력과 에러 출력이 어디론가 사라진 상태다.
원인은 대부분 크론 환경과 사용자가 로그인한 쉘 환경의 차이에서 나온다.
이 문제를 풀려면
- 크론이 어떤 쉘과 환경으로 명령을 실행하는지
- 리다이렉션을 어떻게 해석하는지
- 파일 경로와 권한이 어떤 영향을 주는지
를 차근차근 확인해야 한다.
정말 실행됐는지부터 아주 단순하게 확인하기
먼저 해야 할 일은 크론이 해당 시각에 실제로 명령을 실행했는지 검증하는 것이다.
가장 간단한 방법은 다음과 같은 테스트 잡을 추가하는 것이다.
* * * * * echo "$(date) 크론 테스트" >> /tmp/cron_test.log 2>&1
이 잡을 넣고 몇 분 기다린 뒤
tail /tmp/cron_test.log
을 확인해 보자.
- 이 파일에는 줄줄이 로그가 쌓이는데 실제 잡 로그만 안 찍힌다면
→ 해당 잡의 리다이렉션이나 명령 작성에 문제가 있을 가능성이 크다 - 테스트 로그조차 생성되지 않는다면
→ 크론 데몬이 꺼져 있거나 crontab 편집이 잘못되었을 수 있다
이렇게 가장 단순한 케이스를 먼저 확인해야 나중에 복잡한 문제를 좁혀 가기 쉬워진다.
크론이 사용하는 쉘과 리다이렉션 문법 차이
많은 리눅스 배포판에서 crontab은 기본 쉘로 /bin/sh를 사용한다.
평소에 bash만 쓰던 사람이 bash 전용 문법을 crontab에 그대로 넣으면 조용히 실패하면서 로그가 안 남는다.
대표적인 예가 다음과 같은 리다이렉션이다
# bash에서는 종종 이렇게 쓴다
my_command &>> /var/log/myjob.log
이 표현은 bash 확장 문법이라 /bin/sh에서는 동작하지 않는다.
크론에서는 에러만 내고 끝나거나 아예 무시되는 경우가 많다.
크론 환경에서는 보다 호환성이 높은 형태로 쓰는 편이 안전하다
my_command >> /var/log/myjob.log 2>&1
두 가지를 기억해 두면 좋다
- 크론 잡에서 특별한 설정을 하지 않았다면 /bin/sh 기준 문법만 쓴다
- bash 전용 문법은 명시적으로 쉘을 지정했을 때만 사용한다
크론 줄을 다음처럼 바꾸는 방법도 있다
* * * * * /bin/bash -c 'my_command &>> /var/log/myjob.log'
이렇게 하면 bash를 강제로 사용한다. 다만 한 줄 안에 작은따옴표 큰따옴표가 섞이면서 가독성이 떨어질 수 있으니 복잡한 경우에는 아예 쉘 스크립트 파일을 만들고 그 파일을 크론에서 실행하도록 분리하는 편이 관리에 유리하다.
PATH 등 환경 변수 차이로 로그가 안 생기는 경우
크론에서는 로그인 쉘에서 보던 환경 변수가 거의 없다시피 하다.
대표적으로 PATH가 매우 짧다.
로그가 안 남는 대표적인 패턴
- crontab에는 단순히 my_command라고만 적어 두었다
- 로그인 쉘에서는 PATH에 해당 바이너리 경로가 있어서 잘 실행된다
- 크론에서는 my_command를 찾지 못해 바로 종료된다
- 리다이렉션은 뒤에 붙어 있지만 명령 자체가 실행되지 않아 로그가 비어 있다
이 문제를 막으려면 두 가지를 지키면 된다
첫째 명령과 스크립트에는 절대 경로를 사용한다
/usr/bin/python3 /home/user/project/script.py >> /var/log/myjob.log 2>&1
둘째 crontab 상단에 필요한 PATH를 명시적으로 정의한다
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
이 한 줄만 추가해도 많은 문제가 사라진다.
특히 파이썬 루비 노드 같은 런타임이 특이한 경로에 설치된 환경에서는 PATH 정리가 거의 필수다.
로그 파일 경로와 권한 문제
명령은 실행되는데 로그 파일이 생성되지 않는 또 다른 흔한 이유는 권한이다.
예를 들어
- 일반 사용자 crontab에서 /var/log 아래로 직접 로그를 쓰려고 한다
- 해당 계정은 /var/log에 쓸 권한이 없다
- 결과적으로 리다이렉션에서 권한 오류가 발생하고 로그 파일이 비어 있는 상태로 남는다
먼저 현재 로그 파일의 소유자와 권한을 확인해 보자
ls -l /var/log/myjob.log
크론을 실행하는 주체가
- 시스템 전체 crontab이나 root 계정 crontab인지
- 특정 사용자 crontab인지
에 따라 로그 경로 전략을 다르게 잡아야 한다.
일반 사용자라면
- 홈 디렉터리 아래 log 디렉터리를 만들고
- 그 안에 로그 파일을 쓰는 방식
이 안전하다.
mkdir -p /home/user/logs
# crontab에는 이렇게
* * * * * /path/to/my_command >> /home/user/logs/myjob.log 2>&1
root 크론 잡이라 해도 디렉터리 권한이 읽기 전용이면 로그가 안 생길 수 있다. 디스크 사용량이 가득 찬 경우에도 비슷한 증상이 나오므로 필요시 df 명령으로 남은 용량을 함께 확인하는 것이 좋다.
표준 출력과 에러 출력이 서로 다른 곳으로 가는 경우
명령이 실패해도 에러 메시지가 로그에 남지 않는 경우가 많다.
대부분 다음 패턴 때문이다
my_command > /var/log/myjob.log
이렇게만 쓰면 표준 출력만 로그 파일로 가고 에러 출력은 그대로 버려진다.
성공했을 때 남는 내용은 보이지만 실패 시 단서가 남지 않는 것이다.
보다 안정적인 패턴은 다음과 같다
my_command >> /var/log/myjob.log 2>&1
설명
- 로 기존 로그 뒤에 이어서 쓴다
- 2>&1 로 에러 출력까지 표준 출력과 동일한 파일로 보낸다
이 패턴을 습관처럼 쓰면 크론 잡이 실패해도 이유를 로그에서 바로 확인할 수 있다.
크론 자체 로그와 작업 로그는 별개라는 점 이해하기
지금까지 이야기한 로그는 작업에서 만드는 애플리케이션 로그다.
한편 리눅스에는 크론 데몬 자체의 동작을 기록하는 시스템 로그도 있다.
대표적인 파일 예
- var log cron
- var log syslog 안의 크론 관련 줄
여기에는
- 어떤 시각에 어떤 사용자 크론 잡이 시작됐는지
- 명령 줄 전체가 무엇이었는지
같은 정보가 남는다.
작업 로그가 안 보일 때 시스템 크론 로그를 함께 보면
- 해당 시간에 잡이 실제로 실행했는지
- 오타가 있는지
를 빠르게 확인할 수 있다.
반대로 시스템 로그가 비어 있다면 크론 데몬이 제대로 돌지 않는 것일 수 있으니 데몬 상태도 함께 확인해야 한다.
로그가 파일이 아니라 메일로 날아가고 있는 경우
크론은 기본적으로 작업의 출력 내용을 메일로 보낸다.
대부분 서버에서는 로컬 메일 전송 설정이 돼 있지 않거나 메일을 확인할 줄 모르는 경우가 많아
로그가 안 남는다
라고 느끼지만 실제로는 메일 큐에 쌓여 있는 상황이기도 하다.
크론 잡 상단에 다음과 같이 설정되어 있을 수 있다
MAILTO=user@example.com
이 경우 표준 출력과 에러 출력을 파일로 리다이렉션하지 않으면 전부 메일로 간다.
메일 대신 파일 로그를 쓰고 싶다면
- MAILTO를 비워 두거나
- 모든 출력에 대해 명시적으로 리다이렉션을 설정한다
메일을 쓰는 전략도 나쁘지 않지만, 운영자가 메일 알림과 파일 로그 중 어느 쪽을 기준으로 모니터링할지 명확하게 결정해야 한다.
스크립트 안에서 로그를 처리하는 방법
한 줄짜리가 아니라 별도 스크립트를 실행하는 구조라면
- 스크립트 안에서 로그 파일을 열고
- 전체 실행 과정을 하나의 파일로 남기도록 구성
하는 것도 좋은 방법이다.
예를 들어 bash 스크립트라면 스크립트 맨 위에
#!/bin/bash
exec >> /var/log/myjob.log 2>&1
echo "==== 실행 시작 $(date) ===="
처럼 두고, crontab에서는 단순히
* * * * * /path/to/script.sh
만 실행하도록 만들 수 있다.
이렇게 하면 스크립트 내부에서 실행하는 모든 명령의 출력이 한 곳에 모인다.
set 옵션을 추가해 디버깅에 활용하는 것도 가능하다.
set -o errexit
set -o pipefail
set -o nounset
이 패턴을 쓰면 예상치 못한 에러나 오타가 있을 때 조용히 죽지 않고 로그에 흔적을 남겨 준다.
크론 로그 문제를 정리하는 체크리스트
crontab에서 작업은 도는 것 같은데 로그가 안 남는 상황을 마주쳤을 때 다음 순서로 점검해 보자
- 간단한 테스트 잡으로 실제 실행 여부 확인
- 명령에 절대 경로를 썼는지 확인
- PATH 등 환경 변수를 crontab 상단에서 정의
- 리다이렉션 문법을 크론 쉘 기준으로 다시 작성
- 로그 파일 경로와 권한이 적절한지 확인
- stdout만이 아니라 stderr도 함께 로그로 보내는지 확인
- 시스템 크론 로그에서 실행 흔적 확인
- 메일로 출력이 빠져나가지 않았는지 MAILTO 확인
이 체크리스트를 한 번만 제대로 밟아 보면 이후에는 거의 자동으로 문제 원인이 눈에 들어올 것이다.
마무리 크론과 로그를 설계하는 관점 정리
crontab에서 실행은 되는데 로그가 안 남는 이유는 대부분
- 크론 환경과 인터랙티브 쉘 환경의 차이를 이해하지 못했거나
- 리다이렉션과 권한에 대한 기본 규칙을 놓쳤기 때문
이다.
로그는 장애 분석과 모니터링의 출발점이다.
처음부터 크론 잡을 작성할 때
- 어떤 파일에
- 어떤 형식으로
- 성공과 실패를 어떻게 구분해
로그를 남길지 함께 설계해 두면 나중에 문제를 찾는 시간이 크게 줄어든다.
조금만 습관을 바꾸면 크론이 조용히 실패하는 일 없이, 예측 가능한 자동화 환경을 만들 수 있다.