Forschen

Automatische Image Erstellung mit Packer


Mittlerweile gibt es viele verschiedene Virtualisierer, um Systeme für Test und Produktion zur Verfügung zu stellen: Docker, KVM, VMware, Proxmox, Virtualbox, HyperV, ….
Allen gemein bleibt, dass sie ein Image mit einem installierten Betriebssystem für die von ihnen zur Verfügung gestellten VMs benötigen.
Neben der altbewährten, aber zeitaufwendigen manuellen Installation eines Betriebssystems gibt es einige klassische Provisioning Tools wie Foreman, Spacewalk, FAI, etc, die aber alle vor ihrer Nutzung ebenfalls relativ aufwendig installiert werden müssen und schon eine gewisse Anforderung an die eigene Hardware stellen.
Eine interessante Alternative ist das Open Source Tool Packer von der Firma HashiCorp. Es besteht aus einem einzigen Binary, das mit Hilfe von Plugins aus einer JSON artigen Template-Datei, welche das Zielimage beschreibt, Systemimages für die verschiedensten Zielplattformen erstellt. Dabei lassen sich auch vorhandene Tools wie Ansible, ssh oder auch einfache Bash Skripte integrieren.
Packer schliesst mit seiner Philosophie die Automatisierungslücke zwischen dem Entstehen einer VM und ihrer Konfiguration. Außerdem werden durch Packer auch bei der Imageerstellung die aus der Infrastructure-as-a-Code bekannten Vorteile sichergestellt: Nachvollziehbarkeit, Wiederholbarkeit und Automatisierung.


Installation

Packer kann aus verschiedenen Quellen installiert werden: Homebrew, fertiges deb/rpm Paket oder direkter Download des Binary:

wget https://releases.hashicorp.com/packer/1.8.2/packer_1.8.2_linux_amd64.zip

sudo unzip packer_1.8.2_linux_amd64.zip -d /usr/local/bin/


Template

Eine Template Datei beschreibt, was für ein Image wie von Packer gebaut werden soll. Früher im JSON Format ist seit Version 1.7 das hauseigene Format HCL die empfohlene Definitionssprache für Templates.
Ein Template besteht aus drei Blöcken:

Packer Block

In diesem Block werden Einstellungen hinterlegt, die Packer direkt betreffen und vor allem, welche Plugins genutzt werden sollen.

Source Block

Hier werden die Plugin-spezifischen Einstellungen festgelegt:

  • Welche Plattform soll genutzt werden
  • Welche Leistungsdaten (CPU, RAM, HDD, usw) soll sie haben
  • Wie soll die Verbindung hergestellt werden
  • Es können mehrere source Blöcke existieren, je nachdem, für welche Virtualisierer Images gebaut werden sollen.

    Build Block

    Was genau, also welches OS mit welchem Inhalt, gebaut werden soll und ggf. mit welchen zusätzlichen Hilfsmitteln, wird in diesem Abschnitt beschrieben.

    Ein einfaches Beispiel Template, welches jeweils ein Image mit Rocky Linux für Proxmox und Virtualbox erstellt, könnte so aussehen:

    packer {
      required_plugins {
        virtualbox = {
          version = "1.0.4"
          source  = "github.com/hashicorp/virtualbox"
        }
        proxmox = {
          version = "= 1.0.8"
          source  = "github.com/hashicorp/proxmox"
        }
      }
    }
    
    source "proxmox-iso" "rocky" {
      proxmox_url      = "https://proxmox.pve:8006/api2/json"
      username         = "root@pam!packer"
      token            = "xx-xx-xx-xx"
      node             = "example"
      iso_storage_pool = "iso"
      iso_file          = "iso:iso/Rocky-8.6-x86_64-dvd1.iso"
      iso_checksum     = "sha256:1d48e0af63d07ff4e582a1819348e714c694e7fd33207f48879c2bc806960786"
      pool             = "terraform"
      memory           = 4096
      cores            = 2
      sockets          = 1
      cpu_type         = "host"
      os               = "l26"
      qemu_agent       = true
      unmount_iso      = true
      scsi_controller  = "virtio-scsi-single"
      disks {
        type              = "scsi"
        disk_size         = "8G"
        storage_pool      = "ceph_vm"
        storage_pool_type = "rbd"
        format            = "raw"
      }
      network_adapters {
        bridge   = "vmbr0"
        model    = "virtio"
        firewall = false
      }
      communicator   = "ssh"
      ssh_username   = "packer"
      ssh_password   = "packer"
      ssh_timeout    = "10m"
      vm_name        = "packer-rocky"
      vm_id          = 110
      boot_wait      = "3s"
      boot_command = [
        "<up><tab><end> inst.text inst.ks=http://webserver.example.com/provision/rocky/8/ks.cfg<wait5><enter>"
      ]
    }
    
    source "virtualbox-iso" "rocky" {
      guest_os_type = "RedHat_64"
      iso_url              = "https://download.rockylinux.org/pub/rocky/8/isos/x86_64/Rocky-8.6-x86_64-dvd1.iso"
      iso_checksum         = "sha256:1d48e0af63d07ff4e582a1819348e714c694e7fd33207f48879c2bc806960786"
      output_directory     = "rocky_vbox"
      cpus                 = "2"
      memory               = "2048"
      guest_additions_mode = "disable"
      http_directory       = "./http/"
      communicator         = "ssh"
      ssh_username         = "packer"
      ssh_password         = "packer"
      ssh_timeout          = "20m"
      shutdown_command     = "echo 'packer' | sudo -S shutdown -P now"
      boot_wait            = "3s"
      boot_command = [
        "<up><tab><end> inst.text inst.ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg<wait5><enter>"
      ]
    }
    
    build {
      sources = [
        "source.proxmox-iso.rocky",
        "source.virtualbox-iso.rocky",
      ]
    
      provisioner "shell" {
        only = ["proxmox-iso.rocky"]
        inline = [
          "echo Adrian! :-D",
        ]
      }
    
      provisioner "shell" {
        inline = [
          "echo Packer did it"
        ]
      }
    }
    

    Erläuterungen zum Template Beispiel

    Die meisten Parameter erklären sich von selbst und ergeben sich teilweise aus dem jeweiligen genutzten Plugin. Einige Parameter sind aber eine besondere Erwähnung wert:

  • iso_url: URLs zu einer ISO können auch auf lokale Verzeichnisse verweisen.
  • http_directory: Packer kann temporär einen lokalen HTTP Service starten, um z. B. Kickstart oder Cloud-Init Dateien zur Verfügung zu stellen.
  • boot_command: Im boot_command Parameter lassen sich über Metabeschreibungen Tastenanschläge simulieren, sodass eine “virtuelle” Benutzung eines Bootmenüs möglich ist.

  • Usage

    Das obige Beispiel wird in einem neuen Unterordner als Datei unter dem Namen rocky.pkr.hcl gespeichert. Zusätzlich wird ein weiterer Unterordner namens http angelegt, in der eine Kickstart Datei abgelegt werden kann:

    tree
    .
    ├── http
    │   └── ks.cfg
    └── rocky.pkr.hcl
    
    1 directory, 2 files
    

    Nun muss die Konfiguration mit Packer initialisiert werden, um die benötigten Plugins zu erhalten:

    [0][packer]$ packer init .
    Installed plugin github.com/hashicorp/virtualbox v1.0.4 in "/home/packer/.config/packer/plugins/github.com/hashicorp/virtualbox/packer-plugin-virtualbox_v1.0.4_x5.0_linux_amd64"
    Installed plugin github.com/hashicorp/proxmox v1.0.8 in "/home/packer/.config/packer/plugins/github.com/hashicorp/proxmox/packer-plugin-proxmox_v1.0.8_x5.0_linux_amd64"
    [0][packer]$
    

    Packer bietet zwei Optionen an, um eine Template Datei zum einen zu formatieren und zum anderen auf richtige Syntax zu prüfen:

    [0][packer]$ packer fmt .
    rocky.pkr.hcl
    [0][packer]$ packer validate .
    The configuration is valid.
    [0][packer]$
    

    Ist so weit alles korrekt, kann mit dem Parameter build der Bau des Images gestartet werden:

    [0][packer]$ packer build .
    proxmox-iso.rocky: output will be in this color.
    virtualbox-iso.rocky: output will be in this color.
    
    ==> virtualbox-iso.rocky: Retrieving ISO
    ==> proxmox-iso.rocky: Creating VM
    ==> virtualbox-iso.rocky: Trying /srv/external-usb/isos/Rocky-8.6-x86_64-dvd1.iso
    ==> virtualbox-iso.rocky: Trying /srv/external-usb/isos/Rocky-8.6-x86_64-dvd1.iso?checksum=sha256%3A1d48e0af63d07ff4e582a1819348e714c694e7fd33207f48879c2bc806960786
    ==> proxmox-iso.rocky: Starting VM
    ==> proxmox-iso.rocky: Waiting 3s for boot
    ==> proxmox-iso.rocky: Typing the boot command
    ==> proxmox-iso.rocky: Waiting for SSH to become available...
    ==> virtualbox-iso.rocky: /srv/external-usb/isos/Rocky-8.6-x86_64-dvd1.iso?checksum=sha256%3A1d48e0af63d07ff4e582a1819348e714c694e7fd33207f48879c2bc806960786 => /srv/external-usb/isos/Rocky-8.6-x86_64-dvd1.iso
    ==> virtualbox-iso.rocky: Starting HTTP server on port 8730
    ==> virtualbox-iso.rocky: Creating virtual machine...
    ==> virtualbox-iso.rocky: Creating hard drive rocky_vbox/packer-rocky-1659535275.vdi with size 40000 MiB...
    ==> virtualbox-iso.rocky: Mounting ISOs...
        virtualbox-iso.rocky: Mounting boot ISO...
    ==> virtualbox-iso.rocky: Creating forwarded port mapping for communicator (SSH, WinRM, etc) (host port 3607)
    ==> virtualbox-iso.rocky: Starting the virtual machine...
    ==> virtualbox-iso.rocky: Waiting 3s for boot...
    ==> virtualbox-iso.rocky: Typing the boot command...
    ==> virtualbox-iso.rocky: Using SSH communicator to connect: 127.0.0.1
    ==> virtualbox-iso.rocky: Waiting for SSH to become available...
    ==> proxmox-iso.rocky: Connected to SSH!
    ==> proxmox-iso.rocky: Provisioning with shell script: /tmp/packer-shell3717013971
        proxmox-iso.rocky: Adrian! :-D
    ==> proxmox-iso.rocky: Provisioning with shell script: /tmp/packer-shell800680251
        proxmox-iso.rocky: Packer did it
    ==> proxmox-iso.rocky: Stopping VM
    ==> proxmox-iso.rocky: Converting VM to template
    Build 'proxmox-iso.rocky' finished after 8 minutes 54 seconds.
    ==> virtualbox-iso.rocky: Connected to SSH!
    ==> virtualbox-iso.rocky: Uploading VirtualBox version info (6.1.34)
    ==> virtualbox-iso.rocky: Provisioning with shell script: /tmp/packer-shell2506019040
        virtualbox-iso.rocky: Packer did it
    ==> virtualbox-iso.rocky: Gracefully halting virtual machine...
    ==> virtualbox-iso.rocky: Preparing to export machine...
        virtualbox-iso.rocky: Deleting forwarded port mapping for the communicator (SSH, WinRM, etc) (host port 3607)
    ==> virtualbox-iso.rocky: Exporting virtual machine...
        virtualbox-iso.rocky: Executing: export packer-rocky-1659535275 --output rocky_vbox/packer-rocky-1659535275.ovf
    ==> virtualbox-iso.rocky: Cleaning up floppy disk...
    ==> virtualbox-iso.rocky: Deregistering and deleting VM...
    Build 'virtualbox-iso.rocky' finished after 10 minutes 47 seconds.
    
    ==> Wait completed after 10 minutes 47 seconds
    
    ==> Builds finished. The artifacts of successful builds are:
    --> proxmox-iso.rocky: A template was created: 110
    --> virtualbox-iso.rocky: VM files in directory: rocky_vbox
    [0][packer]$ 
    

    Sind in der Template Datei mehrere Source Blöcke definiert, wird das Image mit dem Aufruf für alle erstellt. Falls das Image nur für eine Sourcedefinition erstellt werden soll, kann das beim build Aufruf als Option mitgegeben werden:

    [0][packer]$ packer build -only=proxmox-iso.rocky rocky.pkr.hcl
    


    Advanced

    In einem zweiten Teil werden weiterführende Packer Techniken betrachtet:

  • Shell Skript Integration
  • Ansible Integration
  • Variablennutzung
  • SSH Key
  • Debugging

  • Fazit

    Mit Packer ist es möglich, schnell und flexibel individuell standardisierte Basis Images für die verschiedensten Virtualisierungsplattformen zu erstellen. Im Internet sind viele fertige Packer Templates zu finden, so dass sich schnell Erfolge erzielen lassen.


    Ein How-To von Martin.


    https://www.packer.io/plugins
    https://github.com/chef/bento

    Downloads

    ks.cfg
    rocky.pkr.hcl

    ×
    ×

    Nehmen Sie Kontakt zu uns auf!

    Mit * gekennzeichnete Felder sind Pflichtfelder.

    Wir haben Ihre Kontaktanfrage erhalten und melden uns kurzfristig bei Ihnen!

    ×

    Ich möchte eine Frage einreichen!

    Vielen Dank für das Einreichen Ihrer Frage!