Day 30–101 Days of DevOps — Introduction to Packer — Part 2

Prashant Lakhera
7 min readAug 7, 2021

Welcome to Day 30 of 101 Days of DevOps. On Day 29, we have discussed the basics of Packer https://www.101daysofdevops.com/courses/101-days-of-devops/lessons/day-29-introduction-to-packer-part-1/. Let extend that concept further and dig more into Packer concepts.

To view the complete course, please check the below url.

For more info, register via the below link

YouTube Channel link

  • Create a Basic Packer Template
{
"builders": [
{
"type": "amazon-ebs",
"region": "us-west-2",
"source_ami": "ami-0721c9af7b9b75114",
"instance_type": "t2.micro",
"ssh_username": "ec2-user",
"ami_name": "amazon-linux-packer-ami-1.0"
}
]
}
  • Let’s try to understand these fields.
* type: Each Builder has a mandatory type field, as we are building this image on AWS we are going to use amazon-ebs type filed* region: Where we want to build this image, as AMI ID differ based on region
* source_ami: This is image going to be launched on AWS and our image is based on this(In this example I am using AWS AMI)
* instance_type: I am using t2.micro as it comes under AWS free tier
* ssh_username: We need to tell packer which ssh username to utilize, as we are using AWS AMI, username is ec2-user
* ami_name: Now we need to tell packer AMI it need to create
  • The first step is to set up the environment variable
export AWS_ACCESS_KEY_ID=" "
export AWS_SECRET_ACCESS_KEY=" "
  • The second step is to validate the template and then build it
$ packer validate firsttemplate.packer
  • The next step is to build the image under debug mode. The advantage of using debug mode is packer is going to pause at each step, and you will know what the packer is doing under the hood.
packer build -debug firsttemplate.packer
Debug mode enabled. Builds will not be parallelized.
amazon-ebs: output will be in this color.==> amazon-ebs: Prevalidating any provided VPC information
==> amazon-ebs: Prevalidating AMI Name: amazon-linux-packer-ami-1.0
==> amazon-ebs: Pausing after run of step 'StepPreValidate'. Press enter to continue.
amazon-ebs:
Found Image ID: ami-0721c9af7b9b75114
==> amazon-ebs: Pausing after run of step 'StepSourceAMIInfo'. Press enter to continue.
==> amazon-ebs: Pausing after run of step 'StepNetworkInfo'. Press enter to continue.
==> amazon-ebs:
Creating temporary keypair: packer_60f60c69-0593-4a1b-ae16-04a19bca1517
amazon-ebs: Saving key for debug purposes: ec2_amazon-ebs.pem
==> amazon-ebs: Pausing after run of step 'StepKeyPair'. Press enter to continue.
==> amazon-ebs: Creating temporary security group for this instance: packer_60f60c80-6ecf-4d8c-56d1-d72222bddf4f
==> amazon-ebs: Authorizing access to port 22 from [0.0.0.0/0] in the temporary security groups...
==> amazon-ebs: Pausing after run of step 'StepSecurityGroup'. Press enter to continue.
==> amazon-ebs: Pausing after run of step 'StepIamInstanceProfile'. Press enter to continue.
==> amazon-ebs: Pausing after run of step 'StepCleanupVolumes'. Press enter to continue.
==> amazon-ebs: Launching a source AWS instance...
==> amazon-ebs: Adding tags to source instance
amazon-ebs: Adding tag: "Name": "Packer Builder"
amazon-ebs: Instance ID: i-0d1a1767d583be063
==> amazon-ebs: Waiting for instance (i-0d1a1767d583be063) to become ready...
amazon-ebs: Public DNS: ec2-34-210-120-197.us-west-2.compute.amazonaws.com
amazon-ebs: Public IP: 34.210.120.197
amazon-ebs: Private IP: 172.31.22.36
==> amazon-ebs: Pausing after run of step 'StepRunSourceInstance'. Press enter to continue.
==> amazon-ebs: Pausing after run of step 'StepGetPassword'. Press enter to continue.
==> amazon-ebs: Pausing after run of step 'StepCreateSSMTunnel'. Press enter to continue.
==> amazon-ebs: Using SSH communicator to connect: 34.210.120.197
==> amazon-ebs: Waiting for SSH to become available...
==> amazon-ebs: Connected to SSH!
==> amazon-ebs: Pausing after run of step 'StepConnect'. Press enter to continue.
==> amazon-ebs: Pausing after run of step 'StepSetGeneratedData'. Press enter to continue.
==> amazon-ebs: Pausing after run of step 'StepProvision'. Press enter to continue.
==>
amazon-ebs: Pausing after run of step 'StepCleanupTempKeys'. Press enter to continue.
==> amazon-ebs: Stopping the source instance...
amazon-ebs: Stopping instance
==> amazon-ebs: Waiting for the instance to stop...
==> amazon-ebs: Pausing after run of step 'StepStopEBSBackedInstance'. Press enter to continue.
==> amazon-ebs: Pausing after run of step 'StepModifyEBSBackedInstance'. Press enter to continue.
==> amazon-ebs: Pausing after run of step 'StepDeregisterAMI'. Press enter to continue.
==> amazon-ebs:
Creating AMI amazon-linux-packer-ami-1.0 from instance i-0d1a1767d583be063
amazon-ebs: AMI: ami-0e4c3651dc6e441df
==> amazon-ebs: Waiting for AMI to become ready...
==> amazon-ebs: Pausing after run of step 'stepCreateAMI'. Press enter to continue.
==> amazon-ebs: Pausing after run of step 'StepAMIRegionCopy'. Press enter to continue.
==> amazon-ebs: Pausing after run of step 'StepModifyAMIAttributes'. Press enter to continue.
==> amazon-ebs: Pausing after run of step 'StepCreateTags'. Press enter to continue.
==> amazon-ebs: Pausing before cleanup of step 'StepCreateTags'. Press enter to continue.
==> amazon-ebs: Pausing before cleanup of step 'StepModifyAMIAttributes'. Press enter to continue.
==> amazon-ebs: Pausing before cleanup of step 'StepAMIRegionCopy'. Press enter to continue.
==> amazon-ebs: Pausing before cleanup of step 'stepCreateAMI'. Press enter to continue.
==> amazon-ebs: Pausing before cleanup of step 'StepDeregisterAMI'. Press enter to continue.
==> amazon-ebs: Pausing before cleanup of step 'StepModifyEBSBackedInstance'. Press enter to continue.
==> amazon-ebs: Pausing before cleanup of step 'StepStopEBSBackedInstance'. Press enter to continue.
==> amazon-ebs: Pausing before cleanup of step 'StepCleanupTempKeys'. Press enter to continue.
==> amazon-ebs: Pausing before cleanup of step 'StepProvision'. Press enter to continue.
==> amazon-ebs: Pausing before cleanup of step 'StepSetGeneratedData'. Press enter to continue.
==> amazon-ebs: Pausing before cleanup of step 'StepConnect'. Press enter to continue.
==> amazon-ebs: Pausing before cleanup of step 'StepCreateSSMTunnel'. Press enter to continue.
==> amazon-ebs: Pausing before cleanup of step 'StepGetPassword'. Press enter to continue.
==> amazon-ebs: Pausing before cleanup of step 'StepRunSourceInstance'. Press enter to continue.
==> amazon-ebs:
Terminating the source AWS instance...
==> amazon-ebs: Pausing before cleanup of step 'StepCleanupVolumes'. Press enter to continue.
==> amazon-ebs: Cleaning up any extra volumes...
==> amazon-ebs: No volumes to clean up, skipping
==> amazon-ebs: Pausing before cleanup of step 'StepIamInstanceProfile'. Press enter to continue.
==> amazon-ebs: Pausing before cleanup of step 'StepSecurityGroup'. Press enter to continue.
==> amazon-ebs:
Deleting temporary security group...
==> amazon-ebs: Pausing before cleanup of step 'StepKeyPair'. Press enter to continue.
==> amazon-ebs:
Deleting temporary keypair...
==> amazon-ebs: Pausing before cleanup of step 'StepNetworkInfo'. Press enter to continue.
==> amazon-ebs: Pausing before cleanup of step 'StepSourceAMIInfo'. Press enter to continue.
==> amazon-ebs: Pausing before cleanup of step 'StepPreValidate'. Press enter to continue.
Build 'amazon-ebs' finished after 28 minutes 27 seconds.==> Builds finished. The artifacts of successful builds are:
-->
amazon-ebs: AMIs were created:
us-west-2: ami-0e4c3651dc6e441df
  • These are the steps involved while creating AMI using packer
1: Pre-validating the existing image
2: Creating temporary Key Pair
3: Add port 22 in the security group
4: Creating a temporary instance
5: Building an AMI
6: Cleaning up all resources

Packer Variables

  • Variables declaration in packer is pretty simple
  • To define a variable
{
"variables": {
"aws_region": "us-west-2"
},
  • To use it
"builders": [{
"type": "amazon-ebs",
"region": "{{user `aws_region`}}"
}],

Packer Environment Variables

  • Everything will be the same except use keyword env
{
"variables": {
"aws_region": "{{env `AWS_REGION`}}"
}
  • To build it using packer
packer build -var 'aws_region=us-west-2' <packer-file>

Packer Built-In Function

  • clean_ami_name
* It's specific to Amazon and it remove unwanted characters
* eg: {{ "v:01" | clean_ami_name }} in this case : is unwanted character
* Output: v-01
  • Timestamp
* Setting up unix timestamp
  • To use it
"ami_name": "centos-packer-example-1.0-{{isotime | clean_ami_name}}"

Provisioners in Packer

Provisioners in packer is used to install and configure the machine image after booting. Some of the common use cases for provisioners are:

  • Downloading the application code
  • Kernel patching
  • Package installation
  • Creating users

Some of the most provisioner types are:

  • File
  • Script
  • Configuration Management

File Provisioner

  • This is one of the heavily used provisioners in a packer, as this will get our files into an immutable image.
  • File provisioner also supports directory copying.

NOTE: File Provisioner is not designed to set permission, so make sure to copy your file to a temporary location and then copy it back to your desired location

* Here type is file
* We need to specify from where we need to copy the file(I created a file called mytestfile)
* Destination where we want to copy the file
  • Now run the packer build.
  • You will see something like this, uploading <file name>

Script Provisioners

  • These are OS-specific provisioner
# Linux* Local Shell
* Remote Shell(Run the script on the machine where packer is building)# Windows* Powershell(Similar to Remote Shell)
* Windows Shell(batch script)
* Windows Restart
* Here we are using script provisioner
* Then script you are going to execute
  • The script is pretty simple here; I am trying to copy the file that was created earlier via file provisioner to the configuration(/etc) directory
#!/bin/bash -e
sudo cp /tmp/mytestfile /etcNOTE: -e in the shebang, it ensures that script executes with the error code so that packer ensure that script exit with proper exit code, if you don't want to use this you need to use inline provisioner

Output

==> amazon-ebs: Connected to SSH!==> amazon-ebs: Uploading mytestfile => /tmp/mytestfile1 items:  18 B / 18 B [=================================================================================================================================================================================] 0s==> amazon-ebs: Provisioning with shell script: script.sh

Building Packer Image with Provisioners(Ansible)

  • Ansible Playbook will look like this
# ansible.sh
#!/bin/bash -e
yum -y install epel-release
yum -y install ansible
  • Let’s break down the code
# Ansible Playbook* There we are trying to install apache and make sure its up after reboot# Packer Template
* Is similar to other provisioner and it just try to execute ansible playbook# Shell Script
* This is to make sure ansible is locally installed on that image

If you like to dig deeper into the AWS concept, please feel free to check my book.

Looking forward to you guys joining this journey and spend a minimum of an hour every day for the next 101 days on DevOps work and post your progress using any of the below mediums.

--

--

Prashant Lakhera

AWS Community Builder, Ex-Redhat, Author, Blogger, YouTuber, RHCA, RHCDS, RHCE, Docker Certified,4XAWS, CCNA, MCP, Certified Jenkins, Terraform Certified, 1XGCP