iac, cloud,

Packer by Hashicorp

Gini Gini Follow · 8 mins read
Packer by Hashicorp
Share this

Packer use cases and samples are kept in this GitHub Repo.

Photo by cottonbro from Pexels

Introduction

Packer is an open source tool for creating identical machine images for multiple platforms from a single source configuration.

Installing Packer

Download and install packer.

# packer on linux
curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
sudo apt-get update && sudo apt-get install packer

Create your first Packer file

Sample docker-ubuntu.pkr.hcl

packer {
  required_plugins {
    docker = {
      version = ">= 0.0.7"
      source = "github.com/hashicorp/docker"
    }
  }
}

source "docker" "ubuntu" {
  image  = "ubuntu:xenial"
  commit = true
}

build {
  name    = "learn-packer"
  sources = [
    "source.docker.ubuntu"
  ]
}

Init and Build Packer

# init packer
$ packer init .

# format packer files
$ packer fmt .

# validate packer files
$ packer validate .

# build
$ packer build .
# or
$ packer build docker-ubuntu.pkr.hcl

Adding provisioner

build {
  name = "learn-packer"
  sources = [
    "source.docker.ubuntu"
  ]
  provisioner "shell" {
    environment_vars = [
      "FOO=hello world",
    ]
    inline = [
      "echo Adding file to Docker Container",
      "echo \"FOO is $FOO\" > example.txt",
    ]
  }
  provisioner "shell" {
    inline = ["echo This provisioner runs last"]
  }
}

Variables

variable "docker_image" {
  type    = string
  default = "ubuntu:xenial"
}
$ touch example.pkrvars.hcl

docker_image = "ubuntu:bionic"

# build with varible file
$ packer build --var-file=example.pkrvars.hcl docker-ubuntu.pkr.hcl

Packer will automatically load any variable file that matches the name *.auto.pkrvars.hcl, without the need to pass the file via the command line.

Build image with command line flag

$ packer build --var docker_image=ubuntu:groovy .

Handling Sensitive Data

local "secret_key" {
  key = "${var.secret_key}"
  sensitive  = true
}

Packer Parallel Build

Add multiple sources

source "docker" "ubuntu" {
  image  = var.docker_image
  commit = true
}

source "docker" "ubuntu-bionic" {
  image  = "ubuntu:bionic"
  commit = true
}

Add multiple sources in build

build {
  name    = "learn-packer"
  sources = [
    "source.docker.ubuntu",
    "source.docker.ubuntu-bionic",
  ]
.
.

Packer Post-Processors

While provisioners are run against an instance while it is running, post-processors run only after Packer saves the instance as an image.

eg:

  • compress artifacts
  • upload artifacts
  • create some files

Adding a docker tag using post-processor

Post

build {
  name    = "learn-packer"
  .
  .
  post-processor "docker-tag" {
    repository = "learn-packer"
    tags       = ["ubuntu-xenial", "packer-rocks"]
    only       = ["docker.ubuntu"]
  }

  post-processor "docker-tag" {
    repository = "learn-packer"
    tags       = ["ubuntu-bionic", "packer-rocks"]
    only       = ["docker.ubuntu-bionic"]
  }

Sequential post-processing steps

  • Use post-processors instead of post-processor
  • Use the post-processors (note the pluralization) block to create post-processing pipelines where the output of one post-processor becomes the input to another post-processor.
  post-processors {
    post-processor "docker-import" {
      repository = "swampdragons/testpush"
      tag        = "0.7"
    }
    post-processor "docker-push" {}
  }

Packer with AWS

Manage AWS Credentials for Packer

Configure environment variables.

$ export AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY
$ export AWS_SECRET_ACCESS_KEY=YOUR_SECRET_KEY

Important: Managing the AMIs created by Packer

  • Packer only builds images, make sure you cleanup if AMI is not needed anymore
  • Remove the AMI by first deregistering it on the AWS AMI management page.
  • Remember to delete the associated snapshot on the AWS snapshot management page.

Add provisioner to template

Using provisioners allows you to completely automate modifications to your image. You can use,

  • shell scripts
  • file uploads
  • tools like Chef or Puppet

Inside the build block,

  provisioner "shell" {
    environment_vars = [
      "FOO=hello world",
    ]
    inline = [
      "echo Installing Redis",
      "sleep 30",
      "sudo apt-get update",
      "sudo apt-get install -y redis-server",
      "echo \"FOO is $FOO\" > example.txt",
    ]
  }

Using Variable to Manage AMI Name

Remember to clean up exising AMI or use different AMI name when you create as AMI name should be unique in AWS.

Automate the AMI naming using local variable and timestamp.

variable "ami_prefix" {
  type    = string
  default = "learn-packer-linux-aws-redis"
}

locals {
  timestamp = regex_replace(timestamp(), "[- TZ:]", "")
}

and

source "amazon-ebs" "ubuntu" {
   ami_name      = "${var.ami_prefix}-${local.timestamp}"
   ## ...
}

Creating Vagrant Boxes from AMI

Add vagrant post-processor

build {
  name    = "learn-packer"
  sources = [
    "source.amazon-ebs.ubuntu",
    "source.amazon-ebs.ubuntu-focal"
  ]
  .
  .

  provisioner "shell" {
    inline = ["echo This provisioner runs last"]
  }

  post-processors {
    post-processor "vagrant" {}
    post-processor "compress" {}
  }
}
Gini
Written by Gini Follow
Backpacker, Foodie, Techie

Latest Stories

Featured