Packer
Variables
In the previous tutorial, you implemented your first provisioner. However, your Packer template is static. Currently if you want to change the contents of the file, you need to manually update your template.
You can use input variables to serve as parameters for a Packer build, allowing aspects of the build to be customized without altering Packer template. In addition, Packer variables are useful when you want to reference a specific value throughout your template.
In this tutorial, you will add Packer variables to parameterize your Packer build, making it more robust.
Prerequisites
This tutorial assumes that you are continuing from the previous tutorials. If not, follow the steps below before continuing.
Install Packer
Create a directory named
packer_tutorial
and paste the following configuration into a file nameddocker-ubuntu.pkr.hcl
.packer { required_plugins { docker = { version = ">= 1.0.8" source = "github.com/hashicorp/docker" } } } source "docker" "ubuntu" { image = "ubuntu:jammy" commit = true } 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"] } }
Initialize the Packer template.
$ packer init .
Once you have successfully initialized the template, you can continue with the rest of this tutorial.
Add variable to template
Add the following variable block to your docker-ubuntu.pkr.hcl
file.
variable "docker_image" {
type = string
default = "ubuntu:jammy"
}
Variable blocks declare the variable name (docker_image
), the data type (string
), and the default value (ubuntu:jammy
). While the variable type and default values are optional, we recommend you define these attributes when creating new variables.
Treat Packer variables as constants — you cannot update them during run time.
In your Packer template, update your source block to reference the docker_image
variable. Notice how the template references the variable as var.docker_image
.
Tip
The below snippet is formatted as a diff to give you context about
which parts of your configuration you need to change. Replace the content
displayed in red with the content displayed in green, leaving out the leading
+
and -
signs.
source "docker" "ubuntu" {
- image = "ubuntu:jammy"
+ image = var.docker_image
commit = true
}
Update the second provisioner to print the docker_image
variable. Notice that even though the docker_image
variable was used directly in the source block above, to embed a variable in another string you need to template it using the syntax ${}
, as shown when echoing docker_image
in the provisioner block.
build {
## ..
provisioner "shell" {
- inline = ["echo This provisioner runs last"]
+ inline = ["echo Running ${var.docker_image} Docker image."]
}
}
Build image
Build the image.
$ packer build docker-ubuntu.pkr.hcl
learn-packer.docker.ubuntu: output will be in this color.
==> learn-packer.docker.ubuntu: Creating a temporary directory for sharing data...
==> learn-packer.docker.ubuntu: Pulling Docker image: ubuntu:jammy
learn-packer.docker.ubuntu: jammy: Pulling from library/ubuntu
learn-packer.docker.ubuntu: Digest: sha256:eed7e1076bbc1f342c4474c718e5438af4784f59a4e88ad687dbb98483b59ee4
learn-packer.docker.ubuntu: Status: Image is up to date for ubuntu:jammy
learn-packer.docker.ubuntu: docker.io/library/ubuntu:jammy
==> learn-packer.docker.ubuntu: Starting docker container...
learn-packer.docker.ubuntu: Run command: docker run -v /Users/youruser/.packer.d/tmp176397065:/packer-files -d -i -t --entrypoint=/bin/sh -- ubuntu:jammy
learn-packer.docker.ubuntu: Container ID: 0ac5cf4617bb923ceffa0e27e48bf5cfea307676e45dae35ded7dab842d6e27b
==> learn-packer.docker.ubuntu: Using docker communicator to connect: 172.17.0.3
==> learn-packer.docker.ubuntu: Provisioning with shell script: /var/folders/s6/m22_k3p11z104k2vx1jkqr2c0000gp/T/packer-shell863456722
learn-packer.docker.ubuntu: Adding file to Docker Container
==> learn-packer.docker.ubuntu: Provisioning with shell script: /var/folders/s6/m22_k3p11z104k2vx1jkqr2c0000gp/T/packer-shell703813640
learn-packer.docker.ubuntu: Running ubuntu:jammy Docker image.
==> learn-packer.docker.ubuntu: Committing the container
learn-packer.docker.ubuntu: Image ID: sha256:e3aafb04d8d628514370617bdf949e9d5e2f0109cb92be63d230be63420e2811
==> learn-packer.docker.ubuntu: Killing the container: 0ac5cf4617bb923ceffa0e27e48bf5cfea307676e45dae35ded7dab842d6e27b
Build 'learn-packer.docker.ubuntu' finished after 10 seconds 43 milliseconds.
==> Wait completed after 10 seconds 43 milliseconds
==> Builds finished. The artifacts of successful builds are:
--> learn-packer.docker.ubuntu: Imported Docker image: sha256:e3aafb04d8d628514370617bdf949e9d5e2f0109cb92be63d230be63420e2811
The output is the same as before, but now the docker_image
variable is being used to specify that the "ubuntu:jammy"
base image should be used.
You'll know it worked if you see the Builds finished. The artifacts of successful builds...
message near the bottom.
Build image with variables
Since docker_image
is parameterized, you can define your variable before building the image. There are multiple ways to assign variables. The order of ascending precedence is: variable defaults, environment variables, variable file(s), command-line flag. In this section, you will define variables using variable files and command-line flags.
Build image with variable file
Create a file named example.pkrvars.hcl
.
$ touch example.pkrvars.hcl
Add the following snippet into it.
docker_image = "ubuntu:lunar"
Build the image with the --var-file
flag.
$ packer build --var-file=example.pkrvars.hcl docker-ubuntu.pkr.hcl
learn-packer.docker.ubuntu: output will be in this color.
==> learn-packer.docker.ubuntu: Creating a temporary directory for sharing data...
==> learn-packer.docker.ubuntu: Pulling Docker image: ubuntu:lunar
## ...
==> learn-packer.docker.ubuntu: Provisioning with shell script: /var/folders/s6/m22_k3p11z104k2vx1jkqr2c0000gp/T/packer-shell905783662
learn-packer.docker.ubuntu: Running ubuntu:lunar Docker image.
## ...
Notice how the build step runs the ubuntu:lunar
Docker image, the value for docker_image
defined by the variable file.
Note
Never commit sensitive values into source control.
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.
Rename your variable file so Packer automatically loads it.
$ mv example.pkrvars.hcl example.auto.pkrvars.hcl
Build the image and notice the Docker image running ubuntu:lunar
. The packer build .
command loads all the contents in the current directory.
$ packer build .
==> learn-packer.docker.ubuntu: Creating a temporary directory for sharing data...
==> learn-packer.docker.ubuntu: Pulling Docker image: ubuntu:lunar
## ...
learn-packer.docker.ubuntu: Running ubuntu:lunar Docker image.
==> learn-packer.docker.ubuntu: Committing the container
## ...
Build image with command line flag
Build the image, setting the variable directly from the command line.
$ packer build --var docker_image=ubuntu:focal .
learn-packer.docker.ubuntu: output will be in this color.
==> learn-packer.docker.ubuntu: Creating a temporary directory for sharing data...
==> learn-packer.docker.ubuntu: Pulling Docker image: ubuntu:focal
## ...
==> learn-packer.docker.ubuntu: Provisioning with shell script: /var/folders/s6/m22_k3p11z104k2vx1jkqr2c0000gp/T/packer-shell930656710
learn-packer.docker.ubuntu: Running ubuntu:focal Docker image.
## ...
Notice how the build step runs the ubuntu:focal
Docker image, the value for docker_image
defined by the command-line flag. The command-line flag has the highest precedence and will override values defined by other methods.
Next steps
In this tutorial, you made your Packer template more robust by parameterizing it with variables. Then, you defined your variables using variable files and command-line flags during the build step, learning variable definition order of precedence in the process. Continue to the next tutorial to create multiple images in parallel using the same template.
Refer to the following resources for additional details on the concepts covered in this tutorial:
- Read more about the Packer variables.
- Learn more about how to use Packer variable blocks.