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
11 KiB
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-12ubuntu-20.04,ubuntu-22.04,ubuntu-24.04
RHEL Family
rhel-8,rhel-9(manual download required)centos-stream-8,centos-stream-9rocky-8,rocky-9almalinux-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 validationinstall- Install hypervisor packagesdownload,verify- Download and verify cloud imagesstorage- Create VM disks (including LVM disk)cloud-init- Generate cloud-init configurationdeploy- Deploy and start VMlvm- Configure LVM on deployed VMpost-deploy- Post-deployment taskscleanup- Remove temporary files
Deployment Process
Stage 1: VM Deployment (~2-3 minutes)
- Download cloud image (if not cached)
- Create primary disk from cloud image
- Create secondary 30GB disk for LVM
- Generate cloud-init configuration
- Deploy VM with both disks attached
- Wait for VM to boot
Stage 2: LVM Configuration (~3-5 minutes)
- Install LVM packages on VM
- Create physical volume on /dev/vdb
- Create volume group vg_system
- Create logical volumes
- Format filesystems
- Copy existing data to LVM volumes
- Update /etc/fstab
- 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 statusorsudo 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
Related Documentation
- 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.logon VM - Consult CLAUDE.md for LVM requirements
- Use role version for advanced features