RHEL 중급 #5 로그 관리 — journald, rsyslog, log rotation
기초 #4에서 journald와 journalctl을 다뤘습니다. 이번 글에서는 그 위에 한 단계 더 들어가 운영에서 로그를 다루는 방법을 정리합니다. 보관 정책으로 디스크 사용량을 잡고, rsyslog로 원격 서버에 로그를 모으고, logrotate로 텍스트 로그를 자동 회전시키는 흐름까지 이어집니다.
RHEL 중급 시리즈에서 이번 글의 위치:
- #1 SELinux 입문 — Enforcing/Permissive, 라벨, 트러블슈팅
- #2 LVM — PV/VG/LV, 스냅샷, 확장
- #3 스토리지 심화 — Stratis, NFS, Samba
- #4 네트워킹 — NetworkManager (nmcli), bonding, teaming
- #5 로그 관리 — journald, rsyslog, log rotation ← 이번 글
- #6 작업 스케줄링 — cron, systemd timer, at
- #7 컨테이너 입문 — Podman/Buildah/Skopeo (Docker와의 차이)
RHEL 9의 로그 구조 #
RHEL 9에서는 두 도구가 함께 일합니다. journald가 메인, rsyslog가 보조입니다.
커널 / 서비스 / 사용자 프로세스
│
│ syslog() / journald API
▼
┌─────────────────────────┐
│ journald │ ← 메인 (구조화 바이너리)
│ /run/log/journal/ │ /var/log/journal/ (영구)
└────────────┬────────────┘
│ 전달 (옵션)
▼
┌─────────────────────────┐
│ rsyslog │ ← 옛 텍스트 로그 호환 + 원격 송신
│ /var/log/messages │
│ /var/log/secure │
│ /var/log/maillog │
└────────────┬────────────┘
│ logrotate (cron)
▼
회전된 압축 로그 파일
/var/log/messages-20260420.gz흐름의 핵심:
- 커널,서비스가 보내는 로그는 모두 journald가 먼저 받습니다.
- journald는 자기 바이너리 형식으로 저장하면서 동시에 rsyslog에도 전달.
- rsyslog는 옛 텍스트 파일(
/var/log/messages등)을 만들고, 원격 syslog 서버로 송신할 수도 있습니다. - 모든 텍스트 로그 파일은 logrotate가 일정 크기,기간으로 자동 회전.
운영자는 둘 다 알아야 합니다. 새 도구는 journalctl이지만, 옛 자료,외부 SIEM(보안 정보 이벤트 관리),다른 호스트와의 통합에서는 rsyslog가 여전히 필수입니다.
journald — 깊이 들어가기 #
기초 #4에서 본 journalctl -u, -b, --since 같은 명령은 일상 도구. 이번엔 그 뒤의 보관 정책과 디스크 사용량 제어를 봅니다.
휘발성 vs 영구 보관 #
기본 RHEL 9는 journald가 휘발성(/run/log/journal/)으로 동작합니다. 재부팅하면 사라집니다. 운영 머신에서는 영구 보관을 켜는 게 표준.
$ sudo mkdir -p /var/log/journal
$ sudo systemd-tmpfiles --create --prefix /var/log/journal
$ sudo systemctl restart systemd-journald
# 확인
$ journalctl --list-boots
-2 ... 2026-04-18 09:01:23 2026-04-19 08:55:11
-1 ... 2026-04-19 09:00:01 2026-04-20 08:55:32
0 ... 2026-04-20 09:00:01 2026-04-20 14:23:01--list-boots가 여러 부팅을 보여주면 영구 보관이 켜진 것입니다.
디스크 사용량 제어 — journald.conf
#
영구 보관을 켜면 로그가 무한히 쌓일 수 있습니다. 상한을 명시적으로 잡아두는 게 운영의 핵심.
[Journal]
Storage=persistent
# 디스크 사용량 상한
SystemMaxUse=2G
SystemKeepFree=500M
SystemMaxFileSize=128M
SystemMaxFiles=100
# 보관 기간
MaxRetentionSec=30day
# 압축 / 봉인
Compress=yes
Seal=yes옵션 풀이:
| 옵션 | 의미 |
|---|---|
Storage=persistent | 영구 보관 강제 |
SystemMaxUse | journald가 쓸 디스크 상한 |
SystemKeepFree | 디스크에 항상 비워둘 여유 공간 |
SystemMaxFileSize | 한 journal 파일의 최대 크기 (이 크기에서 회전) |
SystemMaxFiles | 보관할 파일 수 |
MaxRetentionSec | 보관 최대 기간 (30day, 4week, 1month 등) |
Compress | 자동 압축 |
Seal | 무결성 봉인 (위변조 방지) |
SystemMaxUse와 MaxRetentionSec 중 먼저 도달한 쪽이 적용됩니다. 둘 다 잡으면 안전.
$ sudo systemctl restart systemd-journald
$ journalctl --disk-usage
Archived and active journals take up 1.2G in the file system.journald 정리 — 즉시 회수 #
급히 디스크 공간이 필요할 때:
$ sudo journalctl --vacuum-size=500M # 500M이하로 줄임
$ sudo journalctl --vacuum-time=7d # 7일 이상 된 것 삭제
$ sudo journalctl --vacuum-files=10 # 파일 10개로 줄임--vacuum-size가 가장 자주 쓰이는 옵션. 운영에서 디스크 알림 직후 즉각적인 회수가 필요할 때 씁니다.
구조화 로그 활용 #
journald의 진짜 장점. 모든 로그가 키-값 메타데이터를 가지고 있습니다.
$ journalctl _COMM=sshd # sshd 명령의 로그
$ journalctl _SYSTEMD_UNIT=nginx.service # 특정 unit
$ journalctl _UID=1000 # 특정 사용자
$ journalctl _PID=1234 # 특정 PID
# 모든 메타데이터 보기
$ journalctl -o verbose -n 5# nginx의 에러만, 오늘
$ journalctl -u nginx -p err --since today
# 특정 사용자가 친 sudo 명령
$ journalctl _COMM=sudo _UID=1000
# 특정 IP에서 온 ssh 시도 (메시지 본문 검색)
$ journalctl -u sshd | grep "192.168.64.50"출력 형식 변경 #
$ journalctl -o json -n 10 # 한 줄 JSON
$ journalctl -o json-pretty -n 5 # 보기 좋은 JSON
$ journalctl -o cat -n 100 # 메시지 본문만
$ journalctl -o short-iso -n 100 # ISO 8601 시간-o json은 자동화에 유용. jq와 함께 쓰면 강력한 분석 도구가 됩니다.
$ journalctl -o json -u nginx --since today | \
jq 'select(.PRIORITY == "3") | .MESSAGE' # err 메시지만 추출rsyslog — 옛 표준이 살아있는 이유 #
journald가 메인이지만 rsyslog는 여전히 활발합니다. 세 가지 이유:
- 외부 SIEM(Splunk, Graylog, ELK 등) 연동 — 표준 syslog 프로토콜로 받음.
- 원격 로그 수집 — 여러 호스트의 로그를 한 서버에 모음.
- 옛 텍스트 파일 호환 —
/var/log/messages,/var/log/secure를 보는 자동화 / 모니터링.
$ systemctl status rsyslog
● rsyslog.service - System Logging Service
Active: active (running)
...주요 텍스트 로그 #
rsyslog가 만드는 익숙한 파일들:
| 파일 | 내용 |
|---|---|
/var/log/messages | 일반 시스템 메시지 |
/var/log/secure | 인증 / 권한 (sshd, sudo 등) |
/var/log/maillog | 메일 |
/var/log/cron | cron / at 작업 |
/var/log/boot.log | 부팅 로그 |
/var/log/dnf.log | 패키지 작업 |
/var/log/secure는 보안 점검의 첫 진입점. 누가 언제 ssh로 접속하고 sudo를 썼는지가 모두 여기 남습니다.
설정 — /etc/rsyslog.conf
#
# 기본 모듈
module(load="imuxsock") # local 시스템 로그 받기
module(load="imjournal") # journald에서 받기
# 규칙 (facility.priority + 액션)
*.info;mail.none;authpriv.none;cron.none /var/log/messages
authpriv.* /var/log/secure
mail.* -/var/log/maillog
cron.* /var/log/cron
*.emerg :omusrmsg:*규칙의 좌측은 facility.priority(어떤 종류의 로그를), 우측은 액션(어디로). facility는 auth/authpriv/cron/daemon/kern/mail/user/local0~7 등이 있고, priority는 debug/info/notice/warning/err/crit/alert/emerg.
추가 설정 — /etc/rsyslog.d/
#
핵심 파일은 그대로 두고, 새 규칙은 분리 파일로 두는 게 표준입니다.
# 우리 앱이 쓰는 facility local6만 별도 파일로
local6.* /var/log/myapp.log$ sudo systemctl restart rsyslog원격 로그 — 여러 호스트 → 중앙 서버 #
운영 머신이 여러 대면 로그를 한곳에 모으는 게 표준입니다. rsyslog가 이걸 합니다.
중앙 서버 (수신 측) #
# UDP 514로 수신
module(load="imudp")
input(type="imudp" port="514")
# TCP도 같이 (안정성)
module(load="imtcp")
input(type="imtcp" port="514")
# 호스트별 디렉터리로 분리
$template RemoteHost,"/var/log/remote/%HOSTNAME%/%PROGRAMNAME%.log"
*.* ?RemoteHost
& stop$ sudo firewall-cmd --permanent --add-port=514/udp
$ sudo firewall-cmd --permanent --add-port=514/tcp
$ sudo firewall-cmd --reload
$ sudo systemctl restart rsyslog이러면 다른 호스트가 보낸 로그가 /var/log/remote/<hostname>/<프로그램>.log에 저장됩니다.
클라이언트 (송신 측) #
# 모든 로그를 192.168.64.10으로 전달
*.* @192.168.64.10:514 # @는 UDP
# *.* @@192.168.64.10:514 # @@는 TCP (더 안전)$ sudo systemctl restart rsyslogTLS로 암호화 (운영 권장) #
평문 syslog는 네트워크에서 평문으로 흐릅니다. 운영에서는 TLS로 감싸는 게 표준입니다. rsyslog-gnutls 패키지를 설치하고 인증서를 잡아 imrelp / omrelp 모듈을 쓰는 흐름을 정리합니다. 자세한 셋업은 고급 시리즈에서 다룹니다.
logrotate — 로그 회전의 표준 #
텍스트 로그 파일은 그냥 두면 GB까지 커집니다. logrotate가 일정 주기,크기에 도달하면 회전(이름 바꾸고 새 파일 시작) + 압축 + 오래된 것 삭제를 자동으로.
logrotate는 별도 데몬이 아니라 cron 또는 systemd timer로 호출되는 도구입니다.
$ systemctl list-timers | grep logrotate
NEXT LEFT LAST PASSED UNIT ACTIVATES
... ... ... ... logrotate.timer logrotate.service
$ systemctl cat logrotate.timer
[Timer]
OnCalendar=daily
AccuracySec=1h
Persistent=true매일 한 번 자동 실행. 옛 RHEL은 /etc/cron.daily/logrotate로 실행했지만 RHEL 9는 systemd timer로 옮겨졌습니다.
설정 구조 #
weekly
rotate 4
create
dateext
include /etc/logrotate.d# 예: /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 640 nginx adm
sharedscripts
postrotate
if [ -f /run/nginx.pid ]; then
kill -USR1 $(cat /run/nginx.pid)
fi
endscript
}옵션 풀이:
| 옵션 | 의미 |
|---|---|
daily / weekly / monthly | 회전 주기 |
rotate N | 보관할 회전본 수 |
compress | 회전 직후 압축 (기본 gzip) |
delaycompress | 회전 후 한 번 더 기다렸다 압축 (현재 쓰는 파일 보호) |
missingok | 파일이 없어도 에러 안 냄 |
notifempty | 비어 있으면 회전 안 함 |
create <mode> <user> <group> | 회전 후 새 파일 생성 권한 |
dateext | 파일명에 날짜 붙이기 (-20260420) |
sharedscripts | 여러 파일에 한 번만 스크립트 실행 |
postrotate ~ endscript | 회전 후 실행할 명령 (시그널 전송 등) |
직접 작성 #
내 앱의 로그를 logrotate에 맡기려면:
/var/log/myapp/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 640 myapp myapp
sharedscripts
postrotate
systemctl reload myapp.service > /dev/null 2>&1 || true
endscript
}테스트 / 강제 실행 #
$ sudo logrotate -d /etc/logrotate.d/myapp # debug — 어떻게 회전될지만 출력
$ sudo logrotate -v /etc/logrotate.d/myapp # verbose — 실제 실행 + 자세한 출력
$ sudo logrotate -f /etc/logrotate.d/myapp # force — 회전 조건 무시하고 강제운영에서는 -d로 먼저 시뮬레이션하고, 의도와 맞으면 그대로 두면 됩니다. timer가 자동으로 적용합니다.
journald와 logrotate의 관계 #
/var/log/journal/의 journald 파일은 logrotate가 건드리지 않습니다. journald가 자기 정책(SystemMaxUse 등)으로 직접 회전합니다.
logrotate는 rsyslog가 만드는 텍스트 로그 파일(/var/log/messages 등)과 사용자가 만든 로그 파일을 다룹니다. journald는 logrotate 대상이 아니고, rsyslog 텍스트 로그는 journald와 다른 층에서 관리한다는 식의 분업입니다.
보안 / 컴플라이언스 관점 #
운영에서 자주 만나는 요구사항:
로그 무결성 #
Seal=yes로 journald 봉인을 켜면 로그를 위변조하면 검출됩니다.
$ sudo journalctl --setup-keys
$ sudo journalctl --verify보관 기간 정책 #
산업,규제에 따라 다릅니다. 흔한 기준:
| 환경 | 권장 보관 |
|---|---|
| 일반 서버 | 30~90일 |
| PCI-DSS (결제) | 1년 |
| HIPAA (의료) | 6년 |
| 금융 / SOX | 7년 |
장기 보관은 보통 원격 서버 또는 S3,tape으로 옮깁니다. 머신 안에는 단기만 보관합니다.
로그 무한 증가 방지 #
SystemMaxUse와 MaxRetentionSec를 둘 다 잡고, logrotate의 rotate N도 명시. 모니터링 알람도 /var/log 사용량에 거는 게 표준.
AlmaLinux / Rocky 차이 #
이번 글의 모든 명령이 그대로 동작 합니다. journald / rsyslog / logrotate는 RHEL 패키지 그대로.
자주 만나는 함정 #
“journald 영구 보관을 켰는데 디스크가 가득 차요” #
SystemMaxUse를 명시적으로 잡지 않으면 기본은 디스크의 10%까지 차요. 큰 디스크에선 문제될 수 있습니다. 항상 명시적으로 상한 지정.
“journalctl이 옛 부팅 로그를 안 보여 줍니다” #
영구 보관이 안 켜진 경우. /var/log/journal/ 디렉터리가 있는지 확인.
“rsyslog 원격 서버에 로그가 안 옴” #
방화벽(514 UDP/TCP)과 SELinux를 함께 보세요. SELinux로 포트를 바꿨다면 syslogd_port_t가 맞는지 확인하고, 필요하면 semanage port로 등록해야 합니다.
“logrotate가 안 돕니다” #
systemctl status logrotate.timer로 timer가 활성인지 확인. 또는 logrotate -d로 시뮬레이션해 어떤 파일이 어떤 이유로 회전 안 되는지 보기.
“회전 후 앱이 새 파일에 안 쓰고 옛 파일에 계속 써요” #
앱이 SIGHUP을 받아 파일을 다시 열어야 하는데, postrotate에서 kill -HUP 또는 systemctl reload를 빼먹은 경우. 회전 규칙에 반드시 reload 명령 포함.
자주 쓰는 명령 한 표 #
| 도구 | 명령 |
|---|---|
| journald | journalctl -u <unit> [-f] |
| journald | journalctl --since "1 hour ago" |
| journald | journalctl --list-boots |
| journald | journalctl --disk-usage |
| journald | journalctl --vacuum-size=500M |
| journald | journalctl _COMM=sshd (필드 검색) |
| journald | journalctl -o json (JSON 출력) |
| rsyslog | systemctl status rsyslog |
| rsyslog | tail -f /var/log/messages |
| rsyslog | tail -f /var/log/secure |
| logrotate | logrotate -d <conf> (시뮬레이션) |
| logrotate | logrotate -f <conf> (강제 실행) |
| logrotate | systemctl list-timers | grep logrotate |
정리 #
이번 글에서 정리한 흐름:
- RHEL 9의 로그는 journald(메인) + rsyslog(보조) + **logrotate(회전)**의 세 도구가 함께 일합니다.
- journald는 영구 보관(
/var/log/journal/)을 명시적으로 켜고, **SystemMaxUse/MaxRetentionSec**으로 디스크 상한을 잡는 게 표준. - 디스크가 급할 땐 **
journalctl --vacuum-size=...**로 즉시 회수. - 구조화 로그 검색은
_COMM=/_SYSTEMD_UNIT=같은 필드 +-o json+ jq 조합. - rsyslog는 옛 텍스트 로그 호환과 원격 syslog 수집의 표준. 중앙 서버 + 클라이언트 흐름은 한 호스트 너머에서 운영의 일상.
- logrotate는 systemd timer로 매일 실행.
/etc/logrotate.d/<app>에 규칙을 두고,-d시뮬레이션으로 항상 검증. - 보관 정책은 산업,규제에 따라 30일~7년, 머신 외부로 옮기는 흐름이 일반적.
다음 — 작업 스케줄링 #
로그를 정리했다면, 이제 그 작업을 언제 돌릴지로 넘어갑니다. 매일 실행되는 logrotate 자체도 systemd timer의 대표적 사례입니다.
#6 작업 스케줄링 — cron, systemd timer, at에서는 전통의 cron과 사용자 crontab, 한 번만 예약 실행하는 at, 머신이 꺼져 있던 시간을 보충하는 anacron, 그리고 cron의 모던 대체인 systemd timer까지 — 어느 도구를 어느 상황에 쓸지 가이드와 함께 정리합니다.