Initial commit
This commit is contained in:
@@ -0,0 +1,83 @@
|
|||||||
|
# Ansible KVM Immutable OS Provisioner
|
||||||
|
|
||||||
|
This project provides an Ansible-based framework to automatically provision virtual machines using KVM on a Linux host. It specifically targets immutable operating systems: **Fedora CoreOS**, **Flatcar Container Linux**, and **openSUSE MicroOS**.
|
||||||
|
|
||||||
|
## 🚀 Features
|
||||||
|
|
||||||
|
- **Automated Host Setup**: Installs and configures `libvirt`, `qemu-kvm`, and `libguestfs-tools`.
|
||||||
|
- **Immutable OS Support**: Handles the specific boot-time configuration requirements for:
|
||||||
|
- **CoreOS/Flatcar**: Generates and injects Ignition JSON configurations.
|
||||||
|
- **MicroOS**: Generates and injects Cloud-init user-data.
|
||||||
|
- **Custom User Provisioning**: Automatically creates a default user with a hashed password and injects your SSH public key.
|
||||||
|
- **Modular Design**: Uses Ansible roles for host preparation, configuration generation, and VM provisioning.
|
||||||
|
|
||||||
|
## 📂 Project Structure
|
||||||
|
|
||||||
|
```text
|
||||||
|
ansible-kvm-vms/
|
||||||
|
├── inventory # Defines the KVM host (defaults to localhost)
|
||||||
|
├── group_vars/
|
||||||
|
│ └── all.yml # Global settings: user, password, and SSH key path
|
||||||
|
├── vars/
|
||||||
|
│ └── vms.yml # List of VMs to create with CPU, RAM, and Disk specs
|
||||||
|
├── roles/
|
||||||
|
│ ├── kvm_host_setup/ # Installs virtualization dependencies on the host
|
||||||
|
│ ├── os_config/ # Generates Ignition/Cloud-init config files
|
||||||
|
│ └── vm_provision/ # Downloads images and creates VMs via virt-install
|
||||||
|
└── playbooks/
|
||||||
|
└── create_vms.yml # Main orchestration playbook
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🛠 Prerequisites
|
||||||
|
|
||||||
|
Before running the playbooks, ensure the following:
|
||||||
|
|
||||||
|
1. **Hardware Virtualization**: Enabled in your BIOS/UEFI (VT-x or AMD-V).
|
||||||
|
2. **Ansible**: Installed on your control node.
|
||||||
|
3. **Sudo Access**: The user running the playbook must have sudo privileges on the KVM host.
|
||||||
|
4. **SSH Key**: You should have an SSH public key generated (usually at `~/.ssh/id_vms.pub`).
|
||||||
|
|
||||||
|
## ⚙️ Configuration
|
||||||
|
|
||||||
|
### 1. Global Settings
|
||||||
|
Edit `group_vars/all.yml` to set your desired credentials:
|
||||||
|
- `vm_user`: The username for the VM.
|
||||||
|
- `vm_password`: The password for the user (will be hashed automatically).
|
||||||
|
- `vm_ssh_public_key`: The absolute path to your `.pub` key file.
|
||||||
|
|
||||||
|
### 2. VM Definitions
|
||||||
|
Edit `vars/vms.yml` to add or modify the VMs you wish to deploy. You can specify:
|
||||||
|
- `name`: Unique name for the VM.
|
||||||
|
- `os_type`: One of `coreos`, `flatcar`, or `microos`.
|
||||||
|
- `os_variant`: The `virt-install` OS variant string.
|
||||||
|
- `cpu`, `ram`, `disk`: Resource allocations.
|
||||||
|
|
||||||
|
## 📖 Usage
|
||||||
|
|
||||||
|
1. **Navigate to the project directory**:
|
||||||
|
```bash
|
||||||
|
cd ansible-kvm-vms
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Run the deployment playbook**:
|
||||||
|
```bash
|
||||||
|
ansible-playbook -i inventory playbooks/create_vms.yml --ask-become-pass
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔍 How it Works
|
||||||
|
|
||||||
|
Since immutable OSs do not use traditional installers, this setup uses a "seed" approach:
|
||||||
|
1. **Config Generation**: The `os_config` role creates a JSON (Ignition) or YAML (Cloud-init) file based on your variables.
|
||||||
|
2. **Image Customization**: The `vm_provision` role downloads the official `.qcow2` cloud image and uses `virt-customize` (from `libguestfs-tools`) to inject the configuration directly into the disk image before the VM is started.
|
||||||
|
3. **Deployment**: `virt-install` is used to create the VM with UEFI boot and the customized disk.
|
||||||
|
|
||||||
|
## 🌐 Accessing your VMs
|
||||||
|
|
||||||
|
The VMs are created on the default KVM NAT network. To find the IP address of your new VMs, run:
|
||||||
|
```bash
|
||||||
|
sudo virsh net-dhcp-leases-all default
|
||||||
|
```
|
||||||
|
Then SSH into them using your configured user:
|
||||||
|
```bash
|
||||||
|
ssh kvmuser@<vm-ip-address>
|
||||||
|
```
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[defaults]
|
||||||
|
inventory = inventory
|
||||||
|
roles_path = ./roles
|
||||||
|
host_key_checking = False
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Global VM settings
|
||||||
|
ansible_python_interpreter: /usr/bin/python3
|
||||||
|
vm_user: "kvmuser"
|
||||||
|
vm_password: "Password123!" # In a real scenario, use ansible-vault to encrypt this
|
||||||
|
vm_ssh_public_key: "~/.ssh/id_vms.pub" # Path to your public key for SSH access
|
||||||
|
|
||||||
|
# Default VM resources
|
||||||
|
default_cpu: 2
|
||||||
|
default_ram: 2048
|
||||||
|
default_disk: "20G"
|
||||||
|
|
||||||
|
# Storage path for images
|
||||||
|
vm_images_dir: "/var/lib/libvirt/images"
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
[kvm_hosts]
|
||||||
|
localhost ansible_connection=local
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
- name: Setup KVM VMs
|
||||||
|
hosts: all
|
||||||
|
become: yes
|
||||||
|
vars_files:
|
||||||
|
- ../vars/vms.yml
|
||||||
|
|
||||||
|
roles:
|
||||||
|
- kvm_host_setup
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Provision each VM
|
||||||
|
include_role:
|
||||||
|
name: os_config
|
||||||
|
vars:
|
||||||
|
vm_name: "{{ item.name }}"
|
||||||
|
os_type: "{{ item.os_type }}"
|
||||||
|
loop: "{{ vms }}"
|
||||||
|
|
||||||
|
- name: Launch each VM
|
||||||
|
include_role:
|
||||||
|
name: vm_provision
|
||||||
|
vars:
|
||||||
|
vm_name: "{{ item.name }}"
|
||||||
|
os_type: "{{ item.os_type }}"
|
||||||
|
os_variant: "{{ item.os_variant }}"
|
||||||
|
cpu: "{{ item.cpu }}"
|
||||||
|
ram: "{{ item.ram }}"
|
||||||
|
disk: "{{ item.disk }}"
|
||||||
|
loop: "{{ vms }}"
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
- name: Install KVM and virtualization tools
|
||||||
|
package:
|
||||||
|
name:
|
||||||
|
- qemu-kvm
|
||||||
|
- libvirt-daemon-system
|
||||||
|
- libvirt-clients
|
||||||
|
- bridge-utils
|
||||||
|
- virtinst
|
||||||
|
- virt-manager
|
||||||
|
- libguestfs-tools
|
||||||
|
- xz-utils
|
||||||
|
state: present
|
||||||
|
when: ansible_facts['os_family'] == "Debian"
|
||||||
|
|
||||||
|
- name: Install KVM and virtualization tools (RedHat/Fedora)
|
||||||
|
package:
|
||||||
|
name:
|
||||||
|
- qemu-kvm
|
||||||
|
- libvirt
|
||||||
|
- virt-install
|
||||||
|
- virt-manager
|
||||||
|
- libguestfs-tools
|
||||||
|
- xz
|
||||||
|
state: present
|
||||||
|
when: ansible_facts['os_family'] == "RedHat"
|
||||||
|
|
||||||
|
- name: Install KVM and virtualization tools (Arch/CachyOS)
|
||||||
|
package:
|
||||||
|
name:
|
||||||
|
- qemu-full
|
||||||
|
- libvirt
|
||||||
|
- virt-manager
|
||||||
|
- iproute2
|
||||||
|
- libguestfs
|
||||||
|
- guestfs-tools
|
||||||
|
- xz
|
||||||
|
state: present
|
||||||
|
when: ansible_facts['os_family'] == "Archlinux"
|
||||||
|
|
||||||
|
- name: Ensure libvirtd is started and enabled
|
||||||
|
service:
|
||||||
|
name: libvirtd
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
|
||||||
|
- name: Ensure KVM default network is active and autostarts
|
||||||
|
shell: |
|
||||||
|
virsh net-start default || true
|
||||||
|
virsh net-autostart default || true
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Add current user to libvirt group
|
||||||
|
user:
|
||||||
|
name: "{{ ansible_facts['user_id'] }}"
|
||||||
|
groups: libvirt
|
||||||
|
append: yes
|
||||||
|
become: yes
|
||||||
|
ignore_errors: yes # Some distros use different group names (e.g., kvm)
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
- name: Generate Ignition config for CoreOS/Flatcar
|
||||||
|
template:
|
||||||
|
src: ignition.json.j2
|
||||||
|
dest: "/tmp/{{ vm_name }}_ignition.json"
|
||||||
|
when: os_type == "coreos" or os_type == "flatcar"
|
||||||
|
|
||||||
|
- name: Generate Cloud-init config for MicroOS
|
||||||
|
template:
|
||||||
|
src: user-data.yaml.j2
|
||||||
|
dest: "/tmp/{{ vm_name }}_user-data"
|
||||||
|
when: os_type == "microos"
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"ignition": {
|
||||||
|
"version": "0.3.0"
|
||||||
|
},
|
||||||
|
"passwd": {
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"name": "{{ vm_user }}",
|
||||||
|
"password_hash": "{{ vm_password | password_hash('sha512') }}",
|
||||||
|
"ssh_public_keys": [
|
||||||
|
"{{ lookup('file', vm_ssh_public_key) }}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"storage": {
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"path": "/etc/ssh/sshd_config.d/permit_root_login.conf",
|
||||||
|
"contents": {
|
||||||
|
"source": "data:text/plain;charset=utf-8,PermitRootLogin yes"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#cloud-config
|
||||||
|
users:
|
||||||
|
- name: {{ vm_user }}
|
||||||
|
passwd: {{ vm_password | password_hash('sha512') }}
|
||||||
|
ssh_authorized_keys:
|
||||||
|
- {{ lookup('file', vm_ssh_public_key) }}
|
||||||
|
sudo: ALL=(ALL) NOPASSWD:ALL
|
||||||
|
lock_passwd: false
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
- name: Define image URLs
|
||||||
|
set_fact:
|
||||||
|
os_images:
|
||||||
|
coreos: "https://builds.coreos.fedoraproject.org/prod/streams/stable/builds/44.20260510.3.1/x86_64/fedora-coreos-44.20260510.3.1-qemu.x86_64.qcow2.xz"
|
||||||
|
flatcar: "https://stable.release.flatcar-linux.net/amd64-usr/current/flatcar_production_qemu_uefi_image.img"
|
||||||
|
microos: "https://ftp.halifax.rwth-aachen.de/opensuse/tumbleweed/appliances/openSUSE-MicroOS.x86_64-kvm-and-xen.qcow2"
|
||||||
|
|
||||||
|
- name: Verify internet connectivity
|
||||||
|
uri:
|
||||||
|
url: http://google.com
|
||||||
|
return_content: no
|
||||||
|
timeout: 10
|
||||||
|
|
||||||
|
- name: Download OS image
|
||||||
|
get_url:
|
||||||
|
url: "{{ os_images[os_type] }}"
|
||||||
|
dest: "{{ vm_images_dir }}/{{ vm_name }}.download"
|
||||||
|
mode: '0644'
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Handle compressed or raw images
|
||||||
|
shell: |
|
||||||
|
DOWNLOAD_FILE="{{ vm_images_dir }}/{{ vm_name }}.download"
|
||||||
|
FINAL_FILE="{{ vm_images_dir }}/{{ vm_name }}.qcow2"
|
||||||
|
|
||||||
|
# 1. Handle XZ compression
|
||||||
|
if [[ "{{ os_images[os_type] }}" == *.xz ]]; then
|
||||||
|
echo "Decompressing XZ image..."
|
||||||
|
unxz -c "$DOWNLOAD_FILE" > "$FINAL_FILE"
|
||||||
|
elif [[ "{{ os_images[os_type] }}" == *.img ]]; then
|
||||||
|
echo "Converting RAW image to QCOW2..."
|
||||||
|
qemu-img convert -f raw -O qcow2 "$DOWNLOAD_FILE" "$FINAL_FILE"
|
||||||
|
else
|
||||||
|
echo "Moving QCOW2 image to final destination..."
|
||||||
|
mv "$DOWNLOAD_FILE" "$FINAL_FILE"
|
||||||
|
fi
|
||||||
|
rm -f "$DOWNLOAD_FILE"
|
||||||
|
become: yes
|
||||||
|
args:
|
||||||
|
creates: "{{ vm_images_dir }}/{{ vm_name }}.qcow2"
|
||||||
|
|
||||||
|
- name: Provision VM using virt-install
|
||||||
|
shell: |
|
||||||
|
virt-install \
|
||||||
|
--name {{ vm_name }} \
|
||||||
|
--vcpus {{ cpu | default(default_cpu) }} \
|
||||||
|
--memory {{ ram | default(default_ram) }} \
|
||||||
|
--disk path={{ vm_images_dir }}/{{ vm_name }}.qcow2,bus=virtio \
|
||||||
|
--import \
|
||||||
|
--os-variant {{ os_variant }} \
|
||||||
|
--network network=default \
|
||||||
|
--graphics none \
|
||||||
|
--noautoconsole \
|
||||||
|
--boot uefi \
|
||||||
|
{% if os_type == 'coreos' or os_type == 'flatcar' %}
|
||||||
|
--cloud-init user-data=/tmp/{{ vm_name }}_ignition.json
|
||||||
|
{% elif os_type == 'microos' %}
|
||||||
|
--cloud-init user-data=/tmp/{{ vm_name }}_user-data
|
||||||
|
{% endif %}
|
||||||
|
args:
|
||||||
|
creates: "/etc/libvirt/qemu/{{ vm_name }}.xml"
|
||||||
|
|
||||||
|
- name: Attach configuration to VM
|
||||||
|
debug:
|
||||||
|
msg: "Configuration is now handled by virt-install --cloud-init flag."
|
||||||
|
when: false # This task is now obsolete
|
||||||
|
become: yes
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
vms:
|
||||||
|
- name: coreos-vm
|
||||||
|
os_type: coreos
|
||||||
|
os_variant: "fedora-coreos-stable"
|
||||||
|
cpu: 2
|
||||||
|
ram: 2048
|
||||||
|
disk: "20G"
|
||||||
|
|
||||||
|
- name: flatcar-vm
|
||||||
|
os_type: flatcar
|
||||||
|
os_variant: "fedora-coreos-stable"
|
||||||
|
cpu: 2
|
||||||
|
ram: 2048
|
||||||
|
disk: "20G"
|
||||||
|
|
||||||
|
- name: microos-vm
|
||||||
|
os_type: microos
|
||||||
|
os_variant: "opensusemicroos"
|
||||||
|
cpu: 2
|
||||||
|
ram: 2048
|
||||||
|
disk: "20G"
|
||||||
Reference in New Issue
Block a user