서비스 · 프로세스 관리 36 / 50 · Part 4. 로그·스케줄링·운영
실습 환경: Rocky Linux 9.8 · Ubuntu 24.04.5 (systemd로 부팅한 Docker 격리 컨테이너, 테스트 계정 analyst)

1. 들어가며

"오늘 밤 11시에 한 번만 서비스를 재시작해 주세요." 이런 일회성 작업에 cron을 쓰면 실행 후 등록을 지우는 것을 잊기 쉽다. 이럴 때 쓰는 도구가 at 이다. at은 지정한 시각에 딱 한 번 명령을 실행하고 스스로 정리된다.

이번 글에서는 at 작업을 예약·확인·삭제하는 방법과, at이 예약 당시의 환경을 스크립트로 저장 하는 구조를 확인한다. 그리고 부하가 낮을 때 실행하는 batch, 스풀 위치와 접근 제어, 예약 작업 점검에서 at을 빠뜨리지 않는 방법을 정리한다.


2. 핵심 개념

2-1. at 관련 명령

명령동작
at TIME표준입력의 명령을 TIME에 실행하도록 예약
at -f script TIME파일 내용을 예약
batch시스템 부하가 낮아지면 실행
atq (at -l)대기 작업 목록 (root는 전체 사용자)
at -c N작업 N의 전체 스크립트 출력
atrm N작업 삭제

2-2. 시각 표현

표현의미
now + 5 minutes / + 2 hours / + 1 day상대 시각
23:50오늘 23:50 (이미 지났으면 내일)
02:00 tomorrow, noon, midnight이름 있는 시각
10:00 2026-10-01날짜 지정

2-3. 일회성 예약 도구 비교

항목atcronsystemd-run --on-active (35편)
실행 횟수1회반복1회
실행 환경예약 당시 환경 저장최소 환경서비스 환경
실행 후스풀 파일 삭제등록 유지임시 unit 삭제
결과 기록atd 시작 로그 (출력은 메일)CMD 로그journal에 출력까지

3. 동작 원리

at 작업의 일생 — 예약 시점의 환경이 통째로 저장된다

echo '명령' | at now + 1 minute
  → at: 현재 셸의 환경변수 · 작업 디렉터리 · umask 를 읽어 /bin/sh 스크립트 생성
  → 스풀 디렉터리에 작업 파일 저장 (소유자 = 예약한 사용자, 권한 700)
  → atd: 시각이 되면 해당 사용자로 스크립트 실행 → 완료 후 파일 삭제

cron이 최소 환경(33편)으로 실행되는 것과 달리, at은 예약한 셸의 환경을 재현 한다. 그래서 대화형 셸에서 되던 명령이 at에서도 대부분 그대로 동작한다. 반대로 말하면 예약 당시의 환경변수(PATH 등)가 스풀 파일에 그대로 남는다.


4. 명령어 실습

# 1) (Rocky, analyst) 예약 · 목록 · 내용 확인 · 실행 · 삭제
echo 'id -un > ~/at-result.txt; date +%T >> ~/at-result.txt' | at now + 1 minute
echo 'echo second job' | at 23:50
atq
at -c $(atq | sort -n | head -1 | cut -f1) | tail -5
at -c $(atq | sort -n | head -1 | cut -f1) | grep -cE '^[A-Z_]+=.*; export'   # 저장된 환경변수 수
sleep $((63 - $(date +%S))); cat ~/at-result.txt; atq
atrm $(atq | cut -f1); atq | wc -l

# 2) (Rocky, root) 스풀 파일과 접근 제어, 실행 로그
echo 'sleep 1' | su - analyst -c 'at now + 2 hours'
ls -l /var/spool/at/ | head -4
ls -l /etc/at.allow /etc/at.deny
journalctl -u atd --since "-5min" --no-pager -o cat | tail -3
atq; atrm $(atq | cut -f1)

# 3) (Ubuntu) batch 와 스풀 위치
echo 'uptime > /tmp/batch.txt' | batch; sleep 3; cat /tmp/batch.txt
ls -la /var/spool/cron/atjobs/ | head -4

5. 실행 결과

실제 실행 결과 — Rocky Linux 9.8 · analyst@rocky9-lab — at 으로 작업 예약하고 실행 확인

실제 실행 결과 — Rocky Linux 9.8 · root@rocky9-lab — at 스풀과 접근 제어

실제 실행 결과 — Ubuntu 24.04.5 · root@ubuntu-lab — batch 와 Ubuntu 의 at 스풀

텍스트 원본(실제 출력):

[analyst@rocky9-lab ~]$ echo 'id -un > ~/at-result.txt; date +%T >> ~/at-result.txt' | at now + 1 minute 2>&1
warning: commands will be executed using /bin/sh
job 1 at Thu Sep 24 12:32:00 2026
[analyst@rocky9-lab ~]$ echo 'echo second job' | at 23:50 2>&1
warning: commands will be executed using /bin/sh
job 2 at Thu Sep 24 23:50:00 2026
[analyst@rocky9-lab ~]$ atq
1	Thu Sep 24 12:32:00 2026 a analyst
2	Thu Sep 24 23:50:00 2026 a analyst
[analyst@rocky9-lab ~]$ at -c $(atq | sort -n | head -1 | cut -f1) | tail -5
}
${SHELL:-/bin/sh} << 'marcinDELIMITER19cf8baa'
id -un > ~/at-result.txt; date +%T >> ~/at-result.txt

marcinDELIMITER19cf8baa
[analyst@rocky9-lab ~]$ at -c $(atq | sort -n | head -1 | cut -f1) | grep -cE '^[A-Z_]+=.*; export'
25
[analyst@rocky9-lab ~]$ sleep $((63 - $(date +%S))); cat ~/at-result.txt; atq
analyst
12:32:00
2	Thu Sep 24 23:50:00 2026 a analyst
[analyst@rocky9-lab ~]$ atrm $(atq | cut -f1); atq | wc -l
0
[root@rocky9-lab ~]# echo 'sleep 1' | su - analyst -c 'at now + 2 hours' 2>&1
warning: commands will be executed using /bin/sh
job 3 at Thu Sep 24 14:32:00 2026
[root@rocky9-lab ~]# ls -l /var/spool/at/ | head -4
total 8
-rwx------ 1 analyst analyst  856 Sep 24 12:32 a0000301c74968
drwx------ 1 root    root    4096 Sep 24 12:32 spool
[root@rocky9-lab ~]# ls -l /etc/at.allow /etc/at.deny 2>&1; cat /etc/at.deny | head -3
ls: cannot access '/etc/at.allow': No such file or directory
-rw-r--r-- 1 root root 1 Nov 11  2025 /etc/at.deny

[root@rocky9-lab ~]# journalctl -u atd --since "-5min" --no-pager -o cat | tail -3
Starting job 1 (a0000101c748f0) for user 'analyst' (1000)
pam_unix(atd:session): session opened for user analyst(uid=1000) by analyst(uid=0)
pam_unix(atd:session): session closed for user analyst
[root@rocky9-lab ~]# atq; atrm $(atq | cut -f1)
3	Thu Sep 24 14:32:00 2026 a analyst
root@ubuntu-lab:~# echo 'uptime > /tmp/batch.txt' | batch 2>&1; sleep 3; cat /tmp/batch.txt
warning: commands will be executed using /bin/sh
job 1 at Thu Sep 24 12:32:00 2026
 12:32:04 up 44 min,  1 user,  load average: 0.00, 0.01, 0.02
root@ubuntu-lab:~# ls -la /var/spool/cron/atjobs/ | head -4
total 20
drwxrwx--T 1 daemon daemon 4096 Sep 24 12:32 .
drwxr-xr-x 1 root   root   4096 Sep 24 09:32 ..
-rw------- 1 daemon daemon    6 Sep 24 12:32 .SEQ

6. 결과 해석

관찰의미
warning: commands will be executed using /bin/shat 작업은 로그인 셸이 아니라 /bin/sh로 실행된다
job 1 at Thu Sep 24 12:32:00 2026now + 1 minute은 다음 분의 0초 로 맞춰진다
atq: 작업 번호 · 실행 시각 · 큐(a) · 사용자대기 작업 목록. root로 보면 모든 사용자의 작업이 보인다
at -c 끝부분: heredoc 안에 원래 명령at이 만든 스크립트의 마지막에 예약한 명령이 들어 있다
저장된 환경변수 25개예약 당시 셸의 환경변수가 export 형태로 스풀 파일에 저장되었다
결과 analyst, 12:32:00 후 atq에서 사라짐예약한 사용자 권한으로 정시에 실행되고 대기 목록에서 제거되었다
스풀 파일 a0000301c74968 (analyst 소유, -rwx------)작업 파일은 예약한 사용자 소유, 본인만 접근 가능하다
at.allow 없음, at.deny 존재allow가 없으므로 deny에 없는 모든 사용자가 at을 쓸 수 있다
atd 로그 Starting job 1 (...) for user 'analyst' (1000)실행 시작 기록. 명령 내용은 남지 않는다
Ubuntu batch → 즉시 uptime 결과부하가 낮아 바로 실행되었다
Ubuntu 스풀 /var/spool/cron/atjobs/, .SEQ배포판마다 스풀 위치가 다르다. .SEQ는 다음 작업 번호

7. 보안 관점

주제내용
점검 누락예약 작업 점검을 crontab만으로 끝내면 at 작업을 놓친다. 39편의 자동 실행 경로 점검에 atq를 포함한다
사용 제한at이 필요 없는 서버는 atd를 비활성화하거나 /etc/at.allow로 허용 계정만 지정한다
환경 노출스풀 파일에 예약 당시 환경변수가 저장된다. 환경변수에 토큰·비밀번호를 두는 습관은 여기서도 노출 위험이 된다
기록의 한계atd 로그에는 "누가 언제 실행했는가"만 남는다. 실행 내용은 스풀 파일이 삭제되기 전에 at -c로 확보해야 한다

8. 보안관제 관점

[정기 점검]  atq                                        ← 대기 작업 (root 로 실행)
             ls -la /var/spool/at/  (Ubuntu: /var/spool/cron/atjobs/)
             systemctl is-enabled atd ; ls -l /etc/at.allow /etc/at.deny
     ↓
[작업 확인]  at -c <번호> | tail -20                     ← 실제 실행될 명령
     ↓
[판단]       변경 관리(작업 요청) 기록에 없는 예약 · 서비스 계정의 예약 → 담당자 확인
     ↓
[기록]       실행 이력: journalctl -u atd --since ... -o short-iso
점검 항목기준
atd 필요 여부사용하지 않으면 systemctl disable --now atd
허용 계정/etc/at.allow에 운영 계정만
대기 작업모든 작업에 요청자·목적이 설명되는가

9. 실무에서 자주 발생하는 실수

실수결과예방
명령의 출력을 리다이렉션하지 않음결과를 볼 수 없음 (메일로 감)> 파일 2>&1
now + 1 minute을 정확히 60초 후로 생각다음 분 0초에 실행필요한 시각을 명시
예약자와 다른 계정으로 atq 확인작업이 안 보임root로 확인
atd가 꺼진 서버에 예약실행되지 않음systemctl is-active atd 확인
반복 작업을 at으로 재예약관리가 흩어짐반복은 cron·timer

10. 실습 체크리스트

[ ] at now + 1 minute 로 작업을 예약하고 실행을 확인했다
[ ] atq, at -c, atrm 으로 작업을 관리했다
[ ] at 스풀 파일에 환경변수가 저장되는 것을 확인했다
[ ] 스풀 파일 위치와 권한을 Rocky/Ubuntu 에서 확인했다
[ ] at.allow / at.deny 규칙을 설명할 수 있다
[ ] batch 로 부하 기반 실행을 확인했다

11. 핵심 정리

  • at은 지정 시각에 한 번만 실행하고, batch는 부하가 낮을 때 실행한다.
  • at은 예약 당시의 환경변수·디렉터리·umask를 스크립트로 저장해 재현한다.
  • 스풀 위치는 Rocky /var/spool/at/, Ubuntu /var/spool/cron/atjobs/이다.
  • atd 로그에는 실행 시작만 남고 명령 내용은 남지 않는다. 내용은 실행 전 at -c로 확인한다.
  • 예약 작업 점검은 crontab·cron.d·timer와 함께 at 대기 작업 까지 포함한다.

12. 다음 편 예고

다음 글 「37. 소켓 활성화 (socket unit)」 에서는 16·22편에서 본 "systemd가 22번 포트를 쥐고 있는" 구조를 직접 만든다. 연결이 들어올 때만 서비스를 실행하는 socket unit을 작성하고, Ubuntu의 ssh.socket이 어떻게 동작하는지 확인한다.


참고 자료


시리즈 이동

profile
코드에 숨겨진 위협을 읽고 AI로 보안의 미래를 설계합니다. 프론트엔드 개발 경험을 자산 삼아 더 견고하고 지능적인 보안 운영 시스템을 구축해 나가는 과정을 기록합니다

0개의 댓글