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

412 lines
11 KiB
Markdown

# 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
```bash
ansible-playbook plays/deploy-linux-vm-lvm.yml \
-e "os_distribution=debian-12" \
-e "vm_name=debian-lvm"
```
### Ubuntu 22.04 with LVM
```bash
ansible-playbook plays/deploy-linux-vm-lvm.yml \
-e "os_distribution=ubuntu-22.04" \
-e "vm_name=ubuntu-lvm"
```
### AlmaLinux 9 with LVM
```bash
ansible-playbook plays/deploy-linux-vm-lvm.yml \
-e "os_distribution=almalinux-9" \
-e "vm_name=alma-lvm"
```
### Custom Resources
```bash
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
```bash
# 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
```bash
ssh grokbox "virsh domifaddr <vm_name>"
```
### Access VM
```bash
ssh -J grokbox ansible@<VM_IP>
```
### Verify LVM Configuration
```bash
# 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
```bash
# 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:
```bash
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
```bash
# 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
```bash
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
```bash
# 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
```bash
# 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
```bash
# 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
```bash
# 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)
```bash
# 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
```bash
# 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`
## 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.log` on VM
- Consult CLAUDE.md for LVM requirements
- Use role version for advanced features