Packer is a tool developed by Hashicorp , used to automate the building of machine images. Machine images can be used to build virtual machines in the Cloud or locally, with the exact specifications required for the virtual machine. Packer can also be used to provision these images. Packer makes use of templates written in JSON(Javascript Object Notation) to set the specifications for the template.
In this article we will build an Amazon Machine Image(AMI), provision it with NginX web server and subsequently use it to spin off an AWS EC2 instance which will serve the NginX default homepage.
Install Packer
First, we need to install packer if you do not already have it installed. The examples in this article are run on a Linux Mint distribution of Linux and it will work on all Debian derived distributions like Ubuntu. If you use a different OS or other Linux distributions like Fedora/CentOS, visit the guide for installing Packer.
Open the terminal and Add the HashiCorp GPG key.
$ curl -fsSL apt.releases.hashicorp.com/gpg | sudo apt-key add -
Add the official HashiCorp Linux repository.
$ sudo apt-add-repository "deb [arch=amd64] apt.releases.hashicorp.com $(lsb_release -cs) main"
Update and install.
$ sudo apt-get update && sudo apt-get install packer
Voila, you have installed Packer. Run packer
to verify your installation, if all is well, it will return a short list of available Packer commands. You could also check your Packer version, packer will tell you if a newer version is available.
AWS IAM Credentials
To create am Amazon Machine Image(AMI), we need AWS credentials of an IAM user. IAM is Amazon Identity and Access Management service which can be used to create a known user on AWS. This user can generate a secret key and secret key ID to use to programmatically access AWS services and this is is what we will do next.
If you do not have an AWS account, it is about time you have that fixed. Head to AWS console click on create a new AWS account button, fill in your details including a debit/credit card details. If you face a any challenge in creating an account, you can check out this guide to create and activate your account.
Next, we will create an IAM user, navigate to the IAM service page from the AWS console, by typing IAM into the search box.
Click on Users, then click on Add User button.
Enter a username, and tick the boxes for programmatic access and console access. Then, move on to set permissions for this user.
The permissions the user has are the only functions the user will be able to perform on behalf of your AWS account. We will give this user AmazonEC2FullAccess.
Next, you can set tags for this user in key-value pairs, like packer, tutorials etc. Next, you get to review all the choices you have made before creating the user.
After the user has been created, the credentials for the User will be generated and shown to you. You have to store these creadentials securely immediately as you will not be able to access them after this.
Parfait, we now have a new IAM user with progeammatic access to AWS EC2 services.
Packer Template
Packer templates are JSON files that configure the various components of Packer in order to create one or more machine images. This has the added benefit of being able to not only create and modify templates by hand, but also write scripts to dynamically create or modify templates.
Let's save our AWS credentials as environment variables in the terminal. Replace anaccesskey with the Access Key ID generated earlier and replace asecretkey with the IAM secret key for the User created.
export AWS_ACCESS_KEY_ID="anaccesskey"
export AWS_SECRET_ACCESS_KEY="asecretkey"
The following template will use a t2.micro EC2 instance to build an AMI and save it on your AWS Account.
{
"variables": {
"aws_access_key": "",
"aws_secret_key": ""
},
"builders": [
{
"type": "amazon-ebs",
"access_key": "{{user `aws_access_key`}}",
"secret_key": "{{user `aws_secret_key`}}",
"region": "us-east-1",
"source_ami_filter": {
"filters": {
"virtualization-type": "hvm",
"name": "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*",
"root-device-type": "ebs"
},
"owners": ["099720109477"],
"most_recent": true
},
"instance_type": "t2.micro",
"ssh_username": "ubuntu",
"ami_name": "packer-AWS-example-{{timestamp}}"
}
],
"provisioners": [
{
"type": "file",
"source": "./welcome.txt",
"destination": "/home/ubuntu/"
},
{
"type": "shell",
"inline": ["ls -al /home/ubuntu", "cat /home/ubuntu/welcome.txt"]
},
{
"type": "shell",
"script": "./startup_script.sh"
}
]
}
The first part of this template is variables. This is optional and it allows us to pass our AWS credentials as environment variables instead of passing them as command line arguments.
The builders part of the template is required, as it contains the configuration for our image. The variables imported are used as well as specifying the type of image, which is an EBS backed image. We also set our AWS region, AMI name, instance type for building, ssh username and the source AMI. The source AMI the base on which our image is built and this determines the OS of any machines spun off this image.
Provisioners are components of Packer that install and configure software within a running machine prior to that machine being turned into a static image. We are provisioning our image to copy a text file containing a welcome text to the Image and print out the contents of this text file. Then run a shell script which installs the Nginx web server on the image before making it static.
Save the template above as a JSON file. I will name mine template.json.
Build an Image
Validate your template with the command:
packer validate template.json
You should get a response saying Template validated successfully.
If all goes well, we are now ready to build our Image. Run:
packer build template.json
The output logs from the build will be printed to the terminal. The end of the output will inform us the build has finished and the ID of AMI created.
Next, we will spin an EC2 instance with our AMI. Navigate to the AWS Console AMI page, you should see details of the AMI you built.
With the AMI selected, click on blue Launch button in the top left part of the screen. This will take you to the instance launch wizard at the point after you have chosen an Image. Select the Machine type, t2.micro to take advantage of free tier.
Click on Next and accept the defaults for instance details, storage and tags. in the Configure Security Groups, select HTTP from the drop down.
Select Review and Launch, review your choices and select Launch.
Create a new key pair and download it to your machine. Then, Launch Instances
It will take a few minutes for the instance to launch. Navigate to the EC2 instances page to see the Instance. You might also see the Packer Builder Instance used by Packer to build the Image with a status of Terminated.
The instance will have a public IP address, visit this IP address or the Public IPv4 DNS on your favourite web browser and you will see the NginX default page served immediately.
Congratulations! You have built your machine image and succesfully deployed it. Automation with Packer is powerful, you can combine this bash scripting to configure and provision your application AMI as backups and for quick deployment on multiple servers or instances.
Cleaning up
Clean up after to avoid getting billed by AWS until you are ready. In the EC2 instances page, select the Instance State drop down and select Terminate Instance. Select Terminate again to confirm.
In the AMI management page, select the Actions dropdown menu and deregister the AMI selected. Then, navigate to the Snapshot management page, then delete the snapshot associated to the AMI.