관리 메뉴

bright jazz music

크론탭(crontab, cron) 사용 관련 본문

OS 및 기타/리눅스

크론탭(crontab, cron) 사용 관련

bright jazz music 2024. 12. 20. 23:31

이전에  엔진엑스 로그를  정리하는 스크립트를  작성하고 크론탭을 사용하였다.  당시에는 바쁘다는 핑계로 정리하지 않았다. 이번에 DuckDNS를 사용해 동적 DNS 를 적용해보는 과정에서 정리의 필요를 느껴 여기에 적는다.

 

참고로 아래 링크는 DuckDNS 사용관련 포스팅이다.



동적DNS(DDNS) 적용하기 (with DuckDNS)

DuckDNS는 도메인과 공인 IP를 매핑하는 서비스이다.사설망에 존재하는 하나의 기기에서, 같은 망에 존재하는 다른 기기로 접근하기 위해 사용하는 방법이 아니다.왜냐하면 duckdns에 업데이트 되는

catnails.tistory.com

 

1. 크론

크론(Cron)은 리눅스 시스템에서 주기적인 작업을 자동화하기 위한 시간 기반 작업 스케줄러이다. 크론은 시스템 데몬(daemon)으로 동작하며 시스템이 부팅될 때 자동으로 시작되도록 설정돼 있다. 참고로 cron이라는 명칭은 그리스 신화의 시간의 신인 크로노스(Chronos)에서 따왔다. 

 

systemd를 사용하는 현대 리눅스 시스템에서는 cron.service로 관리되며, 아래 명령어로 크론의 상태를 확인할 수 있다.

#크론 서비스의 상태 확인
systemctl status cron

#아래 명령어들로 활/비활성화 할 수 있다.
#활성화
sudo systemctl enable cron
#비활성화
sudo systemctl disable cron

#좀 더 확실히 서비스의 부팅 시 구동여부를 확인하려면 is-를 사용할 수 있다.

systemctl is-enabled cron    # 부팅 시 자동 시작 설정 여부 확인
systemctl is-active cron     # 현재 실행 중인지 확인
systemctl is-failed cron     # 서비스 실패 상태인지 확인


#is-enabled를 가장 많이 사용할 텐데, 결과에 따라 의미가 다르다.
# enabled: 부팅 시 자동 시작
# disabled: 자동 시작 안 함
# masked: 완전히 비활성화 (시작 불가)


# enabled라고 돼 있더라도 실제 구동되고 있는 것은 아닐 수 있다. 아래의 명령어를 참고한다.
sudo systemctl start cron    # 서비스 시작
sudo systemctl stop cron     # 서비스 중지
sudo systemctl restart cron  # 서비스 재시작

 

2. 크론탭(crontab)이란

크론은 크론탭(crontab)에 크론 표현식과 명령어를 등록하여 실행시킬 수 있다. 크론탭은 크론 테이블(cron table)약자로, 크론 데몬이 수행할 작업들이 적혀있는 설정 파일 역할을 한다.

 

#시스템 상의 실제 위치:

#사용자별 크론탭:
/var/spool/cron/crontabs/사용자명

#시스템 크론탭:
/etc/crontab

 

개별 사용자들의 크론탭

일반 사용자인 coffee의 크론탭이 보인다.

 

시스템 크론탭의 위치

 

루트 계정으로 접근 가능 /etc

 열면 아래와 같다.

시스템 크론탭 파일의 내용. 아직 아무 것도 적혀있지 않다.

 

 

 

 

 

3. 크론탭의 종류

크론탭은 개별 사용자들이 사용하는 사용자 크론탭과 루트 계정이 사용하는 루트 사용자 크론탭과 시스템 전체가 사용하는 시스템 크론탭이 있다.

  • 사용자 크론탭
  • root 사용자 크론탭(사용자 크론탭의 일종)
  • 시스템 크론탭


3.1. 사용자 크론탭

시스템 전체가 아닌 특정 사용자의 작업을 주기화 시켜야 할 때 사용한다. 개별 사용자의 크론탭 파일은 "/var/spool/cron/crontabs/사용자명"에 저장되며, 해당 파일에 적힌 작업을 수행할 때는 사용자의 홈 디렉토리(~)를 기준으로 수행된다. 저장위치와 수행위치가 다르다는 사실을 헷갈리기 쉬우므로 주의해야 한다.

 

사용자 크론탭은 루트 계정이 필요하지 않는 작업에 한해서 사용한다. 사용자 크론탭에 적는 작업 명령어에 sudo를 붙여 루트 작업을 수행하는 것은 일반적으로 어렵다. 일반 사용자가루트 작업을 수행할 때는 시스템에서 루트 비밀번호를 입력을 요구하는데 크론탭을 통해서는 비밀번호를 입력할 수 없기 때문이다. 그렇다고 루트작업만이 가능한 sudoers 파일을 NOPASSWD로 설정하면 보안에 좋지 않다.

따라서 루트 작업이 필요한 경우에는 루트 사용자의 루트 사용자 크론탭을 사용하거나 시스템 크론탭을 사용해 작업을 수행하는 편이 낫다.

# 사용자 크론탭의 위치
/var/spool/cron/crontabs/사용자명

# 사용자 크론탭 편집 명령어
crontab -e

아래는 사용자 크론탭의 작업 명령어 작성 방식이다. 문법에 대해서는 5번 항목인 크론 표현식에서 설명한다.

 * * * * * command

3.2. 루트(root) 사용자 크론탭

사용자 크론탭의 일종이다. 그럼에도 따로 분류한 것은 시스템 크론탭과의 차이를 강조하기 위해서이다. 루트 사용자 크론탭은 루트 사용자만이 편집 가능하며, 루트 사용자의 크론 작업을 위해 존재한다. 후술하겠지만 시스템 크론탭처럼 여러 사용자를 명시하고 조합하여 작업할 수 없다. 일반 사용자 크론탭과 같은 작업 명령어 작성 방식을 따라야 한다는 의미이다. 

 * * * * * command
# 루트 사용자의 크론탭 위치
/var/spool/cron/crontabs/root

# 루트 사용자의 크론탭 편집 명령어
sudo crontab -e

 

 

3.3. 시스템 크론탭

시스템 크론탭은 시스템 전체에 영향을 미치는 크론탭이다. 루트 사용자만이 편집 가능하며 루트 권한이 필요한 작업, 시스템 전체의 관리 작업, 또는 여러 사용자의 조합이 필요한 작업해야 하는 경우에 사용한다. 

# 크론 탭의 위치
/etc/crontab

# 시스템 크론탭의 편집 명령어
sudo nano /etc/crontab 
#또는
sudo vi /etc/crontab

 

가장 큰 차이는 역시 작업 명령 작성 방식이다. 작업자(root, coffee 등)을 명시적으로 적어줘야 한다.

* * * * * username command

 

4. 크론탭 기본 명령어(사용자 크론탭 기준)

# 크론탭 편집
crontab -e

# 크론탭에 적혀있는 작업 목록 보기
crontab -l

# 크론탭 삭제(크론탭 파일 자체가 삭제된다. 적혀 있는 작업이 모두 삭제됨)
crontab -r

# 크론탭 삭제의 경우 복구가 불가능하다.(/var/spool/cron/crontabs/사용자명 파일이 삭제됨)
# 또한 삭제 여부를 확인하지 않고 즉시 수행되므로 주의해야 한다.

# 따라서 먼저 아래와 같이 백업하는 편이 좋다.
# crontab -l > backup.txt

#특정 작업만 삭제하려는 경우 crontab -e로 편집하는 것이 안전하다.

 

참고로 크론탭을 사용한 적 없는 사용자 계정으로 크론탭을 열면 크론탭을 생성하고 크론탭 편집기를 선택하라는 메시지가 보일 수 있다. 숫자를 눌러 편집기를 선택하면 크론탭이 열리게 된다. 예를 들면 아래와 같은 메시지

#크론탭을 편집하겠다는 명령어
coffee@coffee-rasp:~/duckdns$ crontab -e 

#coffee 계정이 사용할 크론탭이 아직 존재하지 않는다는 의미
no crontab for coffee - using an empty one

#에디터 선택(나는 시스템의 추천대로 나노 에디터를 선택했다)
Select an editor.  To change later, run 'select-editor'.
  1. /bin/nano        <---- easiest
  2. /usr/bin/vim.basic
  3. /usr/bin/vim.tiny
  4. /bin/ed

Choose 1-4 [1]:

 

그리고 작업을 아래와 같이 작업을 등록한다.

# duck.sh 스크립트 5분마다 업데이트
*/5 * * * * ~/duckdns/duck.sh >/dev/null 2>&1

# 참고로 스크립트를 실행하고, 그에 대한 표준출력과 표준 에러를 모두 버리라는 의미이다

 

파일을 저장하고 나오면 아래와 같은 메시지가 나타난다.

# 작업에 크론탭에 성공적으로 저장되었다는 의미. 
# 이것만으로 크론 데몬이 인식하므로 동기화나 재시작 같은 추가 작업이 필요 없다.
crontab: installing new crontab

 

 

5. 크론 표현식

 
크론 표현식은 5개의 필드로 구성된다.
* * * * * command
│ │ │ │ │
│ │ │ │ └─ 요일 (0-6) (0=일요일)
│ │ │ └─── 월 (1-12)
│ │ └───── 일 (1-31)
│ └─────── 시 (0-23)
└───────── 분 (0-59)

 

특수문자는 아래와 같은 의미를 가진다.

*: 모든 값
,: 값 나열 (예: 1,3,5)
-: 범위 지정 (예: 1-5)
/: 간격 지정 (예: */3)

 

 

 

6. 출력 리다이렉션

기본적으로 크론은 명령어의 출력을 메일로 전송하려 시도한다. 이 때의 메일은 이메일이 아니라 시스템의 로컬 메일 시스템을 의미한다. 주로 /var/mail/사용자명 이나 /var/spool/mail/사용자명 디렉토리에 있는 텍스트 파일 형태이다.

 

이 경우 메일 파일이 계속 커질 수 있고, 디스크 공간을 낭비하게 될 수도 있다. 또한 중요한 메시지를 놓치게 될 수도 있다.

따라서 보통 출력을 기본 설정에서 변경해 주는 것이다.

 

예를 들어 아래와 같이 작성하여 모든 출력 무시할 수 있다. 표준출력(stout)과 표준 에러가 모두 제거되는 것이다.

 

command >/dev/null 2>&1

#여기서 command는 사용자가 입력한 임의의 명령어이다.
# >/dev/null: 표준 출력을 버린다.
# 2>&1: 표준 에러를 표준 출력과 같은 곳으로 전송. 여기서는 표준출력이 버리므로 마찬가지로 버린다


# >는 표준 출력(stdout)을 리다이렉트
# /dev/null은 리눅스의 '블랙홀' 장치로, 여기로 보내진 모든 데이터는 사라짐
# 2는 표준 에러(stderr)를 의미
# >&1은 "stdout이 향하는 곳으로 보내라"는 의미
# 이 시점에서 stdout은 이미 /dev/null을 가리키고 있으므로, stderr도 /dev/null로 전송됨

# 최근에는 아래와 같은 간단한 표현도 사용됨
# command &>/dev/null

 

 

또다른 예시

#로그 파일로 저장
command >> /var/log/mycron.log 2>&1

#표준 출력만 저장하고 에러는 무시
command >> /var/log/mycron.log 2>/dev/null

# >>는 파일에 내용을 추가(append)하는 리다이렉션 연산자
# > 덮어쓰기
#   echo "hello" > file.txt  # file.txt의 내용을 지우고 "hello" 작성

# echo "hello" >> file.txt  # 기존 file.txt 내용 뒤에 "hello" 추가
# echo "world" >> file.txt  # 기존 내용 유지하고 그 뒤에 "world" 추가

# 로그파일 작성 시 자주 사용됨
# ./script.sh >> log.txt 2>&1  # 스크립트의 모든 출력을 log.txt에 추가

 

 

7. 환경변수 설정

크론은 제한된 환경에서 실행되므로 필요한 환경변수를 명시적으로 설정해야 할수도 있다.

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
SHELL=/bin/bash

* * * * * command

 

 

8. 실행 권한과 보안

# 스크립트 실행 권한 설정
chmod 700 script.sh  # 소유자만 실행 가능
chmod 755 script.sh  # 모든 사용자 실행 가능


# 실행 사용자 지정
sudo crontab -u username -e  # 특정 사용자의 크론탭 편집

 

 

9. 디버깅 팁

# 1. 스크립트 실행 가능 여부 테스트
chmod +x script.sh
./script.sh

# 2. 크론 로그 확인
grep CRON /var/log/syslog

# 3. 테스트를 위한 실행 결과 로깅
* * * * * /path/to/script.sh >> /tmp/crontest.log 2>&1

 

 

10. 주의 사항

 

#1. 절대 경로 사용
상대 경로 대신 절대 경로를 사용하여 스크립트와 파일을 지정

#2. 실행 권한 확인
스크립트 파일의 실행 권한이 올바르게 설정되어 있는지 확인

#3. 시스템 시간 확인
크론 작업이 예상 시간에 실행되지 않는 경우 시스템 시간대 설정 확인


#4. 중복 실행 방지
길게 실행되는 작업의 경우 중복 실행을 방지하는 로직 추가 고려

 

 

11. 구체적인  예시

 

매일 특정 시간에 실행

# 매일 자정(00:00)에 실행
0 0 * * * /path/to/script.sh

# 매일 새벽 3시에 실행 (서버 백업 등에 활용)
0 3 * * * /path/to/backup.sh

# 매일 오전 8시에 실행
0 8 * * * /path/to/morning-task.sh

# 매일 오후 2시 30분에 실행
30 14 * * * /path/to/afternoon-task.sh

# 매일 오후 11시 45분에 실행
45 23 * * * /path/to/night-task.sh

 

특정 간격으로 실행

# 매 시간 0분에 실행
0 * * * * /path/to/hourly-task.sh

# 매 시간 30분에 실행
30 * * * * /path/to/half-hourly-task.sh

# 5분마다 실행
*/5 * * * * /path/to/five-min-task.sh

# 2시간마다 실행 (짝수 시간 0분에)
0 */2 * * * /path/to/every-two-hours.sh

# 3일마다 자정에 실행
0 0 */3 * * /path/to/every-three-days.sh

 

요일 기준 실행

# 평일(월-금) 오전 9시에 실행
0 9 * * 1-5 /path/to/weekday-task.sh

# 주말(토,일) 오전 11시에 실행
0 11 * * 6,0 /path/to/weekend-task.sh

# 매주 월요일 오전 9시에 실행
0 9 * * 1 /path/to/monday-task.sh

# 매주 일요일 자정에 실행
0 0 * * 0 /path/to/sunday-task.sh

# 매주 금요일 오후 6시에 실행
0 18 * * 5 /path/to/friday-task.sh

 

복합적인 시간 설정

# 평일 오전 9시부터 오후 6시까지 매시간 실행
0 9-18 * * 1-5 /path/to/business-hours.sh

# 매일 오전 9시와 오후 6시에 실행
0 9,18 * * * /path/to/twice-daily.sh

# 평일 오전 9시부터 오후 6시까지 30분마다 실행
*/30 9-18 * * 1-5 /path/to/business-hours-frequent.sh

# 매일 오전 8시부터 오후 8시까지 15분마다 실행
*/15 8-20 * * * /path/to/daytime-monitor.sh

 

월 기준 실행

# 매월 1일 자정에 실행
0 0 1 * * /path/to/monthly-task.sh

# 매월 15일과 말일 자정에 실행
0 0 15,28-31 * * /path/to/mid-month-task.sh

# 매월 첫 번째 월요일 오전 9시에 실행
0 9 1-7 * 1 /path/to/first-monday.sh

# 매월 마지막 금요일 오후 6시에 실행
0 18 24-31 * 5 /path/to/last-friday.sh

 

 

출력 리다이렉션이 포함된 구체적인 예시

# 로그를 남기지 않는 경우
0 0 * * * /path/to/script.sh >/dev/null 2>&1

# 로그 파일에 기록하는 경우
0 0 * * * /path/to/script.sh >> /var/log/script.log 2>&1

# 에러만 로그 파일에 기록하는 경우
0 0 * * * /path/to/script.sh >/dev/null 2>> /var/log/script.error.log

# 실행 시간을 포함하여 로그 남기기
0 0 * * * /path/to/script.sh 2>&1 | ts '[%Y-%m-%d %H:%M:%S]' >> /var/log/script.log

 

환경변수를 포함한 예시

# PATH 환경변수 설정 후 실행
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
0 0 * * * /path/to/script.sh

# 여러 환경변수를 포함한 실행
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
LANG=en_US.UTF-8
0 0 * * * /path/to/script.sh

 

 

운영과 관련된 예시(실행시간 조정이 필요한 작업)

# 서버 백업 (매일 새벽 3시 15분)
15 3 * * * /path/to/backup.sh >/dev/null 2>&1

# 로그 로테이션 (매일 자정)
0 0 * * * /usr/sbin/logrotate /etc/logrotate.conf >/dev/null 2>&1

# 임시 파일 정리 (매주 일요일 새벽 2시)
0 2 * * 0 /usr/bin/find /tmp -type f -atime +7 -delete >/dev/null 2>&1

# 데이터베이스 최적화 (매주 토요일 새벽 4시)
0 4 * * 6 /path/to/db-optimize.sh >> /var/log/db-optimize.log 2>&1

# 시스템 상태 모니터링 (5분마다)
*/5 * * * * /path/to/monitor.sh | ts '[%Y-%m-%d %H:%M:%S]' >> /var/log/monitor.log 2>&1
Comments