summaryrefslogtreecommitdiff
path: root/content/devops/resizing_root_partition.rst
blob: e07f7063892ff9facab7e6800f18b7eb1135b1b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
Note to Self: Growing the Root File System on First Boot
########################################################

:date: 2019-02-16 22:13 +0530
:slug: grow_rootfs
:tags: resize2fs, notetoself
:author: copyninja
:summary: Post discusses about expanding root file system of a system to full
          extent of available space in device.

These 2 are the use cases I came across for expanding root file system.

1. RaspberryPi images which comes in smaller image size like 1GB which you write
   bigger size SD cards like 32GB but you want to use full 32GB of space when
   system comes up.

2. You have a VM image which is contains basic server operating system and you want
   to provision the same as a VM with much larger size root file system.

My current use case was second but I learnt the trick from 1, that is the
`RaspberryPi3 image spec <https://github.com/Debian/raspi3-image-spec>`_ by
Debian project.

Idea behind the expanding root file system is first expanding the root file
system to full available size and then run resize2fs on the expanded partition
to grow file system. *resize2fs* is a tool specific for ext2/3/4 file system.
But this needs to be done before the file system is mounted.

Here is my modified script from `raspi3-image-spec repo
<https://github.com/Debian/raspi3-image-spec/blob/master/rpi3-resizerootfs>`_.
Only difference is I've changed the logic of extracting root partition device to
my need, and of course added comments based on my understanding.

.. code:: shell

   #!/bin/sh

   # Just extracts root partition and removes partition number to get the device
   # name eg. /dev/sda1 becomes /dev/sda
   roottmp=$(lsblk -l -o NAME,MOUNTPOINT | grep '/$')
   rootpart=/dev/${roottmp%% */}
   rootdev=${rootpart%1}

   # Use sfdisk to extend partition to all available free space on device.
   flock $rootdev sfdisk -f $rootdev -N 2 <<EOF
   ,+
   EOF

   sleep 5

   # Wait for all pending udev events to be handled
   udevadm settle

   sleep 5

   # detect the changes to partition (we extended it).
   flock $rootdev partprobe $rootdev

   # remount the root partition in read write mode
   mount -o remount,rw $rootpart

   # Finally grow the file system on root partition
   resize2fs $rootpart

   exit 0fs


raspi3-image-spec uses `sytemd service
<https://github.com/Debian/raspi3-image-spec/blob/master/rpi3-resizerootfs.service>`_
file to execute this script just before any file system is mounted. This is done
by a making service execute before *local-fs.pre* target. From the man page for
*systemd.special*

   local-fs.target
       systemd-fstab-generator(3) automatically adds dependencies of type
       Before= to all mount units that refer to local mount points for this
       target unit. In addition, it adds dependencies of type Wants= to this
       target unit for those mounts listed in /etc/fstab that have the auto
       mount option set.

Testing with VM
===============

*raspi3-image-spec* is well tested, but I wanted to make sure this works with my
use case for VM. Since I didn't have any spare physical disks to experiment with
I used kpartx with raw file images. Here is what I did

1. Created a stretch image using vmdb2 with grub installed. Image size is 1.5G
2. I created another raw disk using fallocate of 4G size.
3. I created a partition on 4G disk.
4. Loop mounted the disk and wrote 1G image on it using dd
5. Finally created a VM using virt-install  with this loop mounted device as
   root disk.

Below is my vmdb configuration yml again derived from `raspi3-image-spec
<https://github.com/Debian/raspi3-image-spec/blob/master/raspi3.yaml>`_ one with
some modifications to my needs.

.. code:: yaml

   # See https://wiki.debian.org/RaspberryPi3 for known issues and more details.
   steps:
   - mkimg: "{{ output }}"
     size: 1.5G

   - mklabel: msdos
     device: "{{ output }}"

   - mkpart: primary
     device: "{{ output }}"
     start: 0%
     end: 100%
     tag: /

   - kpartx: "{{ output }}"

   - mkfs: ext4
     partition: /
     label: RASPIROOT

   - mount: /

   - unpack-rootfs: /

   - debootstrap: stretch
     mirror: http://localhost:3142/deb.debian.org/debian
     target: /
     variant: minbase
     components:
     - main
     - contrib
     - non-free
     unless: rootfs_unpacked

   # TODO(https://bugs.debian.org/877855): remove this workaround once
   # debootstrap is fixed
   - chroot: /
     shell: |
       echo 'deb http://deb.debian.org/debian buster main contrib non-free' > /etc/apt/sources.list
       apt-get update
     unless: rootfs_unpacked

   - apt: install
     packages:
     - ssh
     - parted
     - dosfstools
     - linux-image-amd64
     tag: /
     unless: rootfs_unpacked

   - grub: bios
     tag: /

   - cache-rootfs: /
     unless: rootfs_unpacked

   - shell: |
        echo "experimental" > "${ROOT?}/etc/hostname"

        # '..VyaTFxP8kT6' is crypt.crypt('raspberry', '..')
        sed -i 's,root:[^:]*,root:..VyaTFxP8kT6,' "${ROOT?}/etc/shadow"

        sed -i 's,#PermitRootLogin prohibit-password,PermitRootLogin yes,g' "${ROOT?}/etc/ssh/sshd_config"

        install -m 644 -o root -g root fstab "${ROOT?}/etc/fstab"

        install -m 644 -o root -g root eth0 "${ROOT?}/etc/network/interfaces.d/eth0"

        install -m 755 -o root -g root rpi3-resizerootfs "${ROOT?}/usr/sbin/rpi3-resizerootfs"
        install -m 644 -o root -g root rpi3-resizerootfs.service "${ROOT?}/etc/systemd/system"
        mkdir -p "${ROOT?}/etc/systemd/system/systemd-remount-fs.service.requires/"
        ln -s /etc/systemd/system/rpi3-resizerootfs.service "${ROOT?}/etc/systemd/system/systemd-remount-fs.service.requires/rpi3-resizerootfs.service"

        install -m 644 -o root -g root rpi3-generate-ssh-host-keys.service "${ROOT?}/etc/systemd/system"
        mkdir -p "${ROOT?}/etc/systemd/system/multi-user.target.requires/"
        ln -s /etc/systemd/system/rpi3-generate-ssh-host-keys.service "${ROOT?}/etc/systemd/system/multi-user.target.requires/rpi3-generate-ssh-host-keys.service"
        rm -f ${ROOT?}/etc/ssh/ssh_host_*_key*

     root-fs: /

   # Clean up archive cache (likely not useful) and lists (likely outdated) to
   # reduce image size by several hundred megabytes.
   - chroot: /
     shell: |
        apt-get clean
        rm -rf /var/lib/apt/lists

   # TODO(https://github.com/larswirzenius/vmdb2/issues/24): remove once vmdb
   # clears /etc/resolv.conf on its own.
   - shell: |
        rm "${ROOT?}/etc/resolv.conf"
     root-fs: /

I could not run with vmdb2 installed from Debian archive, so I cloned
raspi3-image-spec and used vmdb2 submodule from it.

.. code:: shell

   fallocate -l 4G rootdisk.img
   # Create one partition with full disk
   sfdisk -f rootdisk.img <<EOF
   ,+
   EOF
   kpartx -av rootdisk.img # mounts on /dev/loop0 for me
   dd if=vmdb.img of=/dev/loop0
   sudo virt-install --name experimental --memory 1024 --disk path=/dev/loop0 --controller type=scsi,model=virtio-scsi --boot hd --network bridge=lxcbr0

Once VM booted I could see the root file system is 4G of size instead of 1.5G it
was after using dd to write image on to it. So success!.