Redundant Array of Independent Disks

Today we will  demonstrate how to create a mirrored raid using two identical 120GB hard drives. A quick lsblk will help us identify the devices that we will be working with.

lsblk
NAME    MAJ:MIN    RM    SIZE    RO    TYPE    MOUNTPOINT
sda       8:0       0    100G     0    disk
├─sda1    8:1       0     96G     0    part        /
├─sda2    8:2       0      1K     0    part
└─sda5    8:5       0      4G     0    part      [SWAP]
sdb       8:16      0    120G     0    disk
sdc       8:32      0    120G     0    disk
sr0       11:0      1   1024M     0     rom

As a best practice raw disks should be partitioned before creating an array. Additionally the partitions should be sized smaller than the max total size of the physical disk (a few megabytes will suffice). If the need arises to replace one of the disks in the future then this can prove to be useful since they may not be the exact same size and raid likes to deal with identical sizes.

It is also important to specify the correct partition when constructing the raid as failing to do so will lead to data loss. Accidentally specifying a disk device when you intended to use a partition will wipe out all partitions and data on the disk so ensure you have a recent backup and thread with caution.

Install mdadm if its not already installed.

sudo apt-get install mdadm

Disk Preparation

For this example I have confirmed there is no data on the disks, however I may have used these previously on another raid so first I need to clean the disks.

Zero out any previous superblocks

sudo mdadm --stop /dev/xxx
sudo mdadm --zero-superblock /dev/xxx
sudo mdadm --zero-superblock /dev/xxx

Next I will add a GPT label and carve out a 118GB partition using fdisk.

sudo fdisk /dev/sdb
Command (m for help): g
Created a new GPT disklabel (GUID: 4AF43EA4-8D40-4CA2-A026-D7F050EBC327).

Command (m for help): n
Partition number (1-128, default 1): 
First sector (2048-251658206, default 2048): 
Last sector, +sectors or +size{K,M,G,T,P} (2048-251658206, default 251658206): +118G
Created a new partition 1 of type 'Linux filesystem' and of size 118 GiB.

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks

Command (m for help): F

Unpartitioned space /dev/sdb: 2 GiB, 2146418176 bytes, 4192223 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes

    Start       End Sectors Size
247465984 251658206 4192223   2G

Do the same for /dev/sdc so that you end up with /dev/sdb1 and /dev/sdc1.

lsblk
NAME    MAJ:MIN    RM    SIZE    RO    TYPE    MOUNTPOINT
sda       8:0       0    100G     0    disk 
├─sda1    8:1       0     96G     0    part        /
├─sda2    8:2       0      1K     0    part 
└─sda5    8:5       0      4G     0    part      [SWAP]
sdb       8:16      0    120G     0    disk 
└─sdb1    8:17      0    118G     0    part 
sdc       8:32      0    120G     0    disk 
└─sdc1    8:33      0    118G     0    part 
sr0      11:0       1   1024M     0     rom

Now its time to create the raid array.

sudo mdadm --create --verbose /dev/md0 --level=1 --raid-devices=2 /dev/sdb1 /dev/sdc1
mdadm: Note: this array has metadata at the start and
    may not be suitable as a boot device.  If you plan to
    store '/boot' on this device please ensure that
    your boot-loader understands md/v1.x metadata, or use
    --metadata=0.90
mdadm: size set to 123666432K
mdadm: automatically enabling write-intent bitmap on large array
Continue creating array? y
mdadm: Defaulting to version 1.2 metadata
mdadm: array /dev/md0 started.

Save the raid configuration to the mdadm.conf file. *Note that some distributions store this file simply in /etc/mdadm.conf

sudo mdadm --detail --scan --verbose > /etc/mdadm/mdadm.conf

Merge the configuration of mdadm.conf  into initramfs.

sudo update-initramfs -u

Now we can use fdisk to add a GPT label and create a partition on the new array.

sudo fdisk /dev/md0
Welcome to fdisk (util-linux 2.27.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0xf0a988b7.

Command (m for help): g
Created a new GPT disklabel (GUID: 88B5E7A3-40A8-4766-95A9-F23954CFF866).

Command (m for help): n
Partition number (1-128, default 1): 
First sector (2048-247332830, default 2048): 
Last sector, +sectors or +size{K,M,G,T,P} (2048-247332830, default 247332830): 

Created a new partition 1 of type 'Linux filesystem' and of size 118 GiB.

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

Done correctly these steps will result in a partition named /dev/md0p1.

lsblk
NAME        MAJ:MIN    RM    SIZE    RO    TYPE    MOUNTPOINT
sda           8:0       0    100G     0    disk  
├─sda1        8:1       0     96G     0    part        /
├─sda2        8:2       0      1K     0    part  
└─sda5        8:5       0      4G     0    part      [SWAP]
sdb           8:16      0    120G     0    disk  
└─sdb1        8:17      0    118G     0    part  
  └─md0       9:0       0    118G     0   raid1 
    └─md0p1 259:0       0    118G     0      md    
sdc           8:32      0    120G     0    disk  
└─sdc1        8:33      0    118G     0    part  
  └─md0       9:0       0    118G     0   raid1 
    └─md0p1 259:0       0    118G     0      md    
sr0          11:0       1   1024M     0     rom

Next format the partition using your file system of choice. Here I will use ext4.

sudo mkfs.ext4 /dev/md0p1
mke2fs 1.42.13 (17-May-2015)
Creating filesystem with 30916347 4k blocks and 7733248 inodes
Filesystem UUID: 18ffe443-d1da-49a3-b99c-9e0d20c23b1b
Superblock backups stored on blocks: 
    32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 
    4096000, 7962624, 11239424, 20480000, 23887872

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done

For the last step we will create a mount point and mount the new disk. We will also change ownership to the current user.

sudo mkdir /media/raid1
sudo mount -t ext4 /dev/md0p1 /media/raid1
sudo chown user:user /media/raid1

Use df to display all mounted partitions.

df -h
Filesystem      Size  Used Avail Use% Mounted on
udev            2.0G     0  2.0G   0% /dev
tmpfs           396M  6.2M  390M   2% /run
/dev/sda1        95G  4.6G   86G   6% /
tmpfs           2.0G  132K  2.0G   1% /dev/shm
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
tmpfs           2.0G     0  2.0G   0% /sys/fs/cgroup
tmpfs           396M   52K  396M   1% /run/user/1000
/dev/md0p1      116G   60M  110G   1% /media/raid1

Check the status of the array with one easy command. 

sudo mdadm --detail /dev/md0
/dev/md0:
Version : 1.2
Creation Time : Sun Jul 24 15:19:29 2016
Raid Level : raid1
Array Size : 123666432 (117.94 GiB 126.63 GB)
Used Dev Size : 123666432 (117.94 GiB 126.63 GB)
Raid Devices : 2
Total Devices : 2
Persistence : Superblock is persistent

Intent Bitmap : Internal

Update Time : Sun Jul 24 15:37:24 2016
State : active
Active Devices : 2
Working Devices : 2
Failed Devices : 0
Spare Devices : 0

Name : pc:0 (local to host pc)
UUID : 9e26116f:894ddec4:7216e900:3e3380ae
Events : 125

Number Major Minor RaidDevice State
0 8 17 0 active sync /dev/sdb1
1 8 33 1 active sync /dev/sdc1

Removing the array can be done in 2 steps. First start by Unmounting the partition.

sudo umount /dev/md0p1

Then stop the array

sudo mdadm --stop /dev/md0

To completely destroy the array you will need to zero out the superblock on each of the disks

sudo mdadm --zero-superblock /dev/sdb1
sudo mdadm --zero-superblock /dev/sdc1