Best practices around organizing/composing packer scripts to stay DRY?

Are there any features for composing packer scripts? And can packer scripts access each other locally?

If I have scriptA and scriptB is scriptB accessible to scriptA during runtime?

Are there any built-in features for reusable module sort of things I can use in my packer scripts? Like say a function that I can import and use in multiple packer scripts so im not duplicating a lot of boiler kind of code multiple scripts might need to use?

1 Like

I would love to know an answer to this as well. Does packer have any concept of a module that could reference a path or tagged git branch like terraform can?

I know Ansible can be used to somewhat approach this with collections, but I find Ansible to slow down builds too much, and I prefer not to use it now when bash does well in packer.

If by “script” you mean “template” (ie packer.json), I think that out of the box this would not be the case, but there are several cases where this would be desirable.

The HCL templates do provide some reusable blocks, but at a cursory glance, this applies to the source only. It would not allow you to reference blocks in a different template.

One way one might write “re-usable module” would be to us a jsonnet template, and use that to generate the Packer template you actually use to build the image.

https://jsonnet.org

In this way, you could write the general-purpose template in Jsonnet and invoke it with the relevant variables. It would generate the Packer template with the relevant blocks you want and you would have to maintain only one large template. There would be less duplication, and you would be able to test several scenarios at once.

The Jsonnet docs have an example covering some Hashi tools:
https://jsonnet.org/articles/fractal.2.html

Personal opinion

My personal experience has been that Jsonnet is only really useful when you have several different resource templates to maintain. I have personally never been entirely comfortable with it, but this may be because I have never truly needed it. Nevertheless, when one finds oneself wanting a library to call into service, this seems to be one of the “right” ways to do it.

1 Like

Hello,
is there any known feature request to extend the “re-usability”?
It would be really cool to have something like:

sources.pkr.hcl # containing multiple reusable sources
provisioners.pkr.hcl # containing multiple reusable provisioners
variables.pkr.hcl # ...
|-  use_case_1
    |- image1.pkr.hcl # referencing subset x of variables, sources and provisioners
|-  use_case_2
    |- image2.pkr.hcl # referencing a subset y of variables, sources and provisioners 

Where a call like packer build use_case_1/image1.pkr.hcl would kind of auto load the variables, sources and provisioners, maybe overwrite the sources/provisioners/variables based on the folder hierarchy and build the image. (Kind of similar to ansible…)

Edit: Of cause also for post-processors :slight_smile:

1 Like

I’m looking for a similar solution. I am provisioning Linux with packer, and I would like to make the shell provisioner modular. I want to split the inline shell commands in seperate files, so I can be more modular.

CAVEAT: I haven’t tried this yet.

You can divide up your template into multiple files.
Then you put the originals in a “library” folder, and symlink them to the folder where you want to use them.
Changes to the original affect all the copies.

In some cases, you might want to version the originals to match product versions, so when you add a feature to “provisioning product X V5”, you don’t break the provisioning of product X v4.