Packer is a tool to automate building machine images and it supports VMware, Amazon EC2, Docker, Google Compute, and others. This is very useful for infrastructure-as-code!

This article covers how to incrementally create Open Virtualization Format (OVF) images using Packer. What I mean is an api-node and a db-node can be based on the server-base-node, avoiding the repeated full ISO install for each... saving a lot of time.

Just a side note: Cloud providers are a bit limited when it comes to importing OVA images, so this article assumes a self-hosted VMware or VirtualBox setup. This limitation is probably not a problem since vendors have a wide selection of base images. Although, packer's focus is create development VMs that match the AWS production environments -- a bit different from my goal of reducing time building images.

Create the server-base image from ISO

We want the server-base to be created using an ISO kickstart installation (aka silent install) followed by updating the system and making it Ansible ready.

Here's a snippet of what the silent install and post-scripts look like in Packer:

{
  "builders": [
    {
      "type": "virtualbox-iso",
      "guest_os_type": "Fedora_64",
      "iso_url": "file:///...",
      "vm_name": "fedora-25-serverbase-x86_64",
      "http_directory": "http",
      "boot_wait": "5s",
      "boot_command": [
        "<tab> ",
        "inst.ks=http://{{.HTTPIP}}:{{.HTTPPort}}/ks.cfg ",
        "biosdevname=0 ",
        "net.ifnames=0 ",
        "<enter>"
      ],
      "format": "ova"
    }
  ],

  "provisioners": [{
    "type": "shell",
    "scripts": [
      "scripts/extra-packages.sh",
    ]
  }]
}

The builders section is the virtualbox-iso type which means it begins with an ISO and ends with an OVA. When running packer, it will boot the ISO and auto-type the boot_command in the bios, and provide the kickstart file over HTTP. That starts the silent installation. Easy! After the silent install completes we have packer provisioners where we execute our extra-packages.sh to further customize the image. An optional step is adding post-processors, such as creating a Vagrant box.

A complete example is my fedora-25-server-base buildnode.json. It does the silent install, creates a sudoer user, updates the system, and installs needed python packages for Ansible. Feel free to base your setup on my working example.

Create a customized OVA from server-base

With the server-base in hand, we save around 10 minutes using that OVA instead of repeating the ISO install.

Below we use the server-base OVA, install GUI packages with install-gui.sh, then install desktop apps (Atom, Chrome, Slack) using Ansible. Note that it's usually easier long term to customize using Ansible instead of the shell scripts.

{
  "builders": [
    {
      "type": "virtualbox-ovf",
      "source_path": "file://{{user `pwd`}}/server-base.ova",
      "vm_name": "fedora-25-desktop-x86_64",
      "boot_wait": "5s",
      "format": "ova"
    }
  ],

  "provisioners": [
   {
      "type": "shell",
      "scripts": [
        "scripts/install-gui.sh"
      ]
    },
    {
      "type": "ansible",
      "playbook_file": "ansible/playbook.yml"
    }
  ]
}

The code above comes from my Fedora 25 Desktop template. Be sure to read more about Ansible at their site.

Conclusion

So there we have it! A series of customized Fedora OVAs using intermediate images, avoiding the redundant and time-consuming ISO installs. The images are highly customized using shell scripts and Ansible playbooks. And the best part? All of it is source controlled.