Kernel Crash 대응 전략: Coredump 활용하기

안녕하세요, surmin입니다. 🙂

오늘은 Kernel Crash가 발생한 경우 대비와 원인 파악을 위해 kdump 사용법에 대해 알아보려고 합니다. 여러분께 도움이 되었으면 좋겠습니다.

환경: CentOS 7

crashkernel=auto 는 Linux 시스템에서 커널 패닉이나 시스템 크래시가 발생했을 때, 시스템의 상태를 분석하고 디버깅하기 위해 사용되는 kdump 기능의 설정입니다. 이 설정은 시스템이 부팅될 때 자동으로 crash kernel(크래시 커널)에 필요한 메모리를 예약하도록 지시합니다.

[root@localhost ~]# cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-3.10.0-1160.45.1.el7.x86_64 root=UUID=7a5c4aaa-03da-4913-a305-cc81d7134854 ro crashkernel=auto rhgb quiet LANG=ko_KR.UTF-8

#실습전 커널이 하나더 필요함으로 커널 버전이 하나만있을경우 버전 하나 더 설치한다
ls /boot/
yum list available kernel  #커널 리스트 검색
yum install kernel #커널 설치
#필수 패키지 kdump를 사용하기 위한
-kexec-tools: 커널 이미지 교체를 위한 도구
-crash: 커널 덤프 파일 분석 도구
yum install kexec-tools crash wget

-kernel-debuginfo: 커널 덤프 파일 분석에 필요한 디버깅 정보 패키지
#커널덤프파일 확인 패키지 여부 확인
rpm -q kernel-debuginfo
#없으면 /tmp 에 받고 설치 (종속성 있을경우  rpm 대신 yum으로 rpm설치)
wget http://debuginfo.centos.org/7/x86_64/kernel-debuginfo-3.10.0-693.17.1.el7.x86_64.rpm
wget http://debuginfo.centos.org/7/x86_64/kernel-debuginfo-common-x86_64-3.10.0-693.17.1.el7.x86_64.rpm
rpm -ivh kernel-debuginfo-common-x86_64-3.10.0-693.17.1.el7.x86_64.rpm
rpm -ivh kernel-debuginfo-3.10.0-693.17.1.el7.x86_64.rpm

#설치 확인
[root@localhost tmp]# rpm -q kernel-debuginfo
kernel-debuginfo-3.10.0-693.17.1.el7.x86_64

#Crash Kernel 메모리 할당적업
[메모리 자동 할당 방법]
/etc/default/grub 파일을 편집합니다.
GRUB_CMDLINE_LINUX_DEFAULT 변수에 crashkernel=auto 옵션을 추가합니다.
sudo grub2-mkconfig -o /boot/grub2/grub.cfg 명령을 실행하여 GRUB 설정을 업데이트합니다.
GRUB_CMDLINE_LINUX_DEFAULT="crashkernel=auto"

[메모리 수동 할당 방법]
vi /etc/default/grub
==
GRUB_CMDLINE_LINUX_DEFAULT="crashkernel=256M"
==

#레거시인지 UEFI인지 확인
ls /sys/firmware/efi 있는지 확인, 없으면 레거시

#변경사항을 적용하기 위해 grub2 설정을 업데이트합니다. (레거시),없는경우 skip
grub2-mkconfig -o /boot/grub2/grub.cfg
#uefi인경우 
grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg

#우분트인경우는: update-grub

# 리부팅하여 crashkernel을 예약하자.
#커널 파라미터 변경사항 적용을 위해,메모리예약을 위해선 리부팅 필수 
reboot

왜 적용을 하기 위해선 리부팅을 해야 할까?

커널 파라미터 적용: crashkernel 예약은 리눅스 부팅 시 커널에 전달되는 파라미터 중 하나입니다. 이 파라미터는 시스템이 부팅할 때 커널에 의해 읽혀지며, 커널이 실행 중일 때는 변경할 수 없습니다. 따라서, crashkernel 파라미터를 추가하거나 수정한 후에는 그 변경사항을 적용하기 위해 시스템을 재부팅해야 합니다.

메모리 예약: crashkernel 옵션은 시스템이 비정상적으로 종료되었을 때 커널 크래시 덤프를 캡처하는 데 필요한 메모리 영역을 예약합니다. 이 메모리는 시스템이 부팅하는 동안에만 예약될 수 있으며, 시스템이 이미 부팅된 후에는 이 영역을 예약하거나 변경할 수 없습니다.

grub2 설정 업데이트: crashkernel 파라미터를 변경하기 위해서는 GRUB2 부트로더 설정 파일을 수정하고, grub2-mkconfig 명령어를 사용하여 변경사항을 적용해야 합니다. 하지만, 이러한 변경사항은 부트로더가 다음 부팅 과정에서 새로운 커널 파라미터를 읽어들일 때까지 실제로 적용되지 않습니다.

#crashkernel이 잘 잡혀있는지 확인할수 있다.
cat /proc/cmdline
==
BOOT_IMAGE=/vmlinuz-3.10.0-1160.114.2.el7.x86_64 root=UUID=1ae8ae48-8d43-467b-a2cc-9c30c3d40f22 ro rhgb quiet crashkernel=256M
==
[root@localhost ~]# grep -i crash /proc/iomem
  26000000-35ffffff : Crash kernel

이제 kexec를 사용할 환경은 마련되었다. 새로운 커널을 load해보자.

#만약 1로 되어있는경우 OS설치 시 kdump를 활성화 한것이고 알아서 커널이 이미
적재되어 있는 상태이니 커널 패닉 TEST로 넘어간다.
[root@localhost ~]# cat /sys/kernel/kexec_crash_loaded
=
0
=

#새로운 커널 로드 
#-p로해야 커널패닉 시 panic시 load될 kernel을 지정할수 있다.
#이명령어는 예시이니 커널과 경로 맞출필요있음!
[root@localhost ~]# kexec -p /boot/vmlinuz-3.10.0-862.el7.x86_64 --initrd=/boot/initramfs-3.10.0-862.el7.x86_64.img --command-line="root=/dev/sda3 ro"

#kdump용 커널 모듈 방법
#만약 확인 시 LVM같은경우 는 경로가 다름 
kexec -p /boot/vmlinuz-3.10.0-1160.114.2.el7.x86_64 --initrd=/boot/initramfs-3.10.0-1160.114.2.el7.x86_64kdump.img --command-line="root=/dev/sda3 ro crashkernel=auto"

LVM 확인

kexec 명령어에서 사용하는 --command-line 옵션은 시스템이 부팅할 때 사용할 커널 파라미터를 지정합니다. 여기서 중요한 부분은 시스템의 root 파일 시스템을 어디에 위치하고 있는지를 지정하는 것입니다. root=/dev/sda1 ro라는 부분에서 root= 뒤에 오는 것이 시스템의 root 파일 시스템이 위치한 파티션입니다.

제공된 lsblk 출력 내용을 바탕으로, 시스템의 root 파일 시스템은 LVM 파티션인 centos-root에 위치하고 있습니다. 이는 / 마운트 포인트로 표시되고 있으며, sda2 파티션 위에 LVM으로 구성되어 있습니다.

따라서, kexec 명령어에서 사용할 정확한 root 파일 시스템 지정을 위해서는 centos-root LVM 볼륨의 장치 파일 경로를 사용해야 합니다. 대개 LVM 볼륨은 /dev/mapper 디렉토리에 위치하므로, centos-root 볼륨의 전체 경로는 /dev/mapper/centos-root가 될 것입니다. 하지만, 시스템에 따라 경로가 다를 수 있으니 /dev/centos/root 혹은 비슷한 경로일 수도 있습니다.

kexec -p /boot/vmlinuz-3.10.0-1160.el7.x86_64 –initrd=/boot/initramfs-3.10.0-1160.el7.x86_64kdump.img –command-line=”root=/dev/mapper/centos-root ro”

이 명령어는 시스템이 centos-root LVM 볼륨을 root 파일 시스템으로 사용하여 부팅하도록 지시합니다. 만약 /dev/mapper/centos-root 경로가 정확하지 않다면, 시스템에서 사용하는 정확한 LVM 볼륨의 경로를 확인해야 합니다. LVM 볼륨의 정확한 경로는 다음 명령어를 통해 찾을 수 있습니다:

ls -l /dev/mapper/

또는

lvdisplay

이를 통해 정확한 LVM 볼륨 경로를 찾아 kexec 명령어에 적용하면 됩니다.

kexec_loaded가 아닌 kexec_crash_loaded로 load여부를 확인할 수 있다. (일반적으로 capture kernel을 load할때 kernel parameter값으로 “irqpoll maxcpus=1”을 추가하도록 권장한다.)

#확인
[root@localhost ~]# cat /sys/kernel/kexec_crash_loaded
1

커널패닉 일으켜본다

# systemctl start kdump.service
# systemctl enable kdump.service

echo c > /proc/sysrq-trigger


#확인
[root@localhost ~]# uname -a
Linux localhost.localdomain 3.10.0-1160.114.2.el7.x86_64 #1 SMP Wed Mar 20 15:54:52 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux

크래시 덤프 파일 확인

크래시 덤프 파일은 기본적으로 /var/crash 디렉토리에 저장됩니다. crash 도구를 사용하여 이 덤프 파일을 분석할 수 있습니다.

[root@localhost crash]# pwd
/var/crash
[root@localhost crash]# ls
2024-04-26-00:46
[root@localhost 2024-04-26-00:46]# crash /usr/lib/debug/lib/modules/3.10.0-693.17.1.el7.x86_64/vmlinux vmcore
vmcore-dmesg.txt 파일 확인 시 
==
..
[  109.751593] Call Trace:
[  109.751593] SysRq : Trigger a crash
[  109.751624] BUG: unable to handle kernel NULL pointer dereference at           (null)
[  109.751637] IP: [<ffffffff8ca91076>] sysrq_handle_crash+0x16/0x30
...
[  109.752130] ---[ end trace 8a31f0514b7202df ]---
[  109.752130] Kernel panic - not syncing: Fatal exception
..
==

#적재한 커널로 부팅 후 확인 시 1확인
cat /sys/kernel/kexec_crash_loaded

#서비스 종료하면 0으로되는거 확인
[root@localhost boot]#  systemctl stop kdump
[root@localhost boot]# cat /sys/kernel/kexec_crash_loaded
0

위 로그에서 확인할 수 있는 중요한 정보는 아래와 같습니다.

  1. SysRq : Trigger a crash: 이 로그는 ‘SysRq’ 키 조합을 사용하여 커널 패닉을 의도적으로 발생시킨 것을 나타냅니다. SysRq 키는 시스템이 응답하지 않을 때 사용자가 시스템을 안전하게 재부팅하거나 디버깅 정보를 얻기 위해 사용할 수 있는 기능입니다. 여기서는 커널 패닉을 유발하는 Trigger a crash 명령이 사용되었습니다.
  2. BUG: unable to handle kernel NULL pointer dereference at (null): 이 메시지는 커널이 NULL 포인터 참조를 처리할 수 없어서 문제가 발생했음을 나타냅니다. NULL 포인터 참조는 유효하지 않은 메모리 위치에 접근하려고 할 때 발생합니다.
  3. IP: [<ffffffff8ca91076>] sysrq_handle_crash+0x16/0x30: 이 부분에서는 문제가 발생한 코드의 위치를 보여줍니다. sysrq_handle_crash 함수 내에서 문제가 발생했음을 나타냅니다.
  4. Kernel panic – not syncing: Fatal exception: 이 메시지는 커널 패닉이 발생하여 시스템이 더 이상 정상적으로 작동할 수 없음을 나타냅니다.

기존 커널 지우고 다시 받는법 (실무에서는 가급적 주의)

현재 실행 중인 커널 버전 확인:

uname -r

설치된 커널 목록 확인:

rpm -q kernel

커널 제거:

sudo yum remove kernel-<버전>

커널 설치:

sudo yum install kernel

GRUB 설정 업데이트

sudo grub2-mkconfig -o /boot/grub2/grub.cfg

#EFI인경우
sudo grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg

#시스템 재부팅
sudo reboot

궁금점

kdump.img 말고 일반 커널을 사용하면 안될까?

  1. kdump.img initramfs는 kernel crash 발생 시 kexec를 통해 로드되는 crash kernel입니다.
  2. 이미 initramfs가 있음에도 별도의 crash kernel을 유지하는 것은, 커널 자체의 오류로 인해 메인 커널에서 덤프를 수집하는 메커니즘이 정상 작동하지 않을 가능성이 있기 때문입니다. kdump가 커널 개발 과정에서도 사용되는 점을 감안하면, 충분히 있을법한 기능입니다.
  3. 명확한 이유와 근거가 있지 않은 한 기본값으로 놓고 쓰세요

부가 설명

시스템이 충돌하거나 문제가 발생했을 때, 이를 분석하기 위해 메모리 상태를 저장하는 것이 kdump의 역할입니다. 이때 사용되는 것이 바로 ‘capture kernel’입니다. Capture kernel은 시스템 부팅 시 사용되는 일반 커널과는 구별되며, 주로 ‘initramfs’라고 하는 초기 RAM 파일 시스템을 로드합니다. Initramfs는 커널이 시스템을 시작할 때 임시로 사용하는 파일 시스템입니다.

Capture kernel이 로드하는 initramfs는 대부분의 경우 일반 커널이 로드하는 initramfs와는 다릅니다. 하지만 때로는 capture kernel과 일반 커널이 같은 initramfs를 사용할 수도 있습니다. 이는 capture kernel이 특정 상황에서 필요한 특별한 설정이나 모듈을 포함할 수 있다는 것을 의미합니다. 그렇기 때문에 일반적인 커널 이미지(예: vmlinuz-3.10.0-862.el7.x86_64.img) 대신 특정한 커널 이미지(.kdump.img 등)를 사용해야 한다는 것입니다.

위로 스크롤