at 명령어로 ‘나중에 실행되는 작업’ 예약하는 방법 (cron과 차이)

Views: 0

서버에서 “나중에 한 번만 실행할 일”을 예약할 때 가장 간편한 도구가 at다. cron은 반복 스케줄에 강하지만 단발성 작업엔 번거롭다. at은 인간 친화적인 시간 표기로 바로 예약하고, 표준 출력은 메일로 알려주거나 파일로 남길 수 있다. 다만 atd 데몬이 켜져 있어야 하고, 환경 변수/경로 처리에 주의해야 한다. 이 글은 at의 설치·활성화부터 예약, 확인·취소, 환경과 로그 설계, 접근 제어, cron/systemd와의 선택 기준까지 운영자가 바로 적용할 수 있도록 정리한다.

at를 쓰기 전 준비: 데몬 활성화와 설치

대부분 배포판은 별도 데몬 atd가 예약을 실제로 실행한다. 동작하지 않으면 예약만 되고 실행은 되지 않는다.

# 설치
# Debian/Ubuntu
sudo apt-get update && sudo apt-get install -y at
# RHEL/CentOS/Alma/Rocky
sudo yum install -y at

# 데몬 기동 및 자동 시작
sudo systemctl enable --now atd
sudo systemctl status atd

컨테이너·경량 환경은 atd가 비활성인 경우가 많으니 반드시 상태를 점검한다.

at의 핵심: 자연어에 가까운 시간 표기

at은 다양한 시간 형식을 이해한다. 아래 예시는 대부분 배포판에서 공통적으로 동작한다.

# 10분 후
echo "bash backup.sh" | at now + 10 minutes

# 오늘 밤 23시
echo "bash backup.sh" | at 23:00

# 내일 오전 9시
echo "bash backup.sh" | at 9am tomorrow

# 특정 날짜와 시각(YYYY-MM-DD HH:MM)
echo "bash backup.sh" | at 2025-11-05 14:30

# 특수키워드
echo "bash report.sh" | at noon
echo "bash report.sh" | at midnight
echo "bash tea.sh" | at teatime   # 16:00로 해석되는 배포판 많음

명령을 여러 줄로 예약하고 싶다면 here-doc이 깔끔하다.

at 02:10 tomorrow <<'EOF'
source ~/.bashrc
cd /srv/app
./rotate.sh >> /var/log/rotate.$(date +\%F).log 2>&1
EOF

예약 작업의 표준 입출력과 메일 처리

at은 작업이 생성하는 표준 출력/오류를 메일로 보낸다(시스템에 MTA가 설정되어 있어야 함). 메일 인프라가 없거나 파일로 남기고 싶다면 명령 자체에 리다이렉션을 포함한다.

# 로그 파일로 모으기
echo "python etl.py >> /var/log/etl.$(date +\%F).log 2>&1" | at 03:30

# 메일을 항상 보내고 싶다면(배포판 옵션)
echo "bash job.sh" | at -m 04:00

운영 환경에선 메일보다 파일 로그가 일관적이다. 회전 정책(logrotate)도 함께 준비한다.

환경 변수와 작업 디렉터리: “셸에서 되는데 at에선 실패”를 막는 법

at은 인터랙티브 셸과 동일한 환경을 보장하지 않는다. PATH, LANG, 가상환경 등이 달라 실패하기 쉽다. 다음 수칙을 습관화하자.

  1. 절대경로 사용
/usr/bin/python3 /srv/app/jobs/cleanup.py
  1. 필요한 환경을 명시적으로 로드
source ~/.profile  # 또는 프로젝트의 env 스크립트
export PYTHONPATH=/srv/app
  1. 작업 디렉터리를 명시
cd /srv/app && ./job.sh
  1. 예약된 스크립트를 점검
# 예약 내용 확인
at -c <job_id>

at -c는 실행될 실제 스크립트를 보여준다. 여기서 PATH/환경이 기대와 다른지 즉시 확인할 수 있다.

예약·조회·취소: 일상 운영 명령

# 예약(표준입력으로 명령 입력, Ctrl+D로 종료)
at 01:00

# 큐 조회(동일: at -l)
atq

# 특정 작업 상세 스크립트 조회
at -c 12

# 취소
atrm 12

# 특정 큐를 보려면(고급) -q
at -q b -l

여러 작업을 한꺼번에 지울 땐 job id를 공백으로 나열하면 된다.

atrm 12 13 14

batch: 시스템 부하가 낮을 때 실행

batch는 즉시 실행하지 않고 시스템 load average가 낮아질 때 작업을 수행한다. 비급하고 무거운 작업에 적합하다.

# 현재 부하가 낮아지면 실행
echo "nice -n 10 ./heavy_task.sh >> /var/log/heavy.log 2>&1" | batch

큐를 분리해 우선순위를 조절할 수도 있다(at -q a 등). 일반적으로 알파벳 큐는 우선순위를 반영한다.

보안과 접근 제어: at.allow / at.deny

관리자가 특정 사용자만 at을 쓰게 하려면 다음 파일로 제어한다.

/etc/at.allow  # 여기에 나열된 사용자만 허용
/etc/at.deny   # 여기 나열된 사용자만 차단(allow가 없을 때 사용)

이 파일이 없으면 배포판 정책에 따라 root만 사용 가능하거나 모든 사용자 허용으로 동작할 수 있다. 멀티테넌트 서버에서는 반드시 정책을 명확히 하자.

타임존과 시계동기

예약은 시스템 시계를 기준으로 해석된다. 컨테이너·클라우드 환경에서 타임존이 기대와 다르거나 NTP가 불안정하면 실행 시점이 어긋난다.

  • OS 타임존: timedatectl set-timezone Asia/Seoul
  • NTP 동기: timedatectl timesync-status 또는 chronyc sources
  • Docker 컨테이너: 호스트의 /etc/localtime 마운트 여부 확인

오류를 줄이는 패턴: 실행 전 체크리스트

  • 절대경로로 명령 작성
  • 작업 시작 전 cdsource 명시
  • 리다이렉션으로 로그 파일 고정
  • 필요한 권한과 소유자 확인(예약한 사용자 권한으로 실행)
  • 실행 전 at -c <job_id>로 최종 스크립트 점검
  • atd 상태 확인 및 재부팅 후 자동 시작 설정

cron과 at, 무엇을 언제 쓰나

  • 단발성(한 번만 실행): at
    예) 오늘 23시에 캐시 비우기, 10분 뒤에 점검 스크립트 실행
  • 반복성(일/주/월 반복): cron
    예) 매일 3시 백업, 매주 일요일 리포트
  • 부하 기반 단발성: batch
    예) CI 산출물 압축처럼 무거운 작업을 시스템이 한가할 때 자동 실행
  • 복잡한 의존성/재시작/리소스 한도 관리: systemd timer
    예) 서비스처럼 관리하고, 실패 시 재시작·자원 제한·로그를 일원화하고 싶을 때

전환 기준 요약

  • 일회성이고 “지금부터 +N분/특정일시”라면 at이 가장 빠르다.
  • 반복 일정이 생기는 순간 cron으로 승격하라.
  • 운영 가시성·리소스 제어가 필요하면 systemd timer로 승격하라.

systemd와의 궁합: ad-hoc이면 at, 서비스화면 systemd-run

systemd-run은 ad-hoc 작업을 유닛처럼 실행·추적한다. 특정 시점 예약엔 --on-active(상대)나 --on-calendar(캘린더)가 있다. at를 대체해도 무방하다.

# 10분 후 한 번 실행
systemd-run --unit=adhoc-job --on-active=10m /srv/app/job.sh

# 특정 시각(캘린더 표현식)
systemd-run --unit=report --on-calendar="2025-11-05 14:30" /srv/report.sh

# 실행 상태와 로그
systemctl status adhoc-job
journalctl -u adhoc-job

메일 인프라가 없는 환경이라면 systemd 저널이 운영상 더 편리하다.

실전 예제: 백업, 점검, 임시 패치

로그 백업 한 번만 실행

cat <<'EOF' | at 01:30
source /etc/profile
cd /srv/app && /usr/bin/env bash backup.sh >> /var/log/backup.$(date +\%F).log 2>&1
EOF

15분 뒤 장애 지표 스냅샷

echo "sh /usr/local/bin/capture_metrics.sh >> /var/log/metrics.$(date +\%F_%H%M).log 2>&1" \
| at now + 15 minutes

임시 패치 배포

at 22:00 <<'EOF'
cd /srv/app
git pull --rebase
systemctl restart myapp
EOF

트러블슈팅

  • 예약이 실행되지 않음: systemctl status atd에서 데몬 상태/권한 확인
  • “Cannot open your terminal”: 예약 내용에 터미널 의존 명령이 포함됨 → 비대화형 명령만 사용
  • PATH 문제로 “command not found”: 절대경로로 호출하거나 source로 환경 로드
  • 메일이 오지 않음: MTA가 없거나 /etc/aliases 미설정 → 파일 로그로 전환
  • 동일 작업이 중복 실행: 중복 예약 확인(atq) 후 즉시 atrm

운영 팁

  • 큐 분리로 중요도 조절: at -q a(우선순위 높은 큐)와 -q z(낮은 큐)를 나눠 사용
  • 무거운 작업은 niceionice를 덧붙여 시스템 영향 최소화
echo "ionice -c3 nice -n 15 ./heavy.sh >> /var/log/heavy.log 2>&1" | at 03:00
  • 감사 로그: 예약 직후 atq 결과를 작업 관리 시스템에 기록해 누가 무엇을 언제 예약했는지 남긴다.

마무리

at은 단발성 스케줄의 최단거리 해법이다. 자연어에 가까운 시간 표기, 간단한 입력 방식, 메일·파일 로그 처리만 익히면 “지금부터 +N분 후”나 “특정 일시에 한 번” 같은 요구를 몇 초 만에 자동화할 수 있다. 반복 일정은 cron, 서비스형 관리는 systemd timer로 승격하는 기준을 갖추고, 절대경로·환경 로드·로그 고정의 3원칙을 지키면 예약 실패와 운영 잡음이 눈에 띄게 줄어든다.