The Packer workflow for building images – Immutable Infrastructure with Packer

The Packer workflow comprises two steps – init and build.

As we already know, Packer uses plugins to interact with the cloud providers; therefore, we need to install them. To do so, Packer provides the init command.

Let’s initialize and install the required plugins using the following command:
$ packer init .

Installed plugin github.com/hashicorp/ansible v1.1.0 in “~/.config/packer/plugins/github. com/hashicorp/ansible/packer-plugin-ansible_v1.1.0_x5.0_linux_amd64”

Installed plugin github.com/hashicorp/azure v1.4.5 in “~/.config/packer/plugins/github. com/hashicorp/azure/packer-plugin-azure_v1.4.5_x5.0_linux_amd64”

As we can see, the plugin is now installed. Let’s now go ahead and build the image.

We use the build command to create an image using Packer. As we would need to pass values to variables, we will specify the variable values using a command-line argument, as in the following command:
$ packer build -var-file=”variables.pkrvars.hcl” .

Packer would build parallel stacks using both the webserver and dbserver configs.

Packer first creates temporary resource groups to spin up staging VMs:
==> azure-arm.webserver: Creating resource group …
==> azure-arm.webserver: -> ResourceGroupName : ‘pkr-Resource-Group-7dfj1c2iej’
==> azure-arm.webserver: -> Location : ‘East US’
==> azure-arm.dbserver: Creating resource group …
==> azure-arm.dbserver: -> ResourceGroupName : ‘pkr-Resource-Group-11xqpuxsm3’
==> azure-arm.dbserver: -> Location : ‘East US’

Packer then validates and deploys the deployment templates and gets the IP addresses of the staging VMs:
==> azure-arm.webserver: Validating deployment template …
==> azure-arm.webserver: Deploying deployment template …
==> azure-arm.webserver: -> DeploymentName : ‘pkrdp7dfj1c2iej’
==> azure-arm.webserver: Getting the VM’s IP address …
==> azure-arm.webserver: -> IP Address : ‘104.41.158.85’
==> azure-arm.dbserver: Validating deployment template …
==> azure-arm.dbserver: Deploying deployment template …
==> azure-arm.dbserver: -> DeploymentName : ‘pkrdp11xqpuxsm3’
==> azure-arm.dbserver: Getting the VM’s IP address …
==> azure-arm.dbserver: -> IP Address : ‘40.114.7.11’

Then, Packer uses SSH to connect with the staging VMs and provisions them with Ansible:
==> azure-arm.webserver: Waiting for SSH to become available…
==> azure-arm.dbserver: Waiting for SSH to become available…
==> azure-arm.webserver: Connected to SSH!
==> azure-arm.dbserver: Connected to SSH!
==> azure-arm.webserver: Provisioning with Ansible…
==> azure-arm.dbserver: Provisioning with Ansible…
==> azure-arm.webserver: Executing Ansible: ansible-playbook -e packer_build_ name=”webserver” -e packer_builder_type=azure-arm –ssh-extra-args ‘-o IdentitiesOnly=yes’ -e ansible_ssh_private_key_file=/tmp/ansible-key328774773 -i /tmp/packer-provisioner-ansible747322992 ~/ansible/webserver-playbook.yaml
==> azure-arm.dbserver: Executing Ansible: ansible-playbook -e packer_build_ name=”dbserver” -e packer_builder_type=azure-arm –ssh-extra-args ‘-o IdentitiesOnly=yes’ -e ansible_ssh_private_key_file=/tmp/ansible-key906086565 -i /tmp/packer-provisioner-ansible3847259155 ~/ansible/dbserver-playbook.yaml
azure-arm.webserver: PLAY RECAP * **
azure-arm.webserver: default: ok=7 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
azure-arm.dbserver: PLAY RECAP ***
azure-arm.dbserver: default: ok=11 changed=7 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Once the Ansible run is complete, Packer gets the disk details, captures the images, and creates the machine images in the resource groups we specified in the Packer configuration:
==> azure-arm.webserver: Querying the machine’s properties
==> azure-arm.dbserver: Querying the machine’s properties
==> azure-arm.webserver: Querying the machine’s additional disks properties …
==> azure-arm.dbserver: Querying the machine’s additional disks properties …
==> azure-arm.webserver: Powering off machine …
==> azure-arm.dbserver: Powering off machine …
==> azure-arm.webserver: Generalizing machine …
==> azure-arm.dbserver: Generalizing machine …
==> azure-arm.webserver: Capturing image …
==> azure-arm.dbserver: Capturing image …
==> azure-arm.webserver: -> Image ResourceGroupName: ‘packer-rg’
==> azure-arm.dbserver: -> Image ResourceGroupName: ‘packer-rg’
==> azure-arm.webserver: -> Image Name: ‘apache-webserver’
==> azure-arm.webserver: -> Image Location: ‘East US’
==> azure-arm.dbserver: -> Image Name: ‘mysql-dbserver’
==> azure-arm.dbserver: -> Image Location: ‘East US’

Finally, it removes the deployment object and the temporary resource group it created:
==> azure-arm.webserver: Deleting Virtual Machine deployment and its attached resources…
==> azure-arm.dbserver: Deleting Virtual Machine deployment and its attached resources…
==> azure-arm.webserver: Cleanup requested, deleting resource group …
==> azure-arm.dbserver: Cleanup requested, deleting resource group …
==> azure-arm.webserver: Resource group has been deleted.
==> azure-arm.dbserver: Resource group has been deleted.

It then provides the list of artifacts it has generated:
==> Builds finished. The artifacts of successful builds are:
–> azure-arm: Azure.ResourceManagement.VMImage:
OSType: Linux
ManagedImageResourceGroupName: packer-rg
ManagedImageName: apache-webserver
ManagedImageId: /subscriptions/Id/resourceGroups/packer-rg/providers/Microsoft.Compute/ images/apache-webserver
ManagedImageLocation: West Europe
OSType: Linux
ManagedImageResourceGroupName: packer-rg
ManagedImageName: mysql-dbserver
ManagedImageId: /subscriptions/Id/resourceGroups/packer-rg/providers/Microsoft.Compute/ images/mysql-dbserver

If we look at the packer-rg resource group, we will find that there are two VM images within it:

Figure 10.2 – Packer custom images

We’ve successfully built custom images with Packer!

Tip

It isn’t possible to rerun Packer with the same managed image name once the image is created in the resource group. That is because we don’t want to override an existing image accidentally. While you can override it by using the -force flag with packer build, you should include a version within the image name to allow multiple versions of the image to exist in the resource group. For example, instead of using apache-webserver, you can use apache-webserver-0.0.1.

It’s time to use these images and create our infrastructure with them now.