Aller au contenu

Builders Packer

Chaque builder cible une plateforme spécifique. Packer démarré une machine temporaire, l'exécuté via les provisioners, puis capture l'image finale dans le format natif du provider.


QEMU

Le builder qemu produit des images au format qcow2 ou raw, utilisables avec KVM, Proxmox, OpenStack ou libvirt. Il démarré une VM temporaire via QEMU/KVM et automatise l'installation via boot_command.

Prérequis : QEMU et KVM installes sur la machine de build. Nécessité des droits de virtualisation (pas utilisable dans un container sans KVM).

packer {
  required_plugins {
    qemu = {
      source  = "github.com/hashicorp/qemu"
      version = "~> 1"
    }
  }
}

source "qemu" "ubuntu" {
  iso_url      = "https://releases.ubuntu.com/22.04/ubuntu-22.04.3-live-server-amd64.iso"
  iso_checksum = "sha256:a4acfda10b18da50e2ec50ccaf860d7f20b389df8765611142305c0e911d16fd"
  output_directory = "output-ubuntu"
  disk_size    = "20G"
  format       = "qcow2"
  accelerator  = "kvm"
  http_directory = "http"
  ssh_username = "ubuntu"
  ssh_password = "ubuntu"
  ssh_timeout  = "20m"
  shutdown_command = "sudo shutdown -P now"

  boot_wait = "5s"
  boot_command = [
    "<enter><wait>",
    "e<wait>",
    "<down><down><down><end>",
    " autoinstall ds=nocloud-net;s=http://{{ .HTTPIP }}:{{ .HTTPPort }}/",
    "<f10>"
  ]
}

build {
  sources = ["source.qemu.ubuntu"]

  provisioner "shell" {
    inline = ["apt-get update -y && apt-get upgrade -y"]
  }
}

L'image qcow2 produite peut être importee dans Proxmox, uploadee dans OpenStack Glance ou utilisée directement avec virt-manager.


Docker

Le builder docker construit une image à partir d'une image de base sans Dockerfile. Il démarré un container, y applique les provisioners, puis le commite comme nouvelle image.

packer {
  required_plugins {
    docker = {
      source  = "github.com/hashicorp/docker"
      version = "~> 1"
    }
  }
}

source "docker" "ubuntu" {
  image  = "ubuntu:22.04"
  commit = true

  changes = [
    "ENV DEBIAN_FRONTEND=noninteractive",
    "ENTRYPOINT [\"/usr/bin/supervisord\"]"
  ]
}

build {
  sources = ["source.docker.ubuntu"]

  provisioner "shell" {
    inline = [
      "apt-get update -y",
      "apt-get install -y nginx supervisor",
      "apt-get clean"
    ]
  }

  post-processor "docker-tag" {
    repository = "monregistre/nginx-base"
    tags       = ["latest", "22.04"]
  }
}

Google Cloud (Compute Engine)

Le builder googlecompute crée une image Compute Engine dans un projet GCP. L'authentification utilisé Application Default Credentials ou un compte de service.

source "googlecompute" "base" {
  project_id   = var.project_id
  source_image_family = "ubuntu-2204-lts"
  zone         = "europe-west1-b"
  machine_type = "e2-medium"
  image_name   = "base-ubuntu-${local.timestamp}"
  image_family = "base-ubuntu"
  ssh_username = "packer"
}

Pour la configuration complète, les variables de build GCP et la validation : Configuration Packer GCP.


AWS (EC2 AMI)

Le builder amazon-ebs crée une AMI à partir d'une image source. source_ami_filter permet de cibler dynamiquement la dernière image officielle.

packer {
  required_plugins {
    amazon = {
      source  = "github.com/hashicorp/amazon"
      version = "~> 1"
    }
  }
}

source "amazon-ebs" "ubuntu" {
  region        = "eu-west-1"
  instance_type = "t3.micro"
  ssh_username  = "ubuntu"

  source_ami_filter {
    filters = {
      name                = "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"
      root-device-type    = "ebs"
      virtualization-type = "hvm"
    }
    owners      = ["099720109477"] # Canonical
    most_recent = true
  }

  ami_name        = "base-ubuntu-${local.timestamp}"
  ami_description = "Image Ubuntu 22.04 de base"

  tags = {
    Name    = "base-ubuntu"
    Builder = "packer"
  }
}

build {
  sources = ["source.amazon-ebs.ubuntu"]

  provisioner "shell" {
    inline = [
      "sudo apt-get update -y",
      "sudo apt-get install -y unattended-upgrades"
    ]
  }
}

L'authentification AWS utilise les variables d'environnement AWS_ACCESS_KEY_ID et AWS_SECRET_ACCESS_KEY, ou un rôle IAM associe à la machine de build.


Azure (Managed Image)

Le builder azure-arm crée une Managed Image dans un Resource Group Azure. L'authentification se fait via un Service Principal.

packer {
  required_plugins {
    azure = {
      source  = "github.com/hashicorp/azure"
      version = "~> 2"
    }
  }
}

source "azure-arm" "ubuntu" {
  client_id       = var.client_id
  client_secret   = var.client_secret
  subscription_id = var.subscription_id
  tenant_id       = var.tenant_id

  managed_image_resource_group_name = "rg-images"
  managed_image_name                = "base-ubuntu-${local.timestamp}"

  os_type         = "Linux"
  image_publisher = "Canonical"
  image_offer     = "0001-com-ubuntu-server-jammy"
  image_sku       = "22_04-lts"

  location = "West Europe"
  vm_size  = "Standard_B2s"

  azure_tags = {
    builder = "packer"
  }
}

build {
  sources = ["source.azure-arm.ubuntu"]

  provisioner "shell" {
    inline = [
      "sudo apt-get update -y",
      "sudo apt-get upgrade -y",
      "/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0"
    ]
  }
}

La commande waagent -deprovision est obligatoire avant la capture : elle generalise l'image en supprimant les données spécifiques à l'instance.


OpenStack

Le builder openstack crée une image dans Glance via l'API OpenStack. Les credentials sont fournis via les variables d'environnement standard (OS_AUTH_URL, OS_USERNAME, etc.) ou directement dans le template.

packer {
  required_plugins {
    openstack = {
      source  = "github.com/hashicorp/openstack"
      version = "~> 1"
    }
  }
}

source "openstack" "ubuntu" {
  identity_endpoint = var.os_auth_url
  username          = var.os_username
  password          = var.os_password
  tenant_name       = var.os_project_name
  region            = "RegionOne"

  source_image_name = "Ubuntu 22.04"
  flavor            = "m1.small"
  ssh_username      = "ubuntu"
  image_name        = "base-ubuntu-${local.timestamp}"

  networks = [var.network_id]
}

build {
  sources = ["source.openstack.ubuntu"]

  provisioner "shell" {
    inline = ["sudo apt-get update -y && sudo apt-get upgrade -y"]
  }
}

vSphere

Les builders vsphere-iso et vsphere-clone créent des templates VM dans vCenter. vsphere-iso démarré une VM à partir d'une ISO et automatise l'installation via boot_command + kickstart. vsphere-clone clone un template existant et y applique les provisioners.

Prérequis : Un vCenter accessible (port 443) avec les permissions adequates. Licences vSphere Enterprise Plus (ou VCF).

vsphere-iso (build from scratch)

packer {
  required_plugins {
    vsphere = {
      source  = "github.com/hashicorp/vsphere"
      version = "~> 1"
    }
  }
}

source "vsphere-iso" "rocky9" {
  vcenter_server      = var.vcenter_server
  username            = var.vcenter_username
  password            = var.vcenter_password
  insecure_connection = true

  datacenter = var.datacenter
  cluster    = var.cluster
  datastore  = var.datastore
  folder     = var.vm_folder

  vm_name        = "rocky9-template-{{timestamp}}"
  guest_os_type  = "rhel9_64Guest"
  CPUs           = 2
  RAM            = 4096
  disk_controller_type = ["pvscsi"]
  storage {
    disk_size             = 40960
    disk_thin_provisioned = true
  }
  network_adapters {
    network      = var.network
    network_card = "vmxnet3"
  }

  iso_paths = ["[${var.datastore}] ISO/Rocky-9-latest-x86_64-minimal.iso"]

  http_directory = "http"
  boot_wait      = "5s"
  boot_command = [
    "<up><wait>",
    "e<wait>",
    "<down><down><end>",
    " inst.ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg",
    "<leftCtrlOn>x<leftCtrlOff>"
  ]

  ssh_username = "packer"
  ssh_password = "packer"
  ssh_timeout  = "30m"

  convert_to_template = true
}

build {
  sources = ["source.vsphere-iso.rocky9"]

  provisioner "ansible" {
    playbook_file = "./ansible/playbook.yml"
    user          = "packer"
    extra_arguments = [
      "--scp-extra-args", "'-O'"
    ]
  }
}

vsphere-clone (clone d'un template existant)

source "vsphere-clone" "rocky9" {
  vcenter_server      = var.vcenter_server
  username            = var.vcenter_username
  password            = var.vcenter_password
  insecure_connection = true

  datacenter = var.datacenter
  cluster    = var.cluster
  datastore  = var.datastore
  folder     = var.vm_folder

  template     = "rocky9-base-template"
  vm_name      = "rocky9-docker-{{timestamp}}"
  linked_clone = false

  ssh_username = "packer"
  ssh_password = "packer"

  convert_to_template = true
}

build {
  sources = ["source.vsphere-clone.rocky9"]

  provisioner "ansible" {
    playbook_file = "./ansible/playbook.yml"
    user          = "packer"
  }
}

Pour la configuration complète, les variables de build vSphere et le kickstart : Configuration Packer VMware.


Comparatif des builders

Builder Authentification Format de sortie Plugin
googlecompute ADC / compte de service Image Compute Engine hashicorp/googlecompute
amazon-ebs IAM / variables d'env AMI hashicorp/amazon
azure-arm Service Principal Managed Image hashicorp/azure
qemu Aucune (local) qcow2 / raw hashicorp/qemu
docker Docker daemon / registre Image Docker hashicorp/docker
openstack Keystone Image Glance hashicorp/openstack
vsphere-iso vCenter user / service account Template vSphere hashicorp/vsphere
vsphere-clone vCenter user / service account Template vSphere hashicorp/vsphere