--- - name: Build Debian Cloud Template directly from Proxmox hosts: node0 become: true gather_facts: false vars_files: - ../vars/debian_template.yml vars: lxc_name: "debian-builder" lxc_id: 9900 lxc_storage: "local-lvm" # lxc_storage: "hdd8t" lxc_template: "local:vztmpl/debian-13-standard_13.1-1_amd64.tar.zst" lxc_ostype: "debian" lxc_cores: 4 lxc_memory: 4096 lxc_swap: 0 lxc_net: "name=eth0,bridge=vmbr0,ip=dhcp" lxc_rootfs_size: "8G" lxc_password: "password" container_id: "{{ lxc_id }}" tasks: - block: - name: Ensure build environment packages are installed on Proxmox ansible.builtin.apt: name: # - libguestfs-tools # - qemu-utils - rsync state: present update_cache: true - name: Ensure QEMU template directory exists on Proxmox host ansible.builtin.file: path: /var/lib/vz/template/qemu state: directory owner: root group: root mode: '0755' - name: Combine SSH public keys into one file ansible.builtin.copy: dest: '{{ ssh_keys_file }}' content: | {% for key in ssh_public_keys %} {{ key }} {% endfor %} mode: '0644' - name: Create LXC build container ansible.builtin.command: > pct create {{ lxc_id }} {{ lxc_template }} --hostname {{ lxc_name }} --password '{{ lxc_password }}' --ssh-public-keys '{{ ssh_keys_file }}' --cores {{ lxc_cores }} --memory {{ lxc_memory }} --swap {{ lxc_swap }} --ostype {{ lxc_ostype }} --net0 {{ lxc_net }} --storage {{ lxc_storage }} --features nesting=1 --start args: creates: "/etc/pve/lxc/{{ lxc_id }}.conf" - name: Check if LXC container {{ lxc_name }} is running ansible.builtin.command: cmd: pct status {{ lxc_id }} register: pct_status changed_when: false - name: Start the LXC container {{ lxc_name }} if stopped ansible.builtin.command: cmd: pct start {{ lxc_id }} when: "'status: stopped' in pct_status.stdout" register: start_result changed_when: "'status: stopped' in pct_status.stdout" - name: Wait until container has an IP address ansible.builtin.shell: "pct exec {{ lxc_id }} -- hostname -I | awk '{print $1}'" register: lxc_ip until: lxc_ip.stdout != '' retries: 10 delay: 5 changed_when: false failed_when: lxc_ip.stdout == '' - name: Add temporary LXC to in-memory inventory ansible.builtin.add_host: name: lxc_builder ansible_host: "{{ lxc_ip.stdout }}" ansible_user: root ansible_password: "{{ lxc_password }}" ansible_ssh_common_args: '-o StrictHostKeyChecking=no' - name: Customize Debian cloud image inside LXC hosts: lxc_builder become: true vars_files: - ../vars/debian_template.yml tasks: - block: - name: Install build dependencies in LXC ansible.builtin.apt: name: - qemu-utils - libguestfs-tools - curl - wget - rsync - xz-utils - nano - htop state: present update_cache: true - name: Ensure sudo is installed ansible.builtin.apt: name: sudo state: present - name: Create working directory ansible.builtin.file: path: "{{ workdir }}" state: directory - name: Download latest Debian genericcloud image ansible.builtin.get_url: url: "{{ debian_image_url }}" dest: "{{ workdir }}/{{ image_name }}" mode: "0644" force: true - name: Get QCOW2 image info ansible.builtin.shell: "qemu-img info {{ workdir }}/{{ image_name }}" register: image_info - name: Show QCOW2 image details ansible.builtin.debug: msg: | === QCOW2 Image Info === {{ image_info.stdout }} - name: Customize image with base utilities and root password ansible.builtin.command: > virt-customize -a {{ workdir }}/{{ image_name }} --install "curl,wget,nano,rsync,htop" --root-password password:{{ root_password }} - name: Set DHCP identifier to hostname for cloud-init ansible.builtin.shell: | virt-customize -a {{ workdir }}/{{ image_name }} \ --run-command "echo 'dhcp-identifier: hostname' >> /etc/cloud/cloud.cfg.d/99_hostname.cfg" - name: Reset machine-id ansible.builtin.shell: | virt-customize -a {{ workdir }}/{{ image_name }} \ --run-command 'truncate -s 0 /etc/machine-id && rm -f /var/lib/dbus/machine-id' - name: Get QCOW2 image info ansible.builtin.shell: "qemu-img info {{ workdir }}/{{ image_name }}" register: image_info - name: Show QCOW2 image details ansible.builtin.debug: msg: | === QCOW2 Image Info === {{ image_info.stdout }} - name: Convert image to compressed qcow2 ansible.builtin.shell: | qemu-img convert -O qcow2 -c {{ workdir }}/{{ image_name }} {{ workdir }}/{{ template_name }}.qcow2 args: creates: "{{ workdir }}/{{ template_name }}.qcow2" - name: Get QCOW2 image info ansible.builtin.shell: "qemu-img info {{ workdir }}/{{ template_name }}.qcow2" register: image_info - name: Show QCOW2 image details ansible.builtin.debug: msg: | === QCOW2 Image Info === {{ image_info.stdout }} # - name: Shrink the compressed qcow2 using virt-sparsify # ansible.builtin.shell: | # virt-sparsify --compress {{ workdir }}/{{ template_name }}.qcow2 {{ workdir }}/{{ template_name }}_sparse.qcow2 # args: # creates: "{{ workdir }}/{{ template_name }}_sparse.qcow2" # - name: Get QCOW2 image info # ansible.builtin.shell: qemu-img info {{ workdir }}/linux-vm.qcow2 # register: image_info # - name: Show QCOW2 image details # ansible.builtin.debug: # msg: | # === QCOW2 Image Info === # {{ image_info.stdout }} # - name: Replace original compressed image with sparsified version # ansible.builtin.shell: | # mv {{ workdir }}/{{ template_name }}_sparse.qcow2 {{ workdir }}/{{ template_name }}.qcow2 # - name: Compress and shrink image # ansible.builtin.shell: | # qemu-img convert -O qcow2 -c {{ workdir }}/{{ image_name }} {{ workdir }}/{{ template_name }}.qcow2 # qemu-img resize {{ workdir }}/{{ template_name }}.qcow2 --shrink - name: Copy finished template back to Proxmox host ansible.posix.synchronize: src: "{{ workdir }}/{{ template_name }}.qcow2" dest: "/var/lib/vz/template/qemu/" mode: push # delegate_to: node0 # rsync_opts: # - "--rsync-path='sudo rsync'" - name: Import Debian Cloud image as Proxmox VM template hosts: node0 become: true tasks: - block: - name: Import QCOW2 as disk to new VM ansible.builtin.shell: > qm create {{ proxmox_template_vm_id }} --name {{ template_name }} --memory 1024 --net0 virtio,bridge=vmbr0 && qm importdisk {{ proxmox_template_vm_id }} /var/lib/vz/template/qcow2/{{ template_name }}.qcow2 {{ proxmox_storage }} - name: Configure VM for Cloud-Init ansible.builtin.shell: | qm set {{ proxmox_template_vm_id }} \ --scsihw virtio-scsi-pci \ --scsi0 {{ proxmox_storage }}:vm-{{ proxmox_template_vm_id }}-disk-0 \ --ide2 {{ proxmox_storage }}:cloudinit \ --boot c --bootdisk scsi0 \ --serial0 socket --vga serial0 - name: Convert VM to template ansible.builtin.shell: "qm template {{ proxmox_template_vm_id }}" - name: Stop and destroy LXC build container ansible.builtin.shell: "pct stop {{ lxc_id }} && pct destroy {{ lxc_id }} --purge" ignore_errors: true - ansible.builtin.debug: msg: "✅ Debian Cloud-Init template {{ template_name }} (VMID {{ proxmox_template_vm_id }}) created successfully!"