Packer Crash Course

Packer Crash Course

Let's Explore Automation Tool…

Topics

  • What is Packer?

  • What Packer Supports?

  • A bit more deep dive into Packer's supported platforms!

  • Installation and set-up

  • Paker Components

  • Demo Shubham Gupta

Introduction to Packer

Packer is an open-source tool developed by HashiCorp that automates the process of building machine and container images for multiple platforms from a single source configuration. It helps to create consistent, reliable, and identical images for various environments, which is essential in the world of DevOps and Infrastructure as Code (IaC).

In summary, Packer enables users to create portable, reproducible, and version-controlled images that can be easily deployed across different environments, improving the overall efficiency and reliability of infrastructure management.

What Packer Supports?

Platforms and Builders: Supports AWS, GCP, Azure, VirtualBox, VMware, Docker, and more for image creation.

Provisioners: Works with Shell, Ansible, Puppet, and Chef to install and configure software within images.

Post-processors: Customizes and prepares output images for deployment, enhancing the final image.

System Requirements

Operating System: Packer is compatible with most major operating systems, including: a. Windows b. macOS c. Linux (various distributions)

Hardware: Packer doesn't have specific hardware requirements, as it primarily depends on the resources needed by the builders, Provisioners, and post-processors used.

Software Dependencies: Packer is a standalone binary and doesn't have any external software dependencies. However, some builders or Provisioners might require additional software or utilities installed on the system. For example:

a. VirtualBox or VMware for building virtual machine images.

b. Docker for building container images.

c. Ansible, Puppet, or Chef for their respective Provisioners.

Network: A stable internet connection is necessary to download Packer and access cloud-based builders, such as AWS, GCP, and Azure.

It’s time to Install Packer

Go to Packer's official site for installation

https://developer.hashicorp.com/packer/downloads?product_intent=packer

Select Operating System & Install

Linux:

wget -O- apt.releases.hashicorp.com/gpg | sudo gpg — dearmor -o/usr/share/keyrings/hashicorp-archive-keyring.gpg

echo “deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] apt.releases.hashicorp.com $(lsb_release -cs) main” | sudo tee/etc/apt/sources.list.d/hashicorp. List

sudo apt update && sudo apt install packer

Mac:

brew tap hashicorp/tap

brew install hashicorp/tap/packer

Windows:

Download: releases.hashicorp.com/packer/1.8.6/packer_..

Check version: packer version



Packer components

Templates are a core component of Packer and serve as the starting point for creating machine and container images. They define the desired configuration and settings of the image to be built, including the builders, provisioners, and post-processors to be used.

A Packer template is a JSON or HCL (HashiCorp Configuration Language) file that contains the following main sections: Variables, Builders, Provisioners, Post- processors.

Variables

What are Variables in Packer?

Variables in Packer templates allow you to parameterize your configurations, making them more flexible and reusable. You can define variables in the template and use them throughout the configuration file. In HCL, variables are defined in the variable block, and their values can be referenced using the var keyword.

Define variables:

variable “aws_access_key” {
type = string
description = “Your AWS Access Key”
sensitive = true
}

variable “aws_secret_key” {
type = string
description = “Your AWS Secret Key”
sensitive = true
}

variable “region” {
type = string
default = “us-west-2”
}

In this example:
We’ve defined three variables: aws_access_key, aws_secret_key, and region.
The type attribute specifies the data type of the variable, while the default attribute assigns a default value if no value is provided. The description attribute provides a human-readable description of the variable, and the sensitive attribute marks a variable as sensitive, ensuring that its value is not exposed in logs or output.

Pass variable values via the command line:
You can pass variable values when running packer build using the -var flag followed by the variable name and value in the format key=value:

packer build -var
‘aws_access_key=YOUR_AWS_ACCESS
_KEY’ -var
‘aws_secret_key=YOUR_AWS_SECRET_ KEY’ template.pkr.hcl

Pass variable values via file
In Packer, you can load variable values from a file using the -var-file flag when running the packer build command.
Create a variables file (for example, variables.pkrvars.hcl) containing the variable values in HCL format:
aws_access_key = “YOUR_AWS_ACCESS_KEY”
aws_secret_key = “YOUR_AWS_SECRET_KEY”
region = “us-west-2”

Variable Types

1. User variables:

User variables are defined by the user in the Packer template and can be used to parameterize the configuration. User variables are defined using the variable block in HCL, and their values can be referenced using the var keyword. You can assign default values to user variables and override them via the command line using the -var flag or -var-file flag when running the packer build. Supported Types are: string, number , bool and Complex : list(<TYPE>), set(<TYPE>), map(<TYPE>), object({<ATTR NAME> = <TYPE>, … }), tuple([<TYPE>, …])

Example: User Defined

variable “region” { type = string
default = “us-west-2”
}

2. Environment variables:

Environment variables are values set outside of the Packer template, typically at the operating system level. Packer can access environment variables using the env() function. This allows you to pass sensitive information, such as API keys or credentials, without hardcoding them in the template.

Example:

source “amazon-ebs”
“example” {
access_key = env(“AWS_ACCESS_KEY”)
secret_key = env(“AWS_SECRET_KEY”)
region = “us-west-2”
// … other configurations …
}

3. Local:

In Packer’s HCL (HashiCorp Configuration Language) templates, the locals block is used to define local values that can be used throughout the configuration file. Local values are like variables but are computed within the configuration and are not directly exposed as input variables or outputs. They are useful for simplifying complex expressions or for storing intermediate values to be used in multiple places within the template.

locals {
timestamp = regex_replace(timestamp(), “[- TZ:]”, “”)
base_image_name = “packer-example”
region = “us-west-2”
}

Builders

What is builders?

Builders are core components of Packer that create machine images for various platforms. Each builder is responsible for generating a machine image with a specific infrastructure provider or environment in mind. Packer supports a wide range of builders, enabling you to create images for different cloud providers, virtualization platforms, and containerization systems.

Amazon Web Services (AWS) Builders amazon-ebs: Creates Amazon Elastic Block Store-backed Amazon Machine Images (AMIs).
amazon-ebssurrogate: Creates EBS-backed AMIs from an existing instance as a base.
amazon-ebsvolume: Creates an EBS volume with data from a custom build process.
amazon-instance: Creates Amazon Instance Store-backed AMIs.

Google Cloud Platform (GCP) Builder:

google compute: Creates images for use with Google Compute Engine.

Microsoft Azure Builder:

azure-arm: Creates images for use with Microsoft Azure Resource Manager.

DigitalOcean Builder:

digital ocean: Creates images (called snapshots) for use with DigitalOcean.

Other Builders:

lxd: Creates images for use with LXD.

qemu: Creates images for use with QEMU.

scaleway: Creates images for use with Scaleway.

vagrant: Creates Vagrant boxes.

Virtualization Platform Builders:

virtualbox-iso: Creates VirtualBox images from an ISO file.

virtualbox-ovf: Creates VirtualBox images from an existing OVF/OVA file.

vmware-iso: Creates VMware images from an ISO file.

vmware-vmx: Creates VMware images from an existing VMX file.

parallels-iso: Creates Parallels Desktop images from an ISO file.

parallels-pvm: Creates Parallels Desktop images from an existing PVM file.

Containerization System Builders:

docker: Creates Docker images from a Dockerfile.

Source

What is source?

In Packer's HCL (HashiCorp Configuration Language) templates, the source block is used to define the configuration for a specific builder. A builder is a component in Packer that generates a machine image for a specific platform, such as Amazon Web Services (AWS), Google Cloud Platform (GCP), Microsoft Azure, VirtualBox, VMware, Docker, and others. The source block allows you to set the required configurations and attributes for the builder.

Amazon Web Services (AWS) - Amazon EBS Builder:

source "amazon-ebs" "example" {
 access_key = "YOUR_AWS ACCESS_KEY"
 secret_key = "YOUR_AWS SECRET_KEY"
 region = "us-west-2"
 source_ami = "ami-Oc55b159cbfafe1f0"
 instance_type = "t2.micro"
 ssh_username = "ubuntu"
 ami_name = "packer-example-${local.timestamp}"
}

Google Cloud Platform (GCP) - Compute Engine Builder:

source "googlecompute" "example" {
 project_id   = "YOUR_GCP_PROJECT_ID"
 source_image = "ubuntu-1804-bionic-v20211026"
 zone         ="us-central1-a"
 ssh_username = "ubuntu"
 image_name   = "packer-example-${local.timestamp}"
}

Microsoft Azure - Azure Resource Manager (ARM) Builder:

Source "Azure-am" "example {
  subscription_id  = "YOUR_AZURE_SUBSCRIPTION_ID" 
  client_id        = "YOUR_AZURE_CLIENT_ID"
  client_secret    = "YOUR_AZURE_CLIENT_SECRET"
  tenant_id        = "YOUR_AZURE_TENANT_ID" 

  location  = "East US"
  vm_size   = "Standard_D52_v2"

  source_image_reference {
  publisher  = "Canonical" 
  offer      = "UbuntuServer"
  sku        = "18.04-LTS"
  Version    = "latest"
 }

  image_publisher = "packer"
  image_offer     = "example"
  image_sku       = "bionic"
  image_version   = "${local.timestamp}"
}

DigitalOcean Builder:

source "digitalocean" "example" {
 api token     = "YOUR_DIGITALOCEAN_API_TOKEN"
 image         = "ubuntu-20-04-x64"
 region        = "nyc3"
 size          = "s-1vcpu-1gb"
 ssh username  = "root"
 snapshot_name = "packer-example-snapshot-${local.timestamp}"
}

Docker:

source "docker" "example" {
 image      = "ubuntu: 20.04"
 commit     = true
 changes    = ["CMD [\"/bin/bash\"]"]
 image name = "packer-example-docker:${local.timestamp}"
}

Build

What is build?

The build block in a Packer template is used to define the build process, including specifying the sources (builders) to use and any provisioning steps to apply during the build. It allows you to set up multiple sources and provisioners, and to control the order in which they are executed.

Simple Build Example

build {
 Sources = [
   "source.amazon-ebs.example",
 ]

 provisioner "shell" { 
    inline = [
     "sleep 30",
     "sudo apt-get update",
     "sudo apt-get upgrade -y", 
     "sudo apt-get install -y nginx",
    ]
  }
}

Multiple sources example

build {
   sources = [
     "source.amazon-ebs.example", 
     "source.googlecompute.example",
   ]

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

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

In this example, the build block specifies two sources (an Amazon EBS builder and a Google Compute Engine builder) and two shell provisioners. The provisioners are executed sequentially, first updating and upgrading the system, and then installing Nginx.

The build block is a critical part of a Packer template, as it orchestrates the build process by defining which sources to use and applying provisioners to customize the machine images.

Provisioners

What are Provisioners?

Provisioners in Packer are used to install and configure software on a machine image during the build process. They allow you to customize the image by executing scripts, copying files, or running configuration management tools. Packer supports a variety of provisioners, enabling you to choose the best tool for your specific use case.

Some popular provisioners supported by Packer include:

Shell

This provisioner allows you to execute shell scripts, either inline or from external files, on the target machine.

provisioner "shell" {  
 inline = [
  "sleep 30",
  "sudo apt-get update",  
  "sudo apt-get upgrade -y",
  "sudo apt-get install -y nginx",
 ]
}

Ansible

This provisioner allows you to execute Ansible playbooks on the target machine.

provisioner "ansible" {  
 playbook_file = "playbook.yml"
}

Chef

This provisioner allows you to run Chef cookbooks on the target machine, either in a client-server mode or in a solo mode.

provisioner "chef-solo" {  
 cookbooks_path = "cookbooks"
 run_list    = ["recipe[example::default]"]
}

File

This provisioner is used to copy files or directories from your local machine to the target machine.

provisioner "file" {
  source = "local-file.txt"  
  destination = "/tmp/remote-file.txt"
}

Puppet

This provisioner enables you to apply Puppet manifests to the target machine.

provisioner "puppet-masterless" {  
 manifest_file = "manifests/site.pp"
}

Salt

This provisioner enables you to apply Salt states to the target machine.

provisioner "salt-masterless" {  
 local_state_tree = "salt-states"
}

Post-processors

What are Post-processors?

Post-processors in Packer are used to modify or process the artifacts generated by a build after it completes. They allow you to perform additional tasks such as compressing, uploading, or customizing the output artifacts. Just like with provisioners, Packer supports a variety of post-processors, enabling you to choose the best tool for your specific use case.

Some popular post-processors supported by Packer include:

Artifice

This post-processor allows you to arbitrarily add files as artifacts, which can be useful when using Packer with external scripts or tools.

post-processor "artifice" {  
 files = ["output-file.txt"]
}

Shell-local

This post-processor allows you to execute shell scripts or commands on your local machine after a build completes.

post-processor "shell-local" {  
  inline = ["echo 'Build completed'"]
}

Manifest

This post-processor generates a JSON or YAML file containing metadata about the build artifacts. This can be helpful for tracking the artifacts or integrating with other tools.

post-processor "manifest" {  
  output = "manifest.json"  
  strip_path = true
}

Docker-import

This post-processor is used to import a Docker image into a Docker daemon after a build completes.

post-processor "docker-import" {  
  repository = "example/packer-docker"  
  tag    = "latest"
}

Docker-push

This post-processor pushes a Docker image to a Docker registry after a build completes.

post-processor "docker-push" {  
  login = true
  login_username = "username"  
  login_password = "password"
}

Vagrant

This post-processor creates a Vagrant box from the build artifacts. This is useful if you want to use the created machine image with Vagrant.

post-processor "vagrant" {
output = "output/{{.Provider}}.box"
}

Packer Template

A Packer template is a configuration file written in HashiCorp Configuration Language (HCL) that defines the sources (builders), provisioners, and post-processors for creating machine images. The template structure consists of the following main sections:

1.Variables: Define input variables, local variables, and use built-in variables.

2.Sources: Configure the builders for various platforms (e.g., AWS, GCP, Azure, Docker, VirtualBox, etc.).

3.Builds: Specify the build process, including the sources to use and the provisioning steps to apply during the build.

4.Provisioners: Install and configure software on the machine image during the build process.

5.Post-processors: Perform additional tasks on the artifacts generated by the build after it completes.

Packer Template Example

Let's Connect