RHEL 중급 #5 로그 관리 — journald, rsyslog, log rotation

10 분 소요

기초 #4에서 journald와 journalctl을 다뤘습니다. 이번 글에서는 그 위에 한 단계 더 들어가 운영에서 로그를 다루는 방법을 정리합니다. 보관 정책으로 디스크 사용량을 잡고, rsyslog로 원격 서버에 로그를 모으고, logrotate로 텍스트 로그를 자동 회전시키는 흐름까지 이어집니다.

RHEL 중급 시리즈에서 이번 글의 위치:

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 #

영구 보관을 켜면 로그가 무한히 쌓일 수 있습니다. 상한을 명시적으로 잡아두는 게 운영의 핵심.

/etc/systemd/journald.conf 일부
[Journal]
Storage=persistent

# 디스크 사용량 상한
SystemMaxUse=2G
SystemKeepFree=500M
SystemMaxFileSize=128M
SystemMaxFiles=100

# 보관 기간
MaxRetentionSec=30day

# 압축 / 봉인
Compress=yes
Seal=yes

옵션 풀이:

옵션의미
Storage=persistent영구 보관 강제
SystemMaxUsejournald가 쓸 디스크 상한
SystemKeepFree디스크에 항상 비워둘 여유 공간
SystemMaxFileSize한 journal 파일의 최대 크기 (이 크기에서 회전)
SystemMaxFiles보관할 파일 수
MaxRetentionSec보관 최대 기간 (30day, 4week, 1month 등)
Compress자동 압축
Seal무결성 봉인 (위변조 방지)

SystemMaxUseMaxRetentionSec먼저 도달한 쪽이 적용됩니다. 둘 다 잡으면 안전.

적용 + 확인
$ 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"

출력 형식 변경 #

JSON / 다른 포맷
$ 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와 함께 쓰면 강력한 분석 도구가 됩니다.

jq와 조합
$ journalctl -o json -u nginx --since today | \
    jq 'select(.PRIORITY == "3") | .MESSAGE'    # err 메시지만 추출

rsyslog — 옛 표준이 살아있는 이유 #

journald가 메인이지만 rsyslog는 여전히 활발합니다. 세 가지 이유:

  1. 외부 SIEM(Splunk, Graylog, ELK 등) 연동 — 표준 syslog 프로토콜로 받음.
  2. 원격 로그 수집 — 여러 호스트의 로그를 한 서버에 모음.
  3. 옛 텍스트 파일 호환/var/log/messages, /var/log/secure를 보는 자동화 / 모니터링.
rsyslog 상태
$ 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/croncron / at 작업
/var/log/boot.log부팅 로그
/var/log/dnf.log패키지 작업

/var/log/secure는 보안 점검의 첫 진입점. 누가 언제 ssh로 접속하고 sudo를 썼는지가 모두 여기 남습니다.

설정 — /etc/rsyslog.conf #

/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/ #

핵심 파일은 그대로 두고, 새 규칙은 분리 파일로 두는 게 표준입니다.

/etc/rsyslog.d/50-myapp.conf
# 우리 앱이 쓰는 facility local6만 별도 파일로
local6.*    /var/log/myapp.log
적용
$ sudo systemctl restart rsyslog

원격 로그 — 여러 호스트 → 중앙 서버 #

운영 머신이 여러 대면 로그를 한곳에 모으는 게 표준입니다. rsyslog가 이걸 합니다.

중앙 서버 (수신 측) #

/etc/rsyslog.d/00-receiver.conf
# 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에 저장됩니다.

클라이언트 (송신 측) #

/etc/rsyslog.d/90-forward.conf
# 모든 로그를 192.168.64.10으로 전달
*.*    @192.168.64.10:514       # @는 UDP
# *.* @@192.168.64.10:514       # @@는 TCP (더 안전)
적용
$ sudo systemctl restart rsyslog

TLS로 암호화 (운영 권장) #

평문 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로 옮겨졌습니다.

설정 구조 #

/etc/logrotate.conf — 전역 기본값
weekly
rotate 4
create
dateext
include /etc/logrotate.d
/etc/logrotate.d/<package>.conf — 패키지별 규칙
# 예: /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에 맡기려면:

/etc/logrotate.d/myapp
/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년
금융 / SOX7년

장기 보관은 보통 원격 서버 또는 S3,tape으로 옮깁니다. 머신 안에는 단기만 보관합니다.

로그 무한 증가 방지 #

SystemMaxUseMaxRetentionSec를 둘 다 잡고, 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 명령 포함.

자주 쓰는 명령 한 표 #

도구명령
journaldjournalctl -u <unit> [-f]
journaldjournalctl --since "1 hour ago"
journaldjournalctl --list-boots
journaldjournalctl --disk-usage
journaldjournalctl --vacuum-size=500M
journaldjournalctl _COMM=sshd (필드 검색)
journaldjournalctl -o json (JSON 출력)
rsyslogsystemctl status rsyslog
rsyslogtail -f /var/log/messages
rsyslogtail -f /var/log/secure
logrotatelogrotate -d <conf> (시뮬레이션)
logrotatelogrotate -f <conf> (강제 실행)
logrotatesystemctl 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까지 — 어느 도구를 어느 상황에 쓸지 가이드와 함께 정리합니다.

X