Create vSphere Template with Packer

· by Christoph Stoettner · Read in about 4 min · (796 words)

The last months I built a lot of environments for tests with IBM Connections Componentpack, Rancher, plain Kubernetes, IBM Domino and some more. In former years, I deployed single virtual machines, cloned them and created snapshots to "easily" jump back in cases of errors. Then I found Packer, which helped me to automate the first virtual machines on my local notebook.

Now I use Packer to create templates for VMware vSphere, which then are deployed and multiplied with Terraform. Terraform needs some packages installed in the template, that it can provision virtual machines on vSphere.

  • Open VM-Tools

  • Perl

You can find all files and scripts on Gitlab.

The definition is simplified to make it better readable. As best practise I would recommend to add a variabe section to the packer file, so you avoid to type the same information over and over again.

In this article I just prepare the template. Working with Terraform will be covered in a future post.

One thing more, to install additional software on the provisioned servers later, I will use Ansible. Ansible needs ssh and Python.

First CentOS template

To create a template for CentOS, we start with a kickstart file, which is used by Packer to install and configure the template.

Create a root password
echo 'import crypt,getpass; \
  print crypt.crypt(getpass.getpass(), "$5$16_CHARACTER_SALT_HERE")' | python -

Replace $16_CHARACTER_SALT_HERE with 16 random characters.

Example to generate 16 random characters
openssl rand -base64 24 | cut -c-16

Kickstart File

Simple kickstart file
install
lang en_US.UTF-8
keyboard de
timezone Europe/Berlin
auth --useshadow --enablemd5
services --enabled=NetworkManager,sshd
eula --agreed
ignoredisk --only-use=sda
reboot

bootloader --location=mbr
zerombr
clearpart --all --initlabel
part swap --asprimary --fstype="swap" --size=1024
part /boot --fstype xfs --size=200
part pv.01 --size=1 --grow
volgroup rootvg01 pv.01
logvol / --fstype xfs --name=lv01 --vgname=rootvg01 --size=1 --grow

authconfig --enableshadow --passalgo=sha256
rootpw --iscrypted $5$cnxfyyiayqjelmbt$4/Lq1vPDBp2BZznXcLukwVy4n0DPp6tX.PrCz7YA62B

%packages --nobase --ignoremissing
@core
%end

Packer JSON

To tell Packer how our template should be installed, start with following file:

{
  "builders": [  (1)
    {
      "type": "vmware-iso",
      "boot_command": [
         "<tab> text ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/kickstart-de.cfg<enter>"
      ],
      "communicator": "ssh",
      "guest_os_type": "centos7-64",
      "http_directory": "http",
      "iso_checksum_type": "sha256",
      "iso_checksum_url": "http://ftp.halifax.rwth-aachen.de/centos/7.6.1810/isos/x86_64/sha256sum.txt",
      "iso_url": "http://ftp.halifax.rwth-aachen.de/centos/7.6.1810/isos/x86_64/CentOS-7-x86_64-Minimal-1810.iso",
      "ssh_username":"root",
      "ssh_password":"password",  (7)
      "ssh_wait_timeout": "600s",
      "shutdown_command": "shutdown -P now",
      "version": 14
    }
  ],
  "provisioners": [ (2)
      {
          "type": "shell",
          "expect_disconnect": true,
          "execute_command": "sudo UPDATE=true bash '{{ .Path  }}'",
          "environment_vars": [
            "UPDATE=true"
          ],
          "scripts": [  (4)
            "script/epel.sh",
            "script/kernel.sh",
            "script/sshd.sh",
            "script/vmtools.sh",
            "script/update.sh",
            "script/reboot.sh",
            "script/ansible.sh",
            "script/cleanup.sh"
          ]
      }
  ],
  "post-processors": [ (3)
      [
        {
            "type": "vsphere",  (5)
            "cluster": "HMUC PWR HOSTS",
            "host": "vsphere.example.com",
            "datacenter": "HMUC",
            "resource_pool": "rp_hvie_devops",
            "username": "cstoettner@example.com",
            "password": "{{user `vsphere_password`}}",
            "datastore": "devops-01_sas_7.2k_raid10",
            "vm_name": "stoeps-centos-gpn19",
            "vm_folder": "devops",
            "vm_network": "vm-net-devops",
            "disk_mode": "thin",
            "insecure": "true",
            "overwrite": "true"
        },
        {
            "type": "vsphere-template",  (6)
            "host": "vsphere.example.com",
            "insecure": "true",
            "datacenter": "HMUC",
            "username": "cstoettner@example.com",
            "password": "{{user `vsphere_password`}}",
            "folder": "/devops/templates"
        }
      ]
   ]
}
1 Builder (building the vmware itself)
2 Provisioner (run some scripts on the new deployed machine)
3 Post-Processor (upload to VMware vSphere)
4 The order is important, or Terraform can’t recognize the vm tools
5 Post-Processor to upload the VM to vSphere
6 Post-Processor to tag it as template
7 I set the root password to password in the kickstart

The kickstart file generates the user root with password password. During the deployment with Terraform I disable the password login with passwd -l root, so the root user needs to use a ssh-key for authentication.

Thanks to Nico for the tip with passwd --lock.

This configuration file uses a lot of default values from VMware, like disk space, cpu count and so on. All these can be changed later during our Terraform deployment.

Within the Provisioner part, I use some scripts, to add:

  • EPEL repository

  • Install open-vm-tools, perl, python

  • Update all installed packages

  • Update the kernel to the latest version (in the moment 5.1)

    • The original CentOS kernel is quite old and the Docker support needs some tweaks like the usage of device-mapper, that’s the main reason for the update

  • Reboot (important to do this after the open-vm-tools installation, because without Terraform will not recognize the tools and not deploy)

  • Cleanup (deleting host keys, repositories and so on)

During my talk at GPN19, someone pointed me to Systemd machine id. I always ignored this, but I added the delete command to the cleanup script and the create command into my Terraform file. Thanks for this hint!

Create the template

packer build -var vsphere_password=My_Vsphere_password centos.json

I use a variable for the password, because I always check-in my definition files to git and I don’t want to have passwords there in the history.

I created a video of the creation, please try the command yourself, or have a look at it.

Now our template is uploaded to vSphere. Using it within Terraform will be another post.