No description
  • Dockerfile 100%
Find a file
2026-06-16 22:37:09 +02:00
.env.example init 2026-06-16 22:19:23 +02:00
.gitignore init 2026-06-16 22:19:23 +02:00
compose.yaml init 2026-06-16 22:19:23 +02:00
Dockerfile init 2026-06-16 22:19:23 +02:00
README.md Add SSH key setup instructions to README 2026-06-16 22:37:09 +02:00

Toolchain container

This directory is a toolchain container setup: Packer runs in an ephemeral Docker container, while the actual project (.pkr.hcl files, plugins, etc.) lives in a sibling directory on the host and is bind-mounted in.

hashicorp-packer/
├── packer-in-docker/             ← Compose, Dockerfile, .env (the runner)
└── insecure-user-with-docker/    ← Packer project (mounted into the container)

The container provides the toolchain (Packer version, shell, SSH keys). It is not a long-running service beside the project — each command is a one-off docker compose run.

Configuration

The project name and the Packer working directory are driven by COMPOSE_PROJECT_NAME. The default value lives in .env:

COMPOSE_PROJECT_NAME=insecure-user-with-docker

Compose uses the effective project name for:

  • the Docker Compose project name
  • the bind mount: ../${COMPOSE_PROJECT_NAME} on the host is mounted to /root/${COMPOSE_PROJECT_NAME} in the container

You can also set the project name at runtime. Precedence (highest to lowest):

  1. -p / --project-name on the command line
  2. COMPOSE_PROJECT_NAME in the shell environment
  3. COMPOSE_PROJECT_NAME in .env
  4. the name: field in compose.yaml (here: ${COMPOSE_PROJECT_NAME})

A shell environment variable overrides the value from .env. Because the bind mount uses ${COMPOSE_PROJECT_NAME} as well, an override changes both the Compose project name and the mounted directory — the sibling folder must exist.

Examples:

# override for a single command
COMPOSE_PROJECT_NAME=other-project docker compose run --rm packer packer validate debian13.pkr.hcl

# same, via flag
docker compose -p other-project run --rm packer packer validate debian13.pkr.hcl

To switch projects permanently, change COMPOSE_PROJECT_NAME in .env to match the sibling folder name under the repo root.

Project .env

Each mounted Packer project has its own .env for build secrets and cloud settings. Copy .env.example to .env in the project directory (e.g. insecure-user-with-docker/.env). Packer reads these variables via env() in .pkr.hcl — export them in your shell or pass them when running compose, for example:

set -a && source ../insecure-user-with-docker/.env && set +a
docker compose run --rm packer packer build main.pkr.hcl
Variable Purpose
HCLOUD_TOKEN Hetzner Cloud API token
SSH_KEY_NAME Name of the SSH public key registered in Hetzner Cloud (see below)

SSH keys

Cloud builders (e.g. Hetzner Cloud) create a temporary VM for each build. Packer SSHes into that VM to run provisioners, then snapshots the result. That requires a key pair:

Piece Location Role
Private key packer-in-docker/ssh//root/.ssh in the container Packer uses this to authenticate from the toolchain container to the build VM
Public key Registered in your cloud account (e.g. Hetzner Cloud) The cloud provider installs this on the build VM when it is created
Key name SSH_KEY_NAME in the mounted project's .env Name of the registered public key in Hetzner Cloud, passed to the builder (e.g. ssh_keys in .pkr.hcl)

This key is for build-time access only. It is not baked into the final machine image unless your provisioners explicitly do that.

Use a dedicated build key here — not your personal SSH key.

One-time setup

  1. Generate a key pair. Either in the container (recommended — OpenSSH is already installed) or on the host; both write to the same bind-mounted directory:

    cd packer-in-docker
    mkdir -p ssh
    
    # in the container
    docker compose run --rm packer ssh-keygen -t ed25519 -f /root/.ssh/id_ed25519 -N "" -C "packer-build"
    
    # or on the host (equivalent)
    ssh-keygen -t ed25519 -f ssh/id_ed25519 -N "" -C "packer-build"
    
  2. Upload ssh/id_ed25519.pub to Hetzner Cloud (console or API). Use the same name as the key comment — e.g. packer-build.

  3. Set SSH_KEY_NAME in the mounted project's .env to that name. For example, in insecure-user-with-docker/.env:

    SSH_KEY_NAME=packer-build
    

The ssh/ directory is gitignored. Do not commit private keys.

Do not generate keys inside the Docker image (Dockerfile/docker build) — they would be baked into the image. Keys must live in the bind-mounted ssh/ directory on the host.

Usage

Build the container image

docker compose build

Run packer

docker compose run --rm packer packer version

Build a machine image

docker compose run --rm packer packer init main.pkr.hcl
docker compose run --rm packer packer validate main.pkr.hcl
docker compose run --rm packer packer build main.pkr.hcl

Interactive shell in the mounted packer dir

docker compose run --rm packer fish # or ash