Create vSphere Template with Packer

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

Fountain pen and a notebook

Photo by Aaron Burden | Unsplash

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"
        }
      ]
   ]
}
1Builder (building the vmware itself)
2Provisioner (run some scripts on the new deployed machine)
3Post-Processor (upload to VMware vSphere)
4The order is important, or Terraform can’t recognize the vm tools
5Post-Processor to upload the VM to vSphere
6Post-Processor to tag it as template
7I 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.

Author
Add a comment
Error
There was an error sending your comment, please try again.
Thank you!
Your comment has been submitted and will be published once it has been approved.

Your email address will not be published. Required fields are marked with *

Suggested Reading
Aaron Burden: Fountain pen and a notebook

My last article showed how to build a server template with Packer.

Now we want to use this template to create some servers on VMware vSphere. DNS will be registered manually and all IP addresses will be defined as fixed in the config files.

Read in about 6 min
Card image cap

I create a lot of virtual machines during the week to test deployments, or try to digg into problems of deployments. In the past I used Vmware Workstation, Oracle VirtualBox or MS HyperV on my desktops, but I also used Vmware ESX. I tried to use Vagrant and Packer to prepare images and distribute them, but wasn’t satisfied at all.

Read in about 6 min
Aaron Burden: Fountain pen and a notebook

I use Shaarli since ages to collect links, notes and bookmarks. I worked a little bit on that collection and started to share some as public lists.

On my mobile device I bought a license for Stakali, it fits perfectly into my workflows. I often search on my mobile and share the link through Stakali to my desktop. Stakali just needs the URL and the API Key of Shaarli, but I got errors. So I analyzed the source and app with:

Stakali has an option to disable SSL Key checking, so no need to use any more tools to intercept the traffic. On Android you normally have to disable SSL Pinning. Here is a good start to learn how to do this.

Even with enabled API it didn’t work. First I used the default .htaccess, but got Error 500 accessing the api.

Read in about 3 min