How to run packer and terraform with a shell script.

Reading Time: 4 minutes

We all are tired of repeating the same steps for creating the image and instance in AWS. But no longer! After reading this blog you will make an image using Packer and an instance through Terraform with help a shell script. You should have prior knowledge of Packer and Terraform. Below, I have briefed them for your reference.

Packer is an open source tool for creating identical machine images for multiple platforms from a single source configuration. You can find more about packer at the official website – Packer doc

Terraform is a tool for building, changing, and versioning infrastructure safely and efficiently. Terraform can manage existing and popular service providers as well as custom in-house solutions. A good primer on Terraform can be found here – Terraform Doc

Amazon EC2’s simple web service interface allows you to obtain and configure capacity with minimal friction. It provides you with complete control of your computing resources and lets you run on Amazon’s proven computing environment.

Before we start make sure that your system ssh public key should be added in the AWS account. To find your system SSH key.

For Ubuntu system:

  1. Go to your home directory.
  2. Press ctrl+H to see the hidden file.
  3. There would be a folder named .ssh.
  4. open the file id_rsa.pub.
  5. This file contents the public SSH Key.

If that folder does not exist then you can run the following command. This will generate the ssh key.

Command: ssh-keygen

To generate ssh-key for ubuntu system you can refer the following link – DigitalOcean

To generate ssh-key for windows system you can refer the following link – Joyent

To Add SSH key in AWS account

  1. Click the username dropDown menu.
  2. Select the My Security Credentials. A new window will be open.
  3. Select the User item from the menubar on the left side.
  4. Select the Security Credentials tag.
  5. If score down the page you will find the upload SSH public key button click on the button.
  6. Paste your SSH key there.

Project Directory Structure

Let’s get started by creating our project directory structure. In the main project folder, create two folders – packer and terraform. Both folders will have the respective configuration file. The main project folder will three shell scripts which we will create.

-project_folder
     --packer
         ---packer.json
         ---docker_download1.sh
     --terraform
         ---demo_terraform.tf
         ---vars.tf
         ---provider.tf
         ---terraform.tfvar
     --build.sh
     --packer.sh
     --terraform.sh

In the packer folder, we will create a configuration file in JSON format which will be used to define how and what image we want to build. In packer terminology, it is called a template.

Below packer template will create an ec2 image with Docker installed in it.



This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters


{
"variables": {
"aws_access_key": "",
"aws_secret_key": "",
"aws_region": "us-east-1",
"version": "1.7.1",
"revision": "0",
"instance_type": "t2.micro",
"image_name" : "{{ env `IMAGE_NAME` }}"
},
"builders": [{
"type": "amazon-ebs",
"access_key": "{{user `aws_access_key`}}",
"secret_key": "{{user `aws_secret_key`}}",
"region": "{{user `aws_region`}}",
"instance_type": "{{user `instance_type`}}",
"ssh_username": "ubuntu",
"ami_name": "{{user `image_name`}}",
"ami_regions": "{{user `aws_region`}}",
"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
},
"launch_block_device_mappings": [
{
"device_name": "/dev/sda1",
"volume_size": 30,
"volume_type": "gp2",
"delete_on_termination": true
}
],
"ssh_pty": "true",
"tags": {
"Name": "bootstrap-{{user `owner`}}-{{user `environment`}}-{{timestamp}}",
"Role": "bootstrap",
"BuildDate": "{{isotime}}"
}
}],
"provisioners": [{
"type": "shell",
"environment_vars": [
"version={{user `version`}}"
],
"scripts": ["packer/docker_download1.sh"]
}]
}
view raw

packer.js

hosted with ❤ by GitHub

Explanation

The above template will do the following task.

  • create an image in AWS in us-east-1 region with the image name as defined by the environment variable.
  • Builder will build the ubuntu machine with some external memory.
  • Through provisioner key in JSON, we will install docker in AWS image.
  • docker_download1.sh script is the script through which docker is installed in the image.

Terraform

Now its time to create the instance of the image through terraform. The set of files used to describe infrastructure in terraform is simply known as a terraform configuration.



This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters


data "aws_ami" "ubuntu" {
most_recent = true
filter {
name = "name"
values = ["${var.image_name}"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
owners = [981997154569]
}
resource "aws_key_pair" "mykey" {
key_name = "mykey"
public_key = "${file("${var.PATH_TO_PUBLIC_KEY}")}"
}
resource "aws_instance" "bootstrap" {
ami = "${data.aws_ami.ubuntu.id}"
instance_type = "t2.micro"
key_name = "${aws_key_pair.mykey.key_name}"
count = "1"
provisioner "file" {
source = "program/hello-world.sh"
destination = "/tmp/hello-world.sh"
}
provisioner "remote-exec" {
inline = [
"chmod +x /tmp/hello-world.sh",
"/tmp/hello-world.sh",
]
}
connection {
user = "${var.INSTANCE_USERNAME}"
private_key = "${file("${var.PATH_TO_PRIVATE_KEY}")}"
}
}
output "ip" {
value = "${aws_instance.bootstrap.ami}"
}
output "name" {
value = "${var.image_name}"
}
view raw

terraform

hosted with ❤ by GitHub

Explanation

The above configuration will do the following task.

  • Data key of the terraform script will help us to find the ami_id of the image. In data key, there is a filter attribute that will filter the ami on the bases of the ami_name.
  • Resource “aws_instance bootstrap” will create the instance of the image that is filtered by the data key. Ami attribute value is given by the data key.
  • The connection attribute will make a connection with the new instance that is created through ssh key in it we mention the private key file path and the username of the remote system.
  • Resource “aws_key_pair mykey” mention the key pair name and public key file path which is used to make a secure connection.

To make it work we have to do one little work. As we have made the AWS instance through packer it acts as a normal machine. So if we want to install the docker in the AWS instance writing in the script is not enough. We have to make a connection to the instance then only we can install docker on the machine. To make the connection we have to add the security group in AWS.

To Add Security Group

  1. Login to your AWS account.
  2. Go to Services drop down to select the EC2.
  3. Left menuBar Under the heading NETWORK & SECURITY selects the Security Group. 
  4. Go to Inbound tag click the edit button a pop box will open.
  5. Select Add Rules.
  6. In Type tag, select the All TCP  item.
  7. In Source tag, selects My IP.
  8. Click the save button.

In vars.tf file we mention the variable’s value for terraform configuration file.



This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters


variable "AWS_ACCESS_KEY" {}
variable "AWS_SECRET_KEY" {}
variable "region" {
default="us-east-1"
}
variable "image_name" {
default = "ami_image_name"
}
variable "PATH_TO_PRIVATE_KEY" {
default = "mykey"
}
variable "PATH_TO_PUBLIC_KEY" {
default= "mykey.pub"
}
variable "INSTANCE_USERNAME" {
default = "ubuntu"
}
view raw

vars

hosted with ❤ by GitHub

Now is the time for the build script.

We will make one script called build.sh that will call two other scripts that will run the packer and terraform command. This script will run through two command line arguments – access key and secret key.



This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters


#!/usr/bin/env bash
echo "*** Deployment started"
usage() {
echo "(AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY) to be set"
exit 1
}
if [ ${#} -ne 2 ]; then
usage
fi
ACCESS_KEY=$1
SECRET_KEY=$2
export SSH_KEY_NAME
SSH_KEY_NAME="mykey"
export IMAGE_NAME
IMAGE_NAME="ubuntu-dockers"
sed -i -e "s/ami_image_name/${IMAGE_NAME}/g" terraform/vars.tf
echo "*** starting packer"
sh packer.sh $ACCESS_KEY $SECRET_KEY;
echo "*** starting terraform"
sh terraform.sh;
sed -i -e "s/${IMAGE_NAME}/ami_image_name/g" terraform/vars.tf
echo "*** Deployment complete"
view raw

build.sh

hosted with ❤ by GitHub

In line number 18 we are replacing default value of image name that is given vars.tf file. This is the name of which we have made the AWS image.
In line number 24 we again replacing the value of image_name with ami_image_name so that line number 18 can run again.
In line number 20 packer script is called with two command line parameter that is received by the build script.

packer script



This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters


#!/usr/bin/env bash
set -e
usage() {
echo "environment variable AWS_PROFILE or access keys (AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY) to be set"
exit 1
}
if [ ${#} -ne 2 ]; then
usage
fi
AWS_ACCESS_KEY=$1
AWS_SECRET_KEY=$2
run_packer() {
set -x
echo "enter into run packer"
packer build \
-var aws_access_key=$1\
-var aws_secret_key=$2\
packer/demo-packer.json
set +x
}
run_packer $AWS_ACCESS_KEY $AWS_SECRET_KEY
view raw

packer

hosted with ❤ by GitHub

The above script will run successfully if two command line arguments are given, otherwise, it will get terminated with a message “environment variable AWS_PROFILE or access keys (AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY) to be set“. From line number 20 to 23 packer build command is written that will call our above packer template.

Finally, the terraform script.



This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters


cd terraform
ssh-keygen -f mykey
terraform init
terraform plan\
-out out.terraform
terraform apply out.terraform
rm out.terraform KEY
view raw

terraform.sh

hosted with ❤ by GitHub

In line number 2, the command is for ssh key generation. This will create the ssh public key and private key to make the remote connection. The path for these keys has to be mentioned in vars.tf file.

Our work is done! We made the image and its instance using packer and terraform.

This is how we dynamically create our image and instance using the script. To run the build script again we have to change the image_name in the build.sh file as AWS won’t create an image with the same name.

This method has an advantage over creating an image using amazon interface as it requires repetitive manual tasks. However, with help of these scripts, we can create multiple instances easily.

To see the full code you can refer to the git link – Packer-terraform-project

For this blog, I referred to the following sites.

knoldus-advt-sticker

Written by 

Priyanka Thakur is a Software Consultant having 6 months of experience currently working at Knoldus Software LLP. She has done MCA at BVICAM, GGSIPU. She has a graduation degree in BCA from JIMS, GGSIPU. She is familiar with programming language' s such as C, Java, and Scala. She also has interest in Angular and Docker and currently working on Logam. She is dedicated, focused and hardworking person. Her interests are in to face new programming challenges because she believes these challenges produce opportunity. She is keen to learn new technologies. In her leisure time, she prefers reading about mythology, watching movies.

1 thought on “How to run packer and terraform with a shell script.6 min read

Comments are closed.