Shell Provisioner in Packer

black laptop computer turned on showing computer codes
Reading Time: 3 minutes


Packer

Packer is an open-source tool. It allows us to create machine images. It can be used for multiple platforms from a single source template. A common use case is creating images that can be used later in cloud infrastructure. We will use shell Provisioner to install or execute our own script while creating machine images.

Basically, It can work with JSON as well as HCL language which is developed by Harshicorp. In this blog, we will use JSON files to create a machine image and the required package for the image. You can read this blog to get basic knowledge of packer.

Shell Provisioner

Shell provisioning is the easiest way to get the software installed and configured on a machine. Simply We can write a script according to our requirements. When we build that machine image, all the required packages or mentioned packages in the script will be installed and created an AMI. Later that AMI can be used to create a new AWS instance.

Example:

{
  "type": "shell",
  "inline": ["echo Knoldus"]
}

Here:

  • Type is use to define the provisioner type basically which is Shell type.
  • Inline is use to pass the shell command.

Now, We will try to create an AMI and run a shell script to install different packages. We will create an AWS instance with the same machine image and will have all the packages which we have installed before.

Steps to use shell provisioner:

Step-1

First, We need to set the environment variable for the packer with the below command:

export ACCESS_KEY=<access key>
export SECRET_KEY=<secret key>

Step-2

Create a file with this <file_name.json> name and this file will look like this:

{
    "variables":{
        "access_key": "{{env `ACCESS_KEY`}}",
        "secret_key": "{{env `SECRET_KEY`}}"
        },
    "builders": [
        {
            "type": "amazon-ebs",
            "access_key": "{{user `access_key`}}",
            "secret_key": "{{user `secret_key`}}",
            "region": "us-east-1",
            "ami_name": "blog-ami-nginx",
            "source_ami": "ami-04505e74c0741db8d",
            "instance_type": "t2.micro",
            "ssh_username": "ubuntu"

        }
    ],
    "provisioners": [
        {
            "type": "shell",
            "inline":["sudo apt-get update", "sudo apt-get install nginx -y"]
        }

    ]

}

Step-3

In this step, We can just build the image. Follow the below command to build:

packer build <file_name.json>

But the problem occurs here. Suppose that we want to install lots of packages then we need to write the lots of commands.

{
    "inline": [
        "sudo apt-get update",
        "sudo apt-get upgrade -y"
        "sudo apt-get install tree",
        "sudo apt-get install nginx -y",
        "sudo systemctl start nginx"

    ]
}

In the above example, I have considered only five commands but when we need to write a script to install the package or do other things then it will look very messy. To overcome this problem, We can write a script and then pass the name of that script in shell provisioner. Script will execute completely and do what we define in it. We can see the below example:


#ami_build.json 
{
    "variables":{
        "access_key": "{{env `ACCESS_KEY`}}",
        "secret_key": "{{env `SECRET_KEY`}}"
        },
    "builders": [
        {
            "type": "amazon-ebs",
            "access_key": "{{user `access_key`}}",
            "secret_key": "{{user `secret_key`}}",
            "region": "us-east-1",
            "ami_name": "blog-ami-nginx",
            "source_ami": "ami-04505e74c0741db8d",
            "instance_type": "t2.micro",
            "ssh_username": "ubuntu"

        }
    ],
    "provisioners": [
        {
            "type": "shell",
            "script": "setup.sh",
            "pause_before": "10s",
            "timeout": "10s"
        }

    ]

}

Here:

pause_before is used to make the packer wait before executing the next script:

timeout It is used to stop the provisioner if it takes more time than the defined time.

#setup.sh

sleep 30
sudo apt-get update
sudo apt-get upgrade -y 
sudo apt-get install -y nginx
sudo systemctl start nginx
sudo apt-get install tree
packer build <file_name.json>

When packer builds AMI. We will create an AWS instance with the same machine image.

Now we will verify the package which we have mentioned in the script. All are installed or not.

Conclusion:

I have covered the basics of the shell provisioner. This is the easiest way to get the required package in the machine image and whenever we will create an instance with that image, we will get all packages. You can follow this documentation to learn more.

Written by 

Mohd Muzakkir Saifi is a Software Consultant at Knoldus Software. He loves to take deep dives into cloud technologies & different tools. His hobbies are playing gymnastics and traveling.

1 thought on “Shell Provisioner in Packer4 min read

Comments are closed.