인프라

[리눅스 뻘짓 일기] 루트 파티션 변경 하기

하루이2222 2025. 4. 8. 04:16

LVM 파티션 재구성 및 GRUB 부트로더 복구 작업 기록

이 문서는 1TB 서버의 100GB LVM 루트 파티션 용량 부족 문제를 해결하기 위해 시스템 파티션을 재구성하고, 변경된 환경에 맞게 GRUB 부트로더를 복구한 전체 과정을 기술함.


1. 초기 문제 정의 및 해결 계획 수립

  • 초기 상황: 1TB 디스크를 장착한 서버가 100GB 크기의 LVM(논리 볼륨)으로 루트(/) 파티션이 설정되어, IntelliJ Gateway 및 LXC 컨테이너 사용으로 인해 용량 부족 현상이 발생했음.
  • 초기 목표: 호스트 OS와 LXC 컨테이너의 스토리지를 분리하기 위해, 기존 LVM 볼륨 그룹(VG)을 확장하고 논리 볼륨(LV)을 분리하는 것을 목표로 설정함.
  • 기술적 한계: LVM 확장을 시도하는 과정에서, LVM의 기반이 되는 물리적 파티션(PV) 자체가 특정 크기에 묶여 있어 단순 확장이 불가능하다는 점을 확인함.

2. LVM 제거 및 파티션 재구성

단순 확장이 불가능하여, LVM을 완전히 제거하고 파티션 구조를 새로 설계하는 방식으로 계획을 변경함.

2-1. 시스템 데이터 백업

  • 상세 작업 내용: 데이터 손실을 방지하기 위해 rsync를 사용하여 시스템 전체 데이터를 별도의 저장소에 백업.
단계 작업 내용 예시 명령어
1 기존 LVM 볼륨 마운트 sudo mount /dev/ubuntu-vg/ubuntu-lv /mnt/oldroot
2 백업용 저장소 마운트 sudo mount /dev/sdb1 /mnt/backup
3 시스템 전체 복제 실행 sudo rsync -aAXv --info=progress2 /mnt/oldroot/ /mnt/backup/

2-2. LVM 해체 및 파티션 재생성

  • 상세 작업 내용: 데이터 백업 완료 후, 기존 LVM 구성을 역순으로 해체하고 parted를 이용해 디스크 파티션을 물리적으로 재구성함.
단계 작업 내용 예시 명령어
1 LVM 비활성화 sudo lvchange -an /dev/ubuntu-vg/ubuntu-lv sudo vgchange -an ubuntu-vg
2 LVM 구성요소 제거 sudo lvremove /dev/ubuntu-vg/ubuntu-lv sudo vgremove ubuntu-vg sudo pvremove /dev/nvme0n1p3
3 Parted 실행 sudo parted /dev/nvme0n1
4 기존 파티션 삭제 (parted) rm 3
5 새 파티션 생성 (parted) mkpart primary ext4 2048s 130G (parted) mkpart primary 130G 100%
6 변경사항 저장 및 종료 (parted) quit

2-3. 시스템 복원 및 부팅 실패 발생

  • 상세 작업 내용: 재구성된 130GB 파티션을 포맷하고, 백업해 둔 시스템 데이터를 복원했음. 이로 인해 파티션의 UUID가 변경되어 첫 부팅에 실패.
단계 작업 내용 예시 명령어
1 새 파티션 포맷 sudo mkfs.ext4 /dev/nvme0n1p2 (새로 생성된 파티션)
2 새 파티션 마운트 sudo mount /dev/nvme0n1p2 /mnt/newroot
3 백업 데이터 복원 sudo rsync -aAXv --info=progress2 /mnt/backup/ /mnt/newroot/
4 결과 확인 재부팅 시 initramfs 프롬프트로 진입

3. 최종 시스템 아키텍처 정의

초기 계획을 수정하여, 최종 시스템 아키텍처를 변경함.

  • 최종 목표 아키텍처:
    • 호스트 OS: /dev/nvme0n1의 첫 130GB를 일반 ext4 파티션으로 할당하여 루트(/)로 사용.
    • LXC 컨테이너: /dev/nvme0n1의 남은 360GB와 다른 SSD의 250GB를 각각 물리 볼륨(PV)으로 만들어 하나의 볼륨 그룹(VG)으로 묶어 컨테이너 전용 LVM 스토리지 풀로 사용.

4. GRUB 부트로더 복구 작업

새로운 아키텍처에 맞게, 변경된 루트 파티션(130GB 일반 파티션)으로 시스템을 부팅시키기 위해 GRUB 부트로더 복구 작업을 수행함.

4-1. 표준 복구 시도의 실패

  • 상세 작업 내용: 부팅 실패의 원인인 UUID 불일치를 해결하기 위해, chroot 환경(Live USB 환경, 파티션 작업은 절대 루트볼륨이 마운트 된 상태에서 하면 안됨!)에서 관련 설정 파일의 UUID를 수동으로 수정했으나 update-grub이 정상적으로 동작하지 않았음.
단계 작업 내용 예시 명령어
1 새 UUID 확인 sudo blkid /dev/nvme0n1p2
2 루트 파티션 마운트 sudo mount /dev/nvme0n1p2 /mnt
3 설정 파일 수정 sudo nano /mnt/etc/fstab , sudo nano /mnt/etc/default/grub
4 결과 update-grub을 실행했으나 부팅 설정이 제대로 갱신되지 않음

4-2. 수동 부트 엔트리 작성으로의 전환

  • 상세 작업 내용: update-grub의 자동 업데이트가 실패, 40_custom 스크립트에 부팅 명령어를 직접 정의하여 강제로 부팅 메뉴를 생성하는 방식으로 전환했음.
단계 작업 내용 예시 명령어
1 커스텀 스크립트 편집 sudo nano /etc/grub.d/40_custom (chroot 환경 내부)
2 실행 권한 부여 sudo chmod +x /etc/grub.d/40_custom
  • 부트 엔트리 코드 작성
    위 1단계에서 편집한 /etc/grub.d/40_custom 파일에 다음 부트 엔트리 코드를 작성했음.
menuentry 'Manual Ubuntu Boot' {
    set root='hd0,gpt2'
    linux /boot/vmlinuz-generic root=UUID=<새 UUID> ro
    initrd /boot/initrd.img-generic
}

4-3. chroot 환경 구축

  • 상세 작업 내용: grub-install과 같은 시스템 복구 명령어를 올바르게 실행하기 위해, Live USB 환경에서 복구 대상 시스템으로 루트를 완벽하게 전환하는 가상 환경을 구축했음.
단계 작업 내용 예시 명령어
1 루트 파티션 마운트 sudo mount /dev/nvme0n1p2 /mnt
2 시스템 디렉토리 바인드 for d in dev dev/pts proc sys; do sudo mount --bind /$d /mnt/$d; done
3 UEFI 파티션 마운트 sudo mount /dev/nvme0n1p1 /mnt/boot/efi
4 chroot 환경 진입 sudo chroot /mnt
5 EFI 변수 마운트 (chroot 내부) mount -t efivars efivars /sys/firmware/efi/efivars

4-4. 최종 오류 분석(트러블 슈팅)

fstab/etc/default/grub의 UUID를 올바르게 수정했음에도 update-grub 명령이 적용되지 않은 현상은, 시스템 복구 과정에서 발생할 수 있는 대표적인 'silent failure'임. 명령어 자체는 오류 없이 실행된 것처럼 보이지만, 실제 결과물인 /boot/grub/grub.cfg는 갱신되지 않았음.

가장 유력한 원인은 불완전한 chroot 환경 때문이라고 추측함.

update-grub은 단순히 설정 파일을 읽어 텍스트를 교체하는 프로그램이 아니라, 실행되는 시점의 시스템을 동적으로 탐색하여 grub.cfg를 '생성'하는 스크립트임. 이 동적 탐색 과정이 실패하면, 명령어 자체는 오류 없이 끝나도 결과물은 갱신되지 않을 수 있음.

  • 실패 과정 상세 분석:
    1. 설정 파일 수정: fstab/etc/default/grub의 UUID를 새로운 루트 파티션의 것으로 정확히 수정했음. 이 단계의 작업은 올바르게 수행되었음.
    2. 불완전한 chroot 환경: 하지만 /dev, /proc, /sys 등의 필수 가상 파일 시스템을 현재 시스템과 연결(bind mount)하지 않은 채 chroot 환경에 진입했음.
    3. 동적 탐색 실패: chroot 내부에서 update-grub을 실행하자, GRUB의 하위 스크립트(주로 /etc/grub.d/10_linux)가 새로운 루트 파티션을 탐색해야 했음. 그러나 시스템의 장치 정보(dev), 커널 및 프로세스 정보(proc, sys)에 접근할 수 없었기 때문에, 새로운 UUID를 가진 장치를 현재 시스템의 루트 파티션으로 발견하는 데 실패했음.
    4. 결과: 스크립트는 새로운 정보를 발견하지 못하자, 변경 전의 정보(캐시 또는 환경 변수에 남아있던 옛 LVM 경로 등)를 바탕으로 grub.cfg를 생성하거나, 혹은 해당 부팅 항목의 업데이트 자체를 건너뛰었음. 이 과정에서 스크립트가 문법 오류 등으로 중단된 것이 아니므로, 셸에는 아무런 오류 메시지 없이 작업이 완료된 것처럼 보였음.

작업 관련 용어 및 개념 총정리

여기서 부터는 LVM 파티션 재구성 및 GRUB 부트로더 복구 과정에서 언급된 모든 기술 용어와 개념을 정리한 자료임.

1. LVM (Logical Volume Manager) 관련 개념

LVM은 물리적인 디스크를 추상화하여 유연하고 확장 가능한 스토리지 관리를 지원하는 기술이며, 계층 구조를 가짐.

  • PV (Physical Volume / 물리 볼륨)
    • 정의: LVM에서 사용할 수 있는 기본 단위로, 디스크 파티션(/dev/nvme0n1p3)이나 디스크 전체를 LVM용으로 초기화한 것임.
    • 관련 명령어: pvcreate (PV 생성), pvremove (PV 제거), pvs (PV 목록 보기).
    • 작업 내용: 사용자는 기존 LVM을 해체하기 위해 pvremove를 사용했으며, 새로운 컨테이너용 LVM을 만들기 위해 360GB와 250GB 파티션을 각각 PV로 만들었음.
  • VG (Volume Group / 볼륨 그룹)
    • 정의: 하나 이상의 PV들을 묶어 하나의 큰 저장소 풀(Pool)로 만든 것임. (예: ubuntu-vg)
    • 관련 명령어: vgcreate (VG 생성), vgremove (VG 제거), vgextend (VG 확장), vgs (VG 목록 보기).
    • 작업 내용: 사용자는 기존 ubuntu-vgvgremove로 제거했으며, 두 개의 새로운 PV를 묶어 컨테이너용 VG를 새로 생성했음.
  • LV (Logical Volume / 논리 볼륨)
    • 정의: VG라는 저장소 풀에서 사용자가 필요한 만큼 할당받아 사용하는 논리적인 파티션임. 운영체제는 이 LV를 일반 파티션처럼 인식하고 사용함. (예: ubuntu-lv)
    • 관련 명령어: lvcreate (LV 생성), lvremove (LV 제거), lvextend (LV 확장), lvreduce (LV 축소), lvs (LV 목록 보기).
    • 작업 내용: 사용자가 lvreduce를 잘못 사용하여 최초의 문제가 발생했으며, 최종적으로는 호스트 OS용 LV를 제거하고 컨테이너용 LV를 새로 생성하는 구조로 변경했음.

2. 파티션 및 파일 시스템 관련 개념

디스크를 나누고 데이터를 저장하는 방식과 관련된 용어임.

  • 파티션 (Partition)
    • 정의: 하드 디스크 드라이브나 솔리드 스테이트 드라이브의 논리적인 구획임. 운영체제는 이 구획을 별개의 디스크처럼 다룰 수 있음.
    • 관련 도구: parted, fdisk
    • 작업 내용: parted를 이용해 기존 LVM이 있던 파티션을 삭제하고, 호스트 OS용(130GB)과 컨테이너 LVM용(360GB) 파티션을 새로 생성했음.
  • UUID (Universally Unique Identifier)
    • 정의: 각 파티션이나 파일 시스템에 부여되는 고유한 식별자임. 디스크 순서가 바뀌어도 시스템이 정확한 파티션을 찾아갈 수 있도록 도와줌.
    • 관련 명령어: blkid
    • 작업 내용: 파티션을 재생성하면서 UUID가 변경된 것이 최초 부팅 실패의 직접적인 원인이었음. 복구 과정에서 blkid로 새 UUID를 확인하여 설정 파일을 수정하는 작업이 필수적이었음.
  • 파일 시스템 (File System)
    • 정의: 운영체제가 파일을 디스크에 저장하고 구성, 탐색, 검색하는 방법을 정의하는 구조임. (예: ext4, vfat)
    • 관련 명령어: mkfs.ext4 (ext4 파일 시스템 생성), resize2fs (ext4 파일 시스템 크기 조정).
    • 작업 내용: resize2fs를 파일 시스템보다 논리 볼륨을 먼저 축소하여 문제가 발생했음. 복구 시에는 mkfs.ext4로 새 파티션을 포맷했음.
  • /etc/fstab
    • 정의: 시스템 부팅 시 자동으로 마운트할 파티션과 파일 시스템의 정보를 담고 있는 설정 파일임. UUID를 기반으로 장치를 지정하는 것이 일반적임.
    • 작업 내용: 파티션 재구성 후, 이 파일에 남아있는 과거의 UUID를 새로운 루트 파티션의 UUID로 수정하는 작업이 필요했음.
  • rsync
    • 정의: 파일과 디렉토리를 복사하고 동기화하는 강력한 유틸리티임. 권한, 소유권 등 속성을 그대로 보존하며 복제할 수 있어 시스템 백업 및 이전에 매우 유용함.
    • 작업 내용: 파티션을 재구성하기 전 시스템 전체를 백업하고, 재구성 후 새 파티션에 시스템을 복원하는 핵심적인 역할을 수행했음.

3. 부팅 프로세스 및 복구 관련 개념

컴퓨터 전원이 켜지고 운영체제가 시작되기까지의 과정, 그리고 이를 복구하는 데 사용되는 용어임.

  • UEFI (Unified Extensible Firmware Interface)
    • 정의: 전통적인 BIOS를 대체하는 최신 펌웨어 인터페이스임. 더 빠른 부팅, 더 큰 디스크 지원, 보안 기능 강화 등의 장점을 가짐.
    • 작업 내용: 사용자의 시스템이 UEFI 기반이었기 때문에, GRUB 복구 시 EFI 파티션을 마운트하는 등 UEFI에 맞는 절차를 따라야 했음.
  • ESP (EFI System Partition)
    • 정의: UEFI 펌웨어가 운영체제 부트 로더를 찾고 로드하는 데 사용하는 특정 파티션임. FAT32(vfat) 파일 시스템으로 포맷되어 있으며, 부트로더 파일(.efi)이 저장됨.
    • 작업 내용: chroot 환경에서 grub-install이 실패한 주된 이유는 이 ESP를 /boot/efi에 마운트하지 않았기 때문임.
  • GRUB (GRand Unified Bootloader)
    • 정의: 대부분의 리눅스 배포판에서 사용하는 부트 로더임. 운영체제 커널을 디스크에서 찾아 메모리에 로드하는 역할을 함.
    • 관련 파일 및 명령어:
      • /etc/default/grub: GRUB의 동작(커널 부팅 옵션, 타임아웃 등)을 제어하는 기본 설정 파일.
      • /etc/grub.d/: update-grub 실행 시 사용되는 스크립트들이 모여있는 디렉토리. 40_custom은 사용자가 직접 메뉴를 추가할 때 사용함.
      • /boot/grub/grub.cfg: 위 설정과 스크립트를 바탕으로 update-grub이 최종적으로 생성하는 실제 부팅 설정 파일. (이 파일을 직접 수정해서는 안 됨.)
      • update-grub: 설정 변경 후, 이를 grub.cfg에 반영하는 명령어.
      • grub-install: GRUB 부트로더 자체를 디스크의 부트 영역에 설치하는 명령어.
  • initramfs (Initial RAM File System)
    • 정의: 리눅스 커널이 부팅 과정 초기에 사용하는 임시 루트 파일 시스템임. 실제 루트 파일 시스템을 마운트하는 데 필요한 드라이버(LVM, RAID 등)를 포함하고 있음.
    • 작업 내용: 부팅 실패 시 최종적으로 진입한 환경이 바로 initramfs 셸이었음. 이는 커널이 필요한 드라이버를 로드했지만, 최종 목적지인 루트 파일 시스템을 찾지 못했음을 의미함.
  • chroot (Change Root)
    • 정의: 특정 디렉토리를 임시 루트 디렉토리로 만들어, 현재 실행 중인 시스템과 격리된 환경에서 작업할 수 있게 하는 명령어임. 시스템 복구 시 Live USB로 부팅한 뒤, 고장 난 시스템의 파티션을 마운트하고 그 안으로 들어가 마치 정상 부팅된 것처럼 작업할 때 필수적으로 사용됨.
    • 작업 내용: GRUB 복구의 모든 과정은 Live USB 환경에서 chroot를 통해 새로운 루트 파티션으로 진입하여 이루어졌음. dev, proc, sys, efi 등을 마운트하는 것은 성공적인 chroot 환경 구축의 핵심임.