Ubuntu Server 20.04 : Btrfs Subvolume 사용 설치(NVMe). v2

원 글과 비교하여, 몇가지 내용이 추가되었다. 원 글은 비교를 위해 그냥 남겨두기로 한다.

  • var(@var) – NoCoW 설정
  • 서브볼륨 세분화
  • /var/lib/dpkg root 로 link(ln -s)

우분투 서버 이미지에는 두가지가 있다. live 가 붙은 것과, 그렇지 않은 것.
서버 설치 프로그램면에선 live/비 live 가 확연히 다른데, 정작 설치된 서버 자체는 미묘한 차이만 있는 듯 하다.

아무튼, 이 글은 ‘Ubuntu Server 20.04.1 Live’ 판을 기준으로 작성했다.


우분투 서버를 설치할 때, 파일시스템을 Btrfs 로 선택할 순 있지만, 서브볼륨을 설정하고 사용할 순 없다. OpenSuse 는 설치프로그램이 정말 완벽하다할 수 있을 정도인데, 우분투는 이 부분이 많이 아쉽다.

이를 극복하려면, 마치 ArchLinux 를 설치할 때처럼 약간의 지식이 필요하다.
이 글에서 간단하게 그 방법을 정리해보기로 한다.
다음 글에서 도움을 얻었다.

Ubuntu Server 18.04 btrfs raid1 (optionnal)


Ubuntu Live Server 디스크 이미지로 설치 진행

우분투 서버 설치 디스크로 부팅한 후 진행하다가, 파티션 작업에서 두가지를 해줘야 한다.

  • / 를 btrfs 로 설정
  • /boot 를 ext4 로 설정. (약 1GB)

디스크 파티션에서, /boot 영역(1GB 정도)을 따로 만드는게 Btrfs 를 사용할 때 여러모로 편리한 면이 있으므로, /boot 파티션을 따로 만들고, 파일시스템은 ext4 로 해준다. (예전에 어떤 책에서는 ext2 를 추천했었는데, 여기선 아예 ext2 를 선택할 수 조차 없다.)

** /boot 파티션(ext4)은 꼭 해야하는 필수사항은 아니다.

UEFI 시스템에서 어떤 파티션이든 하나라도 만들면, EFI(/boot/efi) 파티션은 자동으로 생성된다.

파티션 예.

그리고 끝까지 진행한다.

** 파티션 작업이 은근히 불편하다. 꼭 저 화면에서만 파티션 작업을 해야 한다. (미리 나눠놓은 파티션은 인식은 하지만, 마운트 할당등은 불가능하다.)

계속 진행하다가, 마지막 단계(12/12, 또는 13/13) 가 되었을 때, Reboot Now 를 택하지 말고, Ctrl-Alt-F2(VBox 의 경우, 메뉴 – 입력 – 키보드 – Soft Keyboard) 를 입력한 뒤 두번째 가상 콘솔로 이동한다.

이곳으로 가면, 이제 자유롭게(?) 명령어들을 입력할 수 있다.
좀 더 원활하게 하기 위해 Dvorak 으로 전환한다. (20.04 부터는 아래 작업을 안해도 설치 시에 Dvorak 을 선택했다면 그냥 Dvorak 이 적용된다.)

sudo dpkg-reconfigure keyboard-configuration
... 일련의 설정을 끝내고..
sudo setupcon

setupcon 을 해줘야 변경이 즉각 반영된다.

** 모든 명령은 sudo -i 후 관리자 권한으로 진행한다.

이제 여기서 해야할 일은 다음과 같다.

  • Btrfs 압축을 원한다면, defrag 실행.
  • Btrfs Subvolume 생성
  • 생성된 Subvolume 으로, 설치 프로그램이 만든 파일들 복사
  • 서브볼륨을 사용해 새 루트 시스템 mount 후, chroot 작업
  • fstab 수정
  • 부트로더 수정

복잡해보이지만, ArchLinux 는 저런 식으로 설치해야만 한다. 그것에 비하면 훨씬 간단한(?) 작업이다.

작업을 편하게 하기 위해 sudo -i 로 관리자로 전환한다.
원 글에서는 /target 을 나중에 umount 하라고 되어 있는데, run 디렉토리 때문에 그럴 수가 없었다(오류 발생). 따라서 그냥 umount 는 없이 진행한다.

/target 확인

우분투 서버 설치 프로그램은 /target 디렉토리에, 위에서 작업한 일련의 파티션들을 마운트 한 후 시스템을 구성한다. 따라서 먼저 저 디렉토리를 확인해본다.

ll /target # 잘 설치되어 있는지 확인한다.

그 뒤 lsblk 로 현재 디스크 상황도 파악한다.

설정한 대로, ESP, boot, / 모두 잘 만들어져있다.

Btrfs Compression

만약, Btrfs 의 Compression 기능을 원한다면, 이 시점에서 /target 을 압축해줘야 한다. 후에 fstab 에서 btrfs compression 을 줄 경우, 추후에 생성되는 파일들에 대해서만 압축이 이뤄진다. 따라서, 이왕 할거라면 지금 압축 작업을 해주는게 좋다. (물론, 나중에 시스템이 완성된 후에 해도 된다. 아마도.)

btrfs filesystem defragment -r -v -clzo /target

-clzo 가 핵심인데, 현재 Btrfs 는 zlib, lzo, zstd 세가지 압축 방식을 지원하고 있다. 여기서, 압축효율과 속도를 감안하여 가장 추천(?)하는게 lzo 라고 한다. 기본값은 zlib 이다.
압축 시간은 몇분 걸리지 않는다.
압축이 됐는지 여부는, 나중에 compsize(apt install btrfs-compsize)를 통해 알아볼 수 있다.

Sub Volume 생성

이제 /target 으로 이동하여 Btrfs Subvolume 을 생성한다.
우분투는, @ 을 시스템 루트(/)로, @home 을 /home 으로 사용한다.
헌데, OpenSuse 를 보니 보다 다양한 서브볼륨을 사용하고 있었다. 서브볼륨을 사용한다는 의미는 결국 Snapshot 을 활용한다는 뜻이 되므로, 적절히 추가하는게 효과와 효율면에서 더 나은 선택이 될 수 있다고 본다.
물론, ‘관리’가 가능하다는 전제 하에.

하여, OpenSuse 를 최대한 참고하고, Snapper 를 사용한다는 전제하여 다음과 같이 서브볼륨을 사용하기로 했다.
왼쪽은 서브볼륨, 오른쪽은 마운트 포인트.

  • @ : /
  • @home : /home
  • @var : /var
  • @tmp : /tmp
  • @srv : /srv
  • @root : /root
  • @opt : /opt

OpenSuse 와 다른 점은, usr/local 서브볼륨이 없고, 서브볼륨 구조가 Nested(OpenSuse)가 아닌 Flat 형이라는 점이다.

또, 저 서브볼륨들을 독립된 파티션에 만들 것인지, 아니면 한 파티션에 서브볼륨으로만 만들 것인지도 고민이 됐는데, 그냥 한 파티션만 사용하기로 했다.
만약 파티션이 다르다면, 아래에 서술할 mount 작업에서 적절히 바꿔주기만 하면 되겠다.

cd /target # /target 은, 우분투 설치 프로그램이 작성한 새 시스템 디스크 영역의 / 다.
btrfs subvolume create @
btrfs subvolume create @home
btrfs subvolume create @var
btrfs subvolume create @tmp
btrfs subvolume create @srv
btrfs subvolume create @root
btrfs subvolume create @opt

# set default 는 해주는게 좋다.
btrfs subvolume set-default @

set-default 에 관한 설명은 나중에.

@var NoCoW 설정 및 파일 복사.

@var 에는 NoCoW 를 설정하는게 권장된다고 하므로, 다음과 같이 설정한다.

chattr +C /target/@var

다음 단계에선 파일을 이동(mv)해야 하지만, 여기선 복사를 해줘야 한다. 이유는 NoCoW.
NoCoW 를 시행하려면, 파일을 새로 복사해야하고, 기존의 파일을 그냥 옮기면 아무 효과가 없다.
복사를 한 뒤에는 /var 밑의 파일들은 필요없으므로 지운다.

cp -rp /target/var/. /target/@var
rm -rf /target/var

/var/lib/dpkg 위치 새롭게 설정

Snapper 사용 시 사소한 dpkg 문제가 생길 수 있다. 이를 위해선 이 디렉토리를 루트 Snapshot 에 포함시켜야 하는데, 뭔가 다른 방법이 있을 수도 있겠지만, 간단하게 이런 식으로 처리하기로 했다.

방법 : /var-dpkg 를 만들고, /var/lib/dpkg 를 심볼릭링크로 걸어준다.

실제 작업은 chroot 이후에 해준다.

/target 디렉토리 서브볼륨으로 복사/삭제

위 작업(@var)과 같지만, NoCoW 는 하지 않는다.

현 시점에서 home, opt, srv 는 비어있으므로 복사를 해줄 필요는 없다.
(mv 를 해도 되는데, 그랬을 때 /target/root 아래 있는 .bashrc 등을 어떻게 옮겨야 하는지 방법을 알아내지 못했다. 게다가, 어차피 디렉토리(tmp, root 등)를 지워야 하므로, 그냥 복사후 삭제를 택했다.)

# 복사
cp -rp /target/tmp/. /target/@tmp
cp -rp /target/root/. /target/@root

# 삭제
rm -rf /target/tmp/*
find /target/root -mindepth 1 -delete

/target/root 에는 . 으로 시작하는 파일들이 있는데, 이걸 rm 으로 지우기가 쉽지 않아서 find 를 사용했다.

/target 내부 파일 서브볼륨 @ 으로 이동

이제, /target 안에 생성되어 있는 파일들을, 서브볼륨 @ 안으로 적절히 이동시킨다.
그에 앞서, /target/boot 와 /target/boot/efi 는 마운트 해제해줘야 한다. 이건 독립 파티션이므로, 이동(mv)시킬 필요가 없다.
순서는 efi 를 먼저, boot 를 나중에.

** cdrom 디렉토리는 /target/cdrom 이 아닐 수도 있다. 확인 후 적절히 umount 해줘야 한다.

Unmount 작업

umount /target/boot/efi
umount /target/boot
umount /target/cdrom 또는 umount /target/run/cdrom

파일 이동

mv -t @ b* d* e* h* l* m* o* p* root s* t* u*

run 디렉토리는 mv 가 안된다. 굳이 이 디렉토리를 이동해줘야 할 필요는 없기에 아예 이동시키질 않았다. (예전엔 r* 로 root, run 을 모두 이동시켰지만, root 만 해줬다.)

만약 이동해주면, 아래에서 할 chroot 이후에도 네트웍 관련 작업(apt 등)을 그대로 할 수 있게 된다.
따라서, 이 작업이 필요하다면, 그리고 mv 시 run 디렉토리 관련 오류가 난다면, mv 말고 run 디렉토리를 ‘복사’ 해준다.

cp -rp /target/run /target/@

만약, run 디렉토리가 mv 로 오류없이 이동한다면 그대로 하면 된다.
내 상식으로는, run 디렉토리는 시스템 첫 부팅 시에 새로 만들어지기 때문에, 굳이 남겨놓을 필요는 없다.

서브볼륨을 사용한 /target 재구성

/new-target 을 생성하여 새롭게 시스템을 재구성한다.
워낙엔 /target 을 마운트 해제하고 작업했는데, run 디렉토리로 인해 이게 불가능하게 됐다. (Busy 오류가 나오면서 마운트 해제가 되지 않을 경우가 있다.)

따라서 굳이 umount 를 하지 말고, /new-target 등을 새로 만든 후 그 이하로 아래 작업을 시행하면 된다.

home, opt 는 지금은 mount 해주지 않아도 된다. (현 시점에선 쓸모가 없다.)

또, 원 글에서는 여기에 mount compress 옵션을 줬는데, /target 이 umount 가 되지 않는 상황에선 이 옵션을 줘도 의미가 없다. 게다가 굳이 지금 compress 를 줄 필요도 없다.
나중에 fstab 에서만 옵션을 주면 된다.

cd /
umount /target #(오류가 나면 하지 말고, mkdir /target2 를 만든 뒤 아래를 모두 target 2 로 바꾼다.)
mkdir /target2 #(또는 new-target 등, 원하는대로)

# /, 즉 @ 가 있는 디스크/파티션
mount /dev/nvme0n1p3 /target2 -o subvol=@ # set-default 를 해줬기 때문에 subvol 은 굳이 없어도 되지만.
# /boot 가 있는 디스크/파티션
mount /dev/nvme0n1p2 /target2/boot
# ESP 가 있는 디스크/파티션
mount /dev/nvme0n1p1 /target2/boot/efi

# @var 가 있는 디스크/파티션
mount /dev/nvme0n1p3 /target2/var -o subvol=@var

# 기타 @srv 등은 지금은 필요없다.

mount --bind /proc /target2/proc  
mount --bind /dev /target2/dev  
mount --bind /sys /target2/sys

만약, 위에서 set-default 를 해주지 않았다면, 다음과 같이 @ 를 명시해주는게 여러모로 편하다.

mount /dev/nvme0n1p3 /target -o subvol=@

fstab 수정

이젠, fstab 을 수정해줘야 한다.
chroot 한 뒤 해도 되지만, 지금도 할 수 있다.
lsblk 를 참고하여, fstab 을 아래와 같이 고친다.
맨 먼저 / 를 마운트 해야 하고, 그 후에 home 등을 해주면 된다. (당연하지만, 여기선 반드시 home, opt, var 등 Subvolume 으로 만든 모든 것들을 포함시켜줘야 한다.)

Btrfs 의 현재 제약으로 인해, 마운트 옵션을 서브볼륨별로 달리 줄 수가 없다. 따라서, compress 등 옵션은, 맨 첫 서브볼륨(루트)에만 주고, 나머지엔 써주지 않아도 모두 동일한 옵션이 적용된다.

/boot 를 먼저, /boot/efi 를 나중에 해야 함도 잊지 말 것.

lsblk -f
NAME         FSTYPE   LABEL UUID                                 MOUNTPOINT
nvme0n1                                                          
├─nvme0n1p1  vfat           zzzz                            /target/boot/efi
├─nvme0n1p2  ext4           yyyy                            /target/boot
└─nvme0n1p3  btrfs          xxxx                            /target


vim /target2/etc/fstab
UUID=xxxx 	/ 		btrfs 	defaults,compress=lzo,subvol=@ 0 0
UUID=xxxx 	/home 		btrfs 	subvol=@home 0 0
UUID=xxxx 	/var 		btrfs 	subvol=@var 0 0
UUID=xxxx 	/opt 		btrfs 	subvol=@opt 0 0
UUID=xxxx 	/srv 		btrfs 	subvol=@srv 0 0
UUID=xxxx 	/root 		btrfs 	subvol=@root 0 0
UUID=xxxx 	/tmp		btrfs 	subvol=@tmp 0 0
UUID=yyyy 	/boot 		ext4 	defaults 0 0
UUID=zzzz	/boot/efi 	vfat 	defaults 0 0

밑밥은 끝났다. chroot 로 가상 시스템으로 접근한 뒤, /var/lib/dpkg 를 / 로 이동시켜주고, 링크를 만든 뒤, 부트로더 관련 작업들을 해주면 긴 장정이 끝나게 된다.

chroot 작업

chroot /target2

# dpkg 디렉토리 이동
mkdir /var-dpkg
cp -rp /var/lib/dpkg/* /var-dpkg
rm -rf /var/lib/dpkg
ln -s /var-dpkg /var/lib/dpkg

# 혹시 몰라서.. (/run 이 없으면 부팅 시에 오류 발생 가능성이 있다.)
mkdir /run

# 커널 등록
update-initramfs -u -k all  
grub-install --recheck
update-grub  

** cryptsetup 관련 오류 (Ubuntu 18.04 까지)

update-initramfs 을 하고 나면, cryptsetup 관련 오류가 발생한다.
이것은 ext4 로 설치했을 땐 생기지 않는데, 아마도 Btrfs 관련한 오작동으로 보인다.

cryptsetup 2.0.2 까지 이 버그가 있다고 하는데, 우분투 18.04 까지는 2.0.2 가 제공되고 있기에, 피해갈 방법은 없다.

그냥, cryptsetup 꾸러미를 지워버리는게 가장 단순하지만 효과 만점인 해결책이었는데.. 2020년 2월 현재, 이 꾸러미를 지우면, ubuntu-server 꾸러미도 지워진다.
따라서, 그냥 이 문제는 그냥 무시하고 넘길 수 밖에 없다.
데비안 보고에 따르면, 2.0.3 부터는 해결이 된 모양인데, 우분투 20.04에는 2.2.x 가 들어있었고, 그래서인지 이 문제는 없었다.

이렇게 끝!
exit 후, 원래 콘솔로 돌아가서 reboot 를 택해주면 된다.

Swap 설정?

만약, 스왑파티션을 만들지 않았다면, 설치 관리자는 자연스럽게 /swap.img 를 만든다. Ext4 에선 괜찮지만, Btrfs 에서 이 파일을 그냥 쓰면 여러가지 문제가 발생할 수 있다.

따라서, 다소 귀찮더라도 그냥 Swap Partition 을 만드는게 여러모로 좋은 방법이라고 생각한다.
그게 불가능하다면, 다른 Ext4 파티션에 파일을 만들어 쓰는 방법도 좋다.
Btrfs 에는 가능한한 만들지 않는게 정신건강상 좋고, 굳이 만들려면 ArchLinux 문서를 참고하면 될텐데.. 글쎄?

설치가 끝나고 할 일!

위 설치에서 약간 찌꺼기(?)가 남는다. FS_Root(파일시스템 root)에 run, cdrom 디렉토리가 지워지지 않고 그대로 남아있게 된다.

이건 그냥 부팅해서는 볼 수가 없고, 이 디스크를 다시 마운트 해줘야 볼 수 있는데, subvolume set-default 를 했다면, 마운트 시에 subvolid=5 를 추가해줘야만 이 디렉토리들을 볼 수 있게 된다.

이 작업은, 새로 만든 시스템으로 부팅한 후 해야 한다.

sudo mount /dev/xxxx /mnt -o subvolid=5

ll /mnt
drwxr-xr-x 1 root root 238 2020-01-29 00:30 @
drwxr-xr-x 1 root root  30 2020-01-16 17:22 @home
drwxr-xr-x 1 root root   0 2020-01-13 22:37 @opt
drwxr-xr-x 1 root root 128 2020-01-22 15:57 @var
drwxr-xr-x 1 root root 128 2020-01-22 15:57 @root
drwxr-xr-x 1 root root 128 2020-01-22 15:57 @srv
drwxr-xr-x 1 root root 128 2020-01-22 15:57 @tmp
drwxr-xr-x 1 root root   0 2020-01-13 22:37 cdrom
drwxr-xr-x 1 root root 128 2020-01-22 15:57 run

이런 식으로 cdrom 과 run 이 남아있을 가능성이 있다. 불필요하므로 지워준다.

또, cloud-init 꾸러미도 (적어도 내겐) 불필요하다. 저게 뭔지 설명을 읽어봤음에도 이해를 못하겠다.

sudo apt purge cluod-init --autoremove

이후, 여러가지 작업이 필요하겠지만, 로캘(locale) 설정, 시간대 설정이 가장 최우선이다.

로캘설정은 몇가지 방법이 있겠지만, dpkg-reconfigure 를 이용하는게 편하다.

sudo dpkg-reconfigure locales

시간대 설정도 같은 명령으로 가능하다.

sudo dpkg-reconfigure tzdata

이제 서버를 원활하게 사용하기 위한 세부 설정이 남아있다!!

안녕하세요. 글 남겨주셔서 고맙습니다.