Files
infra-automation/cheatsheets/deploy-linux-vm-lvm.md
Infrastructure Team 5ba666dfbf Add quick reference cheatsheets for all playbooks
Cheatsheets created:
- deploy-debian12-vm.md - Basic Debian 12 deployment reference
- deploy-debian-lvm-netinst.md - Network installer with native LVM
- deploy-linux-vm.md - Multi-distribution quick reference
- deploy-linux-vm-lvm.md - Multi-distro with post-config LVM
- deploy-linux-vm-role.md - Role-based deployment guide
- test-deploy-linux-vm-role.md - Testing and validation procedures

Each cheatsheet includes:
- Quick deployment commands
- Variable reference tables
- Tag-based execution examples
- Post-deployment verification steps
- LVM management commands (where applicable)
- Troubleshooting procedures
- Security validation steps
- VM management commands
2025-11-10 22:52:11 +01:00

11 KiB

Deploy Linux VM with Post-Config LVM - Quick Reference

Playbook

plays/deploy-linux-vm-lvm.yml

Description

Multi-distribution Linux VM deployment with post-installation LVM configuration. This playbook deploys a VM using cloud images and then configures LVM on a second disk to meet CLAUDE.md requirements.

Quick Deployment

Debian 12 with LVM

ansible-playbook plays/deploy-linux-vm-lvm.yml \
  -e "os_distribution=debian-12" \
  -e "vm_name=debian-lvm"

Ubuntu 22.04 with LVM

ansible-playbook plays/deploy-linux-vm-lvm.yml \
  -e "os_distribution=ubuntu-22.04" \
  -e "vm_name=ubuntu-lvm"

AlmaLinux 9 with LVM

ansible-playbook plays/deploy-linux-vm-lvm.yml \
  -e "os_distribution=almalinux-9" \
  -e "vm_name=alma-lvm"

Custom Resources

ansible-playbook plays/deploy-linux-vm-lvm.yml \
  -e "os_distribution=rocky-9" \
  -e "vm_name=prod-server" \
  -e "vm_vcpus=8" \
  -e "vm_memory_mb=16384" \
  -e "vm_disk_size_gb=100"

Supported Distributions

Debian Family

  • debian-11, debian-12
  • ubuntu-20.04, ubuntu-22.04, ubuntu-24.04

RHEL Family

  • rhel-8, rhel-9 (manual download required)
  • centos-stream-8, centos-stream-9
  • rocky-8, rocky-9
  • almalinux-8, almalinux-9

SUSE Family

  • sles-15 (manual download required)
  • opensuse-leap-15.5, opensuse-leap-15.6

LVM Configuration

This playbook creates a 30GB secondary disk (/dev/vdb) with LVM:

Physical Volume: /dev/vdb (30GB)
Volume Group: vg_system

Logical Volumes (CLAUDE.md compliant):
├── lv_opt        3G    /opt
├── lv_tmp        1G    /tmp (noexec,nosuid,nodev)
├── lv_home       2G    /home
├── lv_var        5G    /var
├── lv_var_log    2G    /var/log
├── lv_var_tmp    5G    /var/tmp (noexec,nosuid,nodev)
├── lv_var_audit  1G    /var/log/audit
└── lv_swap       2G    swap

Primary disk (/dev/vda): OS installation (unchanged)

Variables

Variable Default Description
os_distribution REQUIRED Distribution identifier
vm_name linux-guest VM name
vm_hostname linux-vm VM hostname
vm_vcpus 2 Number of vCPUs
vm_memory_mb 2048 RAM in MB
vm_disk_size_gb 20 Primary disk size
lvm_disk_size_gb 30 LVM disk size
lvm_vg_name vg_system Volume group name
lvm_pv_device /dev/vdb Physical volume device

Tag-Based Execution

# Pre-flight checks
ansible-playbook plays/deploy-linux-vm-lvm.yml --tags preflight

# Deploy VM only (no LVM)
ansible-playbook plays/deploy-linux-vm-lvm.yml --skip-tags lvm

# Configure LVM only (existing VM)
ansible-playbook plays/deploy-linux-vm-lvm.yml \
  -e "vm_ip=192.168.122.50" \
  --tags lvm

# Full deployment
ansible-playbook plays/deploy-linux-vm-lvm.yml

Available Tags

  • preflight, validate - Pre-flight validation
  • install - Install hypervisor packages
  • download, verify - Download and verify cloud images
  • storage - Create VM disks (including LVM disk)
  • cloud-init - Generate cloud-init configuration
  • deploy - Deploy and start VM
  • lvm - Configure LVM on deployed VM
  • post-deploy - Post-deployment tasks
  • cleanup - Remove temporary files

Deployment Process

Stage 1: VM Deployment (~2-3 minutes)

  1. Download cloud image (if not cached)
  2. Create primary disk from cloud image
  3. Create secondary 30GB disk for LVM
  4. Generate cloud-init configuration
  5. Deploy VM with both disks attached
  6. Wait for VM to boot

Stage 2: LVM Configuration (~3-5 minutes)

  1. Install LVM packages on VM
  2. Create physical volume on /dev/vdb
  3. Create volume group vg_system
  4. Create logical volumes
  5. Format filesystems
  6. Copy existing data to LVM volumes
  7. Update /etc/fstab
  8. Reboot required to activate

Total Time: ~5-8 minutes

Post-Deployment

Get VM IP

ssh grokbox "virsh domifaddr <vm_name>"

Access VM

ssh -J grokbox ansible@<VM_IP>

Verify LVM Configuration

# Check LVM status
ssh -J grokbox ansible@<VM_IP> "sudo pvs && sudo vgs && sudo lvs"

# Check disk layout
ssh -J grokbox ansible@<VM_IP> "lsblk"

# View fstab
ssh -J grokbox ansible@<VM_IP> "cat /etc/fstab"

Expected lsblk output:

NAME                      SIZE TYPE MOUNTPOINTS
vda                        20G disk
├─vda1                   19.9G part /
└─vda14                     4M part
vdb                        30G disk
├─vg_system-lv_opt         3G lvm  /opt
├─vg_system-lv_tmp         1G lvm  /tmp
├─vg_system-lv_home        2G lvm  /home
├─vg_system-lv_var         5G lvm  /var
├─vg_system-lv_var_log     2G lvm  /var/log
├─vg_system-lv_var_tmp     5G lvm  /var/tmp
├─vg_system-lv_var_audit   1G lvm  /var/log/audit
└─vg_system-lv_swap        2G lvm  [SWAP]

Reboot to Activate LVM Mounts

# IMPORTANT: Reboot required!
ssh -J grokbox ansible@<VM_IP> "sudo reboot"

# Wait ~1 minute, then verify mounts
ssh -J grokbox ansible@<VM_IP> "df -h"

After reboot, verify all LVM volumes are mounted:

ssh -J grokbox ansible@<VM_IP> "df -h | grep vg_system"

Distribution-Specific Features

Debian/Ubuntu

  • Package manager: apt
  • Firewall: ufw (enabled with SSH allowed)
  • Security: AppArmor enabled
  • Auto-updates: unattended-upgrades
  • User group: sudo

RHEL/AlmaLinux/Rocky

  • Package manager: dnf
  • Firewall: firewalld (enabled with SSH allowed)
  • Security: SELinux enforcing
  • Auto-updates: dnf-automatic
  • User group: wheel

SUSE/openSUSE

  • Package manager: zypper
  • Firewall: firewalld
  • User group: wheel

LVM Management

Extend Logical Volumes

# Extend lv_var by 5GB
ssh ansible@<VM_IP> "sudo lvextend -L +5G /dev/vg_system/lv_var"
ssh ansible@<VM_IP> "sudo resize2fs /dev/vg_system/lv_var"

# Use all remaining free space
ssh ansible@<VM_IP> "sudo lvextend -l +100%FREE /dev/vg_system/lv_var"
ssh ansible@<VM_IP> "sudo resize2fs /dev/vg_system/lv_var"

Create New Logical Volume

ssh ansible@<VM_IP> "sudo lvcreate -L 5G -n lv_app vg_system"
ssh ansible@<VM_IP> "sudo mkfs.ext4 /dev/vg_system/lv_app"
ssh ansible@<VM_IP> "sudo mkdir -p /opt/app"
ssh ansible@<VM_IP> "sudo mount /dev/vg_system/lv_app /opt/app"

# Add to fstab
ssh ansible@<VM_IP> "echo '/dev/vg_system/lv_app /opt/app ext4 defaults 0 2' | sudo tee -a /etc/fstab"

LVM Snapshots

# Create snapshot
ssh ansible@<VM_IP> "sudo lvcreate -L 2G -s -n lv_var_snapshot /dev/vg_system/lv_var"

# Mount snapshot
ssh ansible@<VM_IP> "sudo mkdir -p /mnt/snapshot"
ssh ansible@<VM_IP> "sudo mount /dev/vg_system/lv_var_snapshot /mnt/snapshot"

# Remove snapshot
ssh ansible@<VM_IP> "sudo umount /mnt/snapshot"
ssh ansible@<VM_IP> "sudo lvremove /dev/vg_system/lv_var_snapshot"

Troubleshooting

LVM Configuration Failed

# Check if second disk is attached
ssh grokbox "virsh domblklist <vm_name>"

# Check disk visibility on VM
ssh ansible@<VM_IP> "lsblk"

# Manually run LVM setup
ssh ansible@<VM_IP> "sudo pvcreate /dev/vdb"
ssh ansible@<VM_IP> "sudo vgcreate vg_system /dev/vdb"

Mounts Not Active After Reboot

# Check fstab entries
ssh ansible@<VM_IP> "cat /etc/fstab | grep vg_system"

# Manually mount all
ssh ansible@<VM_IP> "sudo mount -a"

# Check for errors
ssh ansible@<VM_IP> "dmesg | tail -30"

Data Migration Issues

# Check data was copied
ssh ansible@<VM_IP> "sudo du -sh /var"
ssh ansible@<VM_IP> "sudo du -sh /opt"

# If data missing, restore from rsync backup
# (Data should be preserved on original locations until reboot)

SELinux Issues (RHEL Family)

# Check SELinux status
ssh ansible@<VM_IP> "getenforce"

# View denials
ssh ansible@<VM_IP> "sudo ausearch -m avc -ts recent"

# Relabel filesystem
ssh ansible@<VM_IP> "sudo restorecon -R /opt /tmp /home /var"

Security Features

All deployed VMs include:

Authentication

  • ansible user with passwordless sudo
  • SSH key-based authentication only
  • Root login disabled via SSH

Firewall (enabled and configured)

  • Debian/Ubuntu: UFW
  • RHEL/SUSE: firewalld

Automatic Updates

  • Debian/Ubuntu: unattended-upgrades
  • RHEL: dnf-automatic
  • Security updates only, no auto-reboot

Security Hardening

  • RHEL: SELinux enforcing
  • Debian: AppArmor enabled
  • Audit daemon enabled
  • Time synchronization (chrony)

Essential Packages

  • System tools: vim, htop, tmux
  • Network: curl, wget, rsync
  • Development: git, python3
  • Security: aide, auditd
  • Storage: lvm2, parted

VM Management

# Start/Stop
ssh grokbox "virsh start <vm_name>"
ssh grokbox "virsh shutdown <vm_name>"
ssh grokbox "virsh destroy <vm_name>"

# Status
ssh grokbox "virsh dominfo <vm_name>"
ssh grokbox "virsh list --all"

# Console
ssh grokbox "virsh console <vm_name>"

# Delete
ssh grokbox "virsh destroy <vm_name>"
ssh grokbox "virsh undefine <vm_name> --remove-all-storage"

Validation Checklist

After deployment and reboot:

  • VM running: virsh list | grep <vm_name>
  • IP assigned: virsh domifaddr <vm_name>
  • SSH accessible: ssh -J grokbox ansible@<VM_IP>
  • Cloud-init complete: cloud-init status
  • LVM configured: sudo vgs && sudo lvs
  • All volumes mounted: df -h | grep vg_system
  • Firewall enabled: sudo ufw status or sudo firewall-cmd --state
  • SELinux enforcing (RHEL): getenforce
  • Swap active: free -h | grep Swap

Comparison with Other Playbooks

Feature deploy-debian12-vm deploy-debian-lvm-netinst deploy-linux-vm-lvm deploy_linux_vm role
Multi-distro No No Yes Yes
LVM Support No Yes (native) Yes (post-config) Yes (post-config)
Deploy Time 2-3 min 15-20 min 5-8 min 5-8 min
CLAUDE.md LVM No Yes Yes Yes
Reboot Required No No Yes Yes
Modular No No No Yes

Important Files

On Hypervisor (grokbox)

  • Cloud images: /var/lib/libvirt/images/*.qcow2
  • VM primary disk: /var/lib/libvirt/images/<vm_name>.qcow2
  • VM LVM disk: /var/lib/libvirt/images/<vm_name>-lvm.qcow2
  • Cloud-init ISO: /var/lib/libvirt/images/<vm_name>-cloud-init.iso

On Guest VM

  • SSH config: /etc/ssh/sshd_config.d/99-security.conf
  • Sudoers: /etc/sudoers.d/ansible
  • Fstab: /etc/fstab (LVM mounts)
  • LVM config: /etc/lvm/lvm.conf
  • Playbook: plays/deploy-linux-vm-lvm.yml
  • Role (recommended): roles/deploy_linux_vm/
  • Multi-distro without LVM: plays/deploy-linux-vm.yml
  • Debian native LVM: plays/deploy-debian-lvm-netinst.yml
  • CLAUDE.md: LVM specifications

Support

For issues or questions:

  • Check playbook output during LVM configuration
  • View /var/log/cloud-init-output.log on VM
  • Consult CLAUDE.md for LVM requirements
  • Use role version for advanced features