새 하드디스크를 리눅스에 달면 커널이 블록 장치로 보여 준다. 그다음은 파티션을 만들고, 파일시스템을 만들고, 부팅 때마다 같은 자리에 붙이는 일이다. 파일시스템을 만드는 명령은 그 장치의 내용을 지운다. 아래 예시의 `/dev/sdX`는 자리표시자다. `lsblk`에 나온 새 디스크의 이름으로 바꾼다. 루트(`/`)가 올라간 디스크에는 실행하지 않는다.

이 글의 명령은 우분투 22.04, 커널 5.15, GNU parted 3.4, e2fsprogs 1.46.5 기준으로 확인했다. 다른 배포판은 패키지 이름만 다를 수 있다.

어떤 디스크인지 먼저 가른다

디스크를 연결하고 전원을 넣은 뒤 장치 목록을 본다.

Bash
lsblk -o NAME,SIZE,TYPE,FSTYPE,LABEL,UUID,MOUNTPOINT,MODEL,TRAN
findmnt /

`MOUNTPOINT`가 `/`인 줄의 부모가 지금 부팅한 디스크다. 새로 단 디스크는 파일시스템과 마운트 위치가 비어 있고, 용량과 `MODEL`이 제품과 맞다. `TRAN`이 sata, nvme, usb 중 무엇인지도 같이 본다.

SATA와 SCSI 디스크는 `/dev/sda`, `/dev/sdb`처럼 붙고 파티션은 `/dev/sdb1`이다. NVMe는 `/dev/nvme0n1`이고 첫 파티션은 `/dev/nvme0n1p1`이다. `nvme0n11`처럼 숫자를 붙여 쓰지 않는다. USB 외장도 `/dev/sdX`로 보이는 경우가 많다.

이름 끝의 문자는 인식 순서라서 디스크를 추가하면 바뀔 수 있다. 작업 중에는 `/dev/disk/by-id/`의 모델과 시리얼이 들어간 경로를 같이 확인한다.

Bash
ls -l /dev/disk/by-id/

목록에 안 보이면 케이블, 전원, 디스크 슬롯을 확인하고 `dmesg | tail`에 인식 오류가 있는지 본다. 가상머신과 클라우드는 하이퍼바이저에서 디스크를 붙여야 게스트의 `lsblk`에 나타난다. 디스크 용량만 키운 경우에는 파티션과 파일시스템이 자동으로 커지지 않는다. 그 차이는 리눅스와 파티션 글에 적어 두었다.

파티션 테이블

2TiB를 넘는 디스크와 새 디스크는 GPT를 쓴다. MBR(`msdos`)은 주 파티션이 네 개이고, 512바이트 섹터에서는 2TiB를 넘기 어렵다.

파티션 테이블을 만드는 명령은 그 디스크의 기존 파티션 정보를 지운다.

Bash
sudo parted --align optimal /dev/sdX --script mklabel gpt
sudo parted --align optimal /dev/sdX --script mkpart data 1MiB 100%
sudo parted /dev/sdX --script print
sudo partprobe /dev/sdX
lsblk /dev/sdX

시작을 `1MiB`로 두면 4KiB 섹터 디스크에서도 정렬이 맞다. `100%`는 디스크 끝까지다. `mkpart`의 이름은 파티션 이름일 뿐이고, 파일시스템을 만들지 않는다. 파일시스템은 다음 절의 `mkfs`가 만든다.

가운데를 나누려면 끝을 용량으로 적는다. 아래는 앞 8GiB를 스왑으로 남기고 나머지를 데이터로 쓰는 예다.

Bash
sudo parted --align optimal /dev/sdX --script mklabel gpt \
  mkpart swap 1MiB 8GiB \
  mkpart data 8GiB 100%
sudo parted /dev/sdX --script set 1 swap on

파티션 없이 디스크 전체에 `mkfs`를 실행할 수도 있다. 리눅스만 쓰는 데이터 디스크에서는 동작한다. 다른 운영체제와 같이 보거나 나중에 스왑을 나눌 계획이면 파티션을 만든다. ZFS는 예외로, 풀에 디스크 전체를 넣는 방식이 기본이다.

예전에 쓰던 시그니처가 남아 `mkfs`가 거절하면, 그 장치가 새 디스크가 맞는지 다시 본 뒤에만 시그니처를 지운다.

Bash
sudo wipefs --all /dev/sdX1

공통으로 붙이고 부팅 때 유지하기

파일시스템을 만든 뒤에는 마운트 지점을 만들고 한 번 붙여 본다.

Bash
sudo mkdir -p /data
sudo mount /dev/sdX1 /data
findmnt /data
df -hT /data

새 파일시스템의 최상위 소유자는 root다. 일반 계정으로 쓰려면 소유자를 바꾼다.

Bash
sudo chown "$USER:$USER" /data

`/dev/sdX1`을 `/etc/fstab`에 그대로 적으면 장치 문자가 바뀔 때 다른 디스크를 집거나 부팅이 멈출 수 있다. UUID를 적는다.

Bash
sudo blkid /dev/sdX1

`/etc/fstab`을 고치기 전에 복사해 둔다.

Bash
sudo cp /etc/fstab /etc/fstab.bak

한 줄의 칸은 장치, 마운트 지점, 종류, 옵션, 덤프, 검사 순이다. 덤프 칸은 0으로 둔다. 검사 칸은 ext4 데이터 파티션은 2, 루트는 1이다. XFS, Btrfs, 스왑, NTFS, FAT는 0으로 둔다. 이유는 각 절에 적는다.

Bash
UUID=실제-uuid를-붙여-넣는다  /data  ext4  defaults,noatime  0  2

저장한 뒤 재부팅 전에 표가 맞는지 확인한다.

Bash
sudo findmnt --verify
sudo mount -a
findmnt /data

`nofail` 옵션을 넣으면 그 디스크가 없어도 부팅이 계속된다. USB처럼 항상 꽂혀 있지 않은 디스크에 쓴다. 항상 있어야 하는 데이터 디스크는 `nofail` 없이 두고, UUID를 확인한 뒤에 재부팅한다.

SSD와 NVMe는 비운 블록을 디스크에 알리는 TRIM이 있다. 우분투는 `fstrim.timer`가 주기적으로 실행하는 구성이 많다. 매번 삭제할 때 TRIM을 보내는 `discard` 마운트 옵션보다 부하가 적다.

Bash
systemctl status fstrim.timer

ext4

리눅스만 쓰는 일반 데이터 디스크의 기본 선택이다. 저널이 있고, 마운트된 상태에서 키울 수 있고, 분리한 뒤에는 줄일 수도 있다. 이 시스템의 `mke2fs.conf` 기본 블록 크기는 4096바이트다. x86에서 커널이 마운트하는 블록 크기는 페이지 크기인 4KiB 이하다.

Bash
sudo mkfs.ext4 -L data /dev/sdX1

기본으로 용량의 5%를 root 전용으로 남긴다. 로그가 있는 시스템 파티션에는 의미가 있다. 수 TB 데이터 디스크에서는 너무 크다. 1%로 만들거나 나중에 바꾼다.

Bash
sudo mkfs.ext4 -m 1 -L data /dev/sdX1
sudo tune2fs -m 1 /dev/sdX1

아이노드는 기본으로 16KiB당 하나다. 용량은 남았는데 파일을 만들지 못하면 `df -i`로 아이노드 소진을 확인한다. 큰 파일만 둘 디스크는 만들 때 아이노드를 줄인다. `-T largefile`은 1MiB당 하나, `-T largefile4`는 4MiB당 하나다. 만든 뒤에는 아이노드 수를 늘릴 수 없다.

Bash
sudo mkfs.ext4 -T largefile -m 1 -L data /dev/sdX1

마운트 옵션은 `defaults,noatime`이면 충분하다. `noatime`은 읽을 때마다 접근 시각을 기록하지 않는다. 오류가 났을 때 읽기 전용으로 되돌리려면 `errors=remount-ro`를 더한다. 데이터 디스크가 읽기 전용이 되면 서비스는 쓰기에 실패하지만, 잘못된 상태로 계속 쓰는 것보다는 발견하기 쉽다.

Bash
UUID=실제-uuid  /data  ext4  defaults,noatime,errors=remount-ro  0  2

검사는 마운트를 해제한 뒤에 한다.

Bash
sudo umount /data
sudo e2fsck -f /dev/sdX1
sudo mount /data

용량을 키울 때는 파티션을 먼저 늘리고 파일시스템을 그 크기에 맞춘다. 마운트된 ext4도 키울 수 있다. `resize2fs`에 크기를 생략하면 파티션 끝까지 늘린다.

Bash
sudo parted /dev/sdX --script resizepart 1 100%
sudo partprobe /dev/sdX
sudo resize2fs /dev/sdX1

줄일 때는 순서가 반대다. 마운트를 해제하고, 검사하고, 파일시스템을 먼저 줄인 다음 파티션을 줄인다. 파티션을 먼저 줄이면 끝을 잘라 버린다.

Bash
sudo umount /data
sudo e2fsck -f /dev/sdX1
sudo resize2fs /dev/sdX1 100G
sudo parted /dev/sdX --script resizepart 1 100G

4KiB 블록에서 파일 하나의 최대 크기는 16TiB다. 그 한계에 닿는 용도라면 XFS나 Btrfs를 검토한다. ext4 최상위에는 `lost+found` 디렉터리가 생긴다. 검사 중 복구된 조각이 여기로 들어간다.

ext3는 저널이 있는 ext2이고, ext2는 저널이 없다. `mkfs.ext3`, `mkfs.ext2`로 만들 수 있고 ext4 드라이버가 마운트한다. 새 디스크에는 ext4를 쓴다. ext3는 아주 오래된 커널만 읽어야 할 때 남긴다.

XFS

큰 파일과 병렬 입출력에 맞다. 키우는 것은 마운트된 상태에서 하고, 줄이는 기능은 없다. 한번 잡은 크기를 나중에 줄일 계획이면 ext4나 Btrfs가 맞다.

Bash
sudo mkfs.xfs -L data /dev/sdX1

이미 파일시스템 시그니처가 있으면 `mkfs.xfs`는 멈춘다. 지우고 새로 만들 의사가 있을 때만 `-f`를 붙인다.

Bash
sudo mkfs.xfs -f -L data /dev/sdX1

fstab의 검사 칸은 0이다. `fsck.xfs`는 실제로 고치지 않고 성공만 돌려준다. 복구는 마운트를 해제한 뒤 `xfs_repair`로 한다. 마운트된 채 실행하면 파일시스템이 더 어긋날 수 있다.

Bash
UUID=실제-uuid  /data  xfs  defaults,noatime  0  0
Bash
sudo umount /data
sudo xfs_repair /dev/sdX1

`xfs_repair -L`은 저널을 비우고 진행한다. 저널에만 있던 최근 수정이 사라질 수 있어서, 일반 복구가 실패하고 백업이 없을 때의 마지막 수단이다.

키우기는 파티션을 늘린 뒤, 마운트된 경로에 `xfs_growfs`를 실행한다.

Bash
sudo parted /dev/sdX --script resizepart 1 100%
sudo partprobe /dev/sdX
sudo mount /data
sudo xfs_growfs /data

레이블과 UUID 변경, 정보 확인은 다음으로 한다. 레이블 변경은 마운트를 해제한 상태에서 한다.

Bash
xfs_info /data
sudo umount /data
sudo xfs_admin -L data /dev/sdX1

Btrfs

스냅샷, 압축, 서브볼륨, 디스크를 나중에 추가하는 구성이 필요할 때 쓴다. 한 대의 디스크에서 메타데이터는 기본이 DUP이라 같은 디스크에 메타데이터 사본을 둔다. 데이터 사본은 아니다. DUP는 디스크 전체 고장을 막지 못한다.

Bash
sudo mkfs.btrfs -L data /dev/sdX1

디스크가 둘 이상이면 기본 프로파일이 버전에 따라 달라질 수 있다. 만들 때 프로파일을 직접 적는다. 두 디스크에 사본을 두려면 데이터와 메타데이터 모두 raid1이다. raid1은 용량이 절반이 되고, 디스크 하나가 죽어도 읽힌다.

Bash
sudo mkfs.btrfs -L data -d raid1 -m raid1 /dev/sdX1 /dev/sdY1

raid5와 raid6는 쓰기 구멍과 복구 쪽 문제가 남아 있다. 새 데이터 디스크로 고르지 않는다.

fstab 검사 칸은 0이다. `fsck.btrfs`도 실제 복구를 하지 않는다. 일상 점검은 마운트된 상태에서 스크럽이다. `btrfs check`는 마운트를 해제한 뒤의 점검이고, `--repair`는 상태를 더 나쁘게 만들 수 있어 원인을 알기 전에는 쓰지 않는다.

Bash
UUID=실제-uuid  /data  btrfs  defaults,noatime,compress=zstd  0  0

`compress=zstd`는 새로 쓰는 블록을 압착한다. 이미 써 둔 파일은 다시 쓰지 않으면 그대로다.

서브볼륨은 파일시스템 안의 독립된 디렉터리 트리이다. 스냅샷의 단위가 된다.

Bash
sudo btrfs subvolume create /data/work
sudo btrfs subvolume snapshot /data/work /data/snap-work

같은 디스크 안의 스냅샷은 그 디스크가 죽으면 같이 사라진다. 백업은 다른 디스크나 다른 머신에 둔다.

키우고 줄이는 명령은 파티션과 별개다. 파티션을 키운 뒤 파일시스템을 파티션 끝까지 맞춘다. 줄일 때는 파일시스템을 먼저 줄인다.

Bash
sudo btrfs filesystem resize max /data
sudo btrfs filesystem resize -10G /data

공간을 보는 명령은 `df`만으로는 부족하다. 데이터와 메타데이터가 청크 단위로 잡히기 때문이다.

Bash
sudo btrfs filesystem df /data
sudo btrfs filesystem usage /data
sudo btrfs scrub start /data

스왑 파일을 Btrfs 위에 두려면 Copy-on-Write를 끄지 않으면 안 된다. 스왑은 별도 파티션이 단순하다.

스왑

메모리가 부족할 때 디스크를 메모리 보조로 쓴다. 최대 절전을 쓰면 램 크기 이상의 스왑이 필요하다. 스왑은 파일시스템 종류가 `swap`이고 마운트 지점 칸은 `none`이다.

Bash
sudo mkswap -L swapdisk /dev/sdX1
sudo swapon /dev/sdX1
swapon --show
Bash
UUID=실제-uuid  none  swap  sw  0  0

파일로 만들 때는 ext4나 XFS 위에 둔다. 권한을 소유자만 읽게 잠근다.

Bash
sudo fallocate -l 8G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
Bash
/swapfile  none  swap  sw  0  0

끄고 지울 때는 `sudo swapoff /swapfile` 다음에 파일을 지운다.

FAT32

`mkfs.vfat`로 만든다. UEFI 부팅 파티션(EFI 시스템 파티션)이 이 형식이다. 이미 부팅에 쓰는 EFI 파티션을 데이터 디스크라고 포맷하면 부팅이 깨진다.

Bash
sudo mkfs.vfat -F 32 -n SHARE /dev/sdX1

파일 하나의 한계는 4GiB다. 유닉스 소유자와 권한이 없다. 마운트 옵션의 `uid`, `gid`, `umask`가 그 디스크의 모든 파일에 일괄 적용된다.

Bash
UUID=대문자-ID  /mnt/share  vfat  uid=1000,gid=1000,umask=022,nofail  0  0

FAT와 NTFS의 UUID는 영문 대문자를 유지한다. ext4 UUID처럼 소문자로 바꾸지 않는다. 리눅스 데이터 디스크보다는 펌웨어 파티션이나 작은 공유 장치에 남긴다.

exFAT

4GiB보다 큰 파일을 윈도우, 맥, 리눅스가 같이 봐야 할 때 쓴다. 유닉스 권한은 없다. 도구는 기본 설치가 아니면 `exfatprogs`에 있다. 커널 5.15에는 exFAT 드라이버가 들어 있다.

Bash
sudo apt install exfatprogs
sudo mkfs.exfat -n SHARE /dev/sdX1
Bash
UUID=대문자-ID  /mnt/share  exfat  uid=1000,gid=1000,umask=022,nofail  0  0

검사는 `fsck.exfat`다. 패키지를 설치한 뒤에 생긴다.

NTFS

윈도우가 쓰는 디스크를 리눅스에서 읽거나 쓸 때 쓴다. 이 커널에는 커널 드라이버 `ntfs3`가 있고, 함께 설치된 `ntfs-3g`도 있다. 새로 마운트할 때는 `ntfs3`를 적는다.

윈도우의 빠른 시작이나 최대 절전은 디스크를 완전히 닫지 않은 채로 둔다. 그 상태에서 리눅스가 읽기 쓰기로 마운트하면 윈도우 쪽 데이터가 깨질 수 있다. 윈도우를 완전히 종료한 뒤에 붙인다. 확신이 없으면 읽기 전용으로 마운트한다.

Bash
sudo mount -t ntfs3 -o ro /dev/sdX1 /mnt/win

리눅스에서 새 NTFS를 만들 수는 있다. `-f`는 빠른 포맷이다. 윈도우와 오래 같이 쓸 디스크는 윈도우에서 포맷하는 편이 속성 차이가 적다.

Bash
sudo mkfs.ntfs -f -L windata /dev/sdX1
Bash
UUID=대문자-ID  /mnt/win  ntfs3  uid=1000,gid=1000,umask=022,nofail  0  0

`ntfsfix`는 더티 플래그를 다루고 기본 일관성을 본다. 윈도우 `chkdsk`를 대신하지 않는다. 파일시스템 구조가 손상되었으면 윈도우에서 검사한다.

F2FS

플래시 저장장치용 파일시스템이다. SD카드, eMMC, USB 스틱, SSD에 맞춰져 있고 회전 하드디스크용은 아니다. 도구 패키지는 `f2fs-tools`다.

Bash
sudo apt install f2fs-tools
sudo mkfs.f2fs -l data /dev/sdX1
Bash
UUID=실제-uuid  /data  f2fs  defaults,noatime,nofail  0  0

하드디스크에 일반 데이터를 둘 파일시스템으로 고르지 않는다. ext4, XFS, Btrfs 중에 고른다.

ZFS

풀 단위로 디스크를 묶고, 스크럽과 압축, 스냅샷을 파일시스템 기능으로 가진다. 우분투에서는 `zfsutils-linux` 패키지가 명령과 커널 모듈을 설치한다. 기본 설치에는 없다. 파티션을 만들지 않고 디스크 전체를 풀에 넣는 구성이 일반적이다. 장치 문자가 바뀌지 않도록 `by-id` 경로를 쓴다.

Bash
sudo apt install zfsutils-linux
sudo zpool create -o ashift=12 tank /dev/disk/by-id/ata-모델_시리얼
sudo zfs create tank/data
sudo zfs set compression=zstd tank
sudo zfs set atime=off tank

`ashift=12`는 4KiB 섹터에 맞춘 값이다. 512e 디스크도 물리 섹터는 4KiB인 경우가 많아서 12로 둔다. 풀을 만든 뒤에는 ashift를 바꿀 수 없다.

`zpool create`는 그 디스크를 풀 레이블로 덮어쓴다. 마운트는 ZFS가 맡으며 기본 경로는 `/tank`와 `/tank/data`다. fstab에 또 적으면 부팅 때 두 번 붙이려 해서 꼬일 수 있다. 부팅 시 가져오기는 ZFS 서비스가 한다.

Bash
zpool status
zpool scrub tank
zfs list

미러는 디스크 둘에 같은 사본을 둔다. 용량은 하나 분이다.

Bash
sudo zpool create -o ashift=12 tank mirror \
  /dev/disk/by-id/ata-첫번째 \
  /dev/disk/by-id/ata-두번째

vdev를 줄이는 것은 미러에서 디스크를 빼는 수준을 빼고는 사실상 안 된다. 용량 계획은 만들기 전에 끝낸다. 풀을 다른 머신에서 보려면 `zpool import`를 쓴다.

예전에 쓰이던 파일시스템

JFS는 `jfsutils`의 `mkfs.jfs`로 만든다. NILFS2는 연속 스냅샷이 목적이고 `nilfs-tools`에 도구가 있다. ReiserFS는 `reiserfsprogs`가 남아 있어도 새 커널에서 빠지는 쪽이다. 새 하드디스크에는 이 셋을 고르지 않는다. 이미 그 형식으로 쓰던 디스크를 읽어야 할 때만 패키지를 설치한다.

디스크 암호화

파일시스템을 만들기 전에 LUKS로 감싸면 디스크를 떼어 다른 기계에 달아도 비밀번호 없이는 내용이 보이지 않는다. 패키지는 `cryptsetup`이다. 포맷은 그 파티션의 내용을 지운다.

Bash
sudo cryptsetup luksFormat /dev/sdX1
sudo cryptsetup open /dev/sdX1 data
sudo mkfs.ext4 -m 1 -L data /dev/mapper/data

`/etc/crypttab`에는 암호화 파티션의 UUID를 적는다. `blkid`에서 `TYPE="crypto_LUKS"`인 줄이다. 파일시스템의 UUID가 아니다.

Bash
data  UUID=luks-파티션-uuid  none  luks

fstab에는 풀린 장치 이름을 적는다.

Bash
/dev/mapper/data  /data  ext4  defaults,noatime  0  2

부팅 때 비밀번호를 묻는다. 비밀번호를 잃으면 데이터를 열 수 없다. 복구 키를 다른 곳에 보관해 둔다.

고르는 기준

- 리눅스만 쓰는 데이터 디스크이고 나중에 줄일 수도 있으면 ext4다. - 큰 파일을 두고 줄이지 않을 서버 데이터면 XFS다. - 스냅샷과 압축, 서브볼륨이 필요하면 Btrfs다. raid5와 raid6는 쓰지 않는다. - 디스크 풀, 스크럽, 압축을 저장 장치 수준에서 운영하면 ZFS다. 패키지와 모듈이 따로 필요하다. - 윈도우와 4GiB 넘는 파일을 주고받으면 exFAT다. - 이미 윈도우가 NTFS로 쓰는 디스크는 포맷하지 않고 `ntfs3`로 마운트한다. 빠른 시작을 끈 상태여야 한다. - FAT32는 UEFI 부팅 파티션과 4GiB 이하 파일의 호환용이다. - 메모리 보조는 스왑 파티션이나 스왑 파일이다. - SD카드와 USB 플래시는 F2FS를 검토할 수 있다. 회전 디스크에는 쓰지 않는다.

포맷이 끝나면 `lsblk -f`와 `findmnt /data`, `df -hT /data`로 종류, UUID, 마운트 위치, 용량이 의도한 것과 같은지 확인한다. fstab을 고쳤으면 재부팅 전에 `findmnt --verify`와 `mount -a`를 통과한 상태여야 한다.