LVM provides a layer of abstraction over physical storage and allows you to create logical storage volumes. With a logical volume, there is no restriction to physical disk sizes. In addition, the hardware storage configuration is hidden from the software enabling for ease of resizing and moving the need to stop applications or unmount the file systems.

Some of the benefits of Logical volumes are:

  • Easy naming of devices: Logical storage volumes can be managed in user-defined and custom named groups.
  • Disk striping: You can create logical volume that stripes data across two or more disks giving you better throughput.
  • Mirroring of volumes: With logical volumes you can provide a convenient way to configure data mirroring
  • Ease of resizing storage pools: Being able to extend logical volumes or reduce logical volumes in size without reformatting and repartitioning underlying disk devices
  • Flexibility in capacity extension: You can extend file systems across multiple disks through disks aggregation and partitioning into a single logical volume.
  • And much more

In this article we look at how you can create a logical volume using Ansible playbook with the following considerations:

  • Creating a logical volume in an existing volume group.
  • Creating PV, VG then Logical Volume(LV)

LVM structure:

  • Physical Volumes: Block devices (physical disks or partitions) initialized.
  • Volume Group: Physical volumes combined into Volume group. It represents a single storage pool of available storage space.
  • Logical Volume: Created on top of Volume Group (Similar to creating simple partitions on disk partition)

1. Create Logical Volume with existing Volume Group

Here is a sample playbook that can be modified when creating a logical volume from existing volume group.

---
- name: Playbook to create LV, Filesystem and Mount it
  hosts: myservers
  remote_user: debian
  become: yes
  become_method: sudo
  vars:
    vg_name: vg0
    lv_name: container_data
    lv_size: 20g
    fs_type: xfs
    mount_path: /data
  tasks:
    - name: Create Logical Volume for data persistence
      community.general.lvol:
        vg: "{{ vg_name }}"
        lv: "{{ lv_name }}"
        size: "{{ lv_size }}"

    - name: Create filesystem on LV 
      community.general.filesystem:
        fstype: "{{ fs_type }}"
        dev:  /dev/mapper/{{ vg_name }}-{{ lv_name }}

    - name: Get LV UUID
      ansible.builtin.command: lsblk /dev/mapper/{{ vg_name }}-{{ lv_name }} -no UUID
      register: lv_uuid

    - name: Mount created filesystem
      ansible.posix.mount:
        path: "{{ mount_path }}"
        src: UUID={{ lv_uuid.stdout }} 
        state: mounted
        fstype: "{{ fs_type }}"

Variables used:

  • vg_name: The name of the existing volume group in your server(s)
  • lv_name: The name of the logical volume to be created.
  • lv_size: The size of logical volume being created. t for terabyte, g for gigabyte, m for megabytes.
  • fs_type: The filesystem type to be used in LV partitioning
  • mount_path: Directory where disk is mounted. It will be created if doesn’t exist.

Create inventory file with the your servers.

$ vim hosts
[myservers]
192.168.1.20
192.168.1.21
192.168.1.22

Run playbook after customizing it create logical volume.

$ ansible-playbook -i hosts lvm-partition_data.yml

PLAY [Playbook to create LV, Filesystem and Mount it] ************************************************************************************************************************************************

TASK [Gathering Facts] *******************************************************************************************************************************************************************************
ok: [192.168.1.20]

TASK [Create Logical Volume for data persistence] ****************************************************************************************************************************************************
changed: [192.168.1.20]

TASK [Create filesystem on LV] ***********************************************************************************************************************************************************************
changed: [192.168.1.20]

TASK [Get LV UUID] ***********************************************************************************************************************************************************************************
changed: [192.168.1.20]

TASK [Mount created filesystem] **********************************************************************************************************************************************************************
changed: [192.168.1.20]

PLAY RECAP *******************************************************************************************************************************************************************************************
192.168.1.20             : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

2. Create Physical Volume, Volume Group and Logical Volume

In this example we’re using raw disks to create PV, then VG and LV creation.

Raw disks used in this example are:

  • /dev/vdb
  • /dev/vdc

Check your server to see available raw disk devices.

$ lsblk
NAME    MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
loop0     7:0    0  63.5M  1 loop /snap/core20/2015
loop1     7:1    0 111.9M  1 loop /snap/lxd/24322
loop2     7:2    0  40.8M  1 loop /snap/snapd/20092
sr0      11:0    1     4M  0 rom
vda     252:0    0    30G  0 disk
├─vda1  252:1    0  29.9G  0 part /
├─vda14 252:14   0     4M  0 part
└─vda15 252:15   0   106M  0 part /boot/efi
vdb     252:16   0    20G  0 disk
vdc     252:32   0    20G  0 disk

Let’s create playbook file.

vim lvm_pv_vg_lv.yml

Customize below contents to be used in the ansible playbook.

---
- name: Playbook to create PV, VG, LV, Filesystem and Mount it
  hosts: myservers
  remote_user: ubuntu
  become: yes
  become_method: sudo
  vars:
    pv_disks: /dev/vdb
    #pv_disks: /dev/vdb,/dev/vdc
    vg_name: vg1
    lv_name: container_data
    lv_size: +100%FREE
    #lv_size: 10g
    fs_type: ext4
    mount_path: /data
  tasks:
    - name: Create a volume group
      community.general.lvg:
        vg: "{{ vg_name }}"
        pvs: "{{ pv_disks }}"

    - name: Create Logical Volume for data persistence
      community.general.lvol:
        vg: "{{ vg_name }}"
        lv: "{{ lv_name }}"
        size: "{{ lv_size }}"

    - name: Create filesystem on LV 
      community.general.filesystem:
        fstype: "{{ fs_type }}"
        resizefs: true
        dev:  /dev/mapper/{{ vg_name }}-{{ lv_name }}

    - name: Get LV UUID
      ansible.builtin.command: lsblk /dev/mapper/{{ vg_name }}-{{ lv_name }} -no UUID
      register: lv_uuid

    - name: Mount created filesystem
      ansible.posix.mount:
        path: "{{ mount_path }}"
        src: UUID={{ lv_uuid.stdout }} 
        state: mounted
        fstype: "{{ fs_type }}"

Where:

  • pv_disks: List of one or more raw disk devices path
  • vg_name: The name of the volume group to be created
  • lv_name: The name of the logical volume to be created
  • lv_size: The size of logical volume to be created. t for terabyte, g for gigabyte, m for megabytes.
  • fs_type: The filesystem type to be used in device partitioning
  • mount_path: Directory where disk is mounted. It will be created if doesn’t exist.

Once done run the Playbook to create PV, VG and LV.

$ ansible-playbook -i hosts lvm_pv_vg_lv.yml
PLAY [Playbook to create LV, Filesystem and Mount it] ************************************************************************************************************************************************

TASK [Gathering Facts] *******************************************************************************************************************************************************************************
ok: [192.168.56.50]

TASK [Create a volume group] *************************************************************************************************************************************************************************
changed: [192.168.56.50] => (item=/dev/vdb)

TASK [Create Logical Volume for data persistence] ****************************************************************************************************************************************************
changed: [192.168.56.50]

TASK [Create filesystem on LV] ***********************************************************************************************************************************************************************
changed: [192.168.56.50]

TASK [Get LV UUID] ***********************************************************************************************************************************************************************************
changed: [192.168.56.50]

TASK [Mount created filesystem] **********************************************************************************************************************************************************************
changed: [192.168.56.50]

PLAY RECAP *******************************************************************************************************************************************************************************************
192.168.56.50              : ok=6    changed=5    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Confirm PV, VG, and LV creations.

$ sudo pvs
  PV         VG  Fmt  Attr PSize   PFree
  /dev/vdb   vg1 lvm2 a--  <20.00g     0

$ sudo vgs
  VG  #PV #LV #SN Attr   VSize   VFree
  vg1   1   1   0 wz--n- <20.00g    0

$ sudo lvs
  LV             VG  Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  container_data vg1 -wi-ao---- <20.00g

$ df -hT /data
Filesystem                     Type  Size  Used Avail Use% Mounted on
/dev/mapper/vg1-container_data ext4   20G   24K   19G   1% /data

$ cat /etc/fstab
LABEL=cloudimg-rootfs	/	 ext4	discard,errors=remount-ro	0 1
LABEL=UEFI	/boot/efi	vfat	umask=0077	0 1
UUID=e7e6a6f6-e85e-46a2-b070-c3ee5fb571f5 /data ext4 defaults 0 0

From the commands output we can confirm the playbook execution was successful. This is a basic ansible usage example of LVM management. You can check official Ansible documentation pages for more modules usage guidance.

LEAVE A REPLY

Please enter your comment!
Please enter your name here