Learn Puppet - Bolt & Orchestration
Series/Learn Puppet/Episode 11
Episode 11 of 23

Learn Puppet - Bolt & Orchestration

In this episode we take direct control with Bolt: running tasks and plans over SSH and WinRM, writing inventory.yaml, and combining Bolt's push model with the Puppet agent's pull model.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Introduction

In episode 10 you saw Tasks and Plans running in Puppet Enterprise. Now we step away from the Console and take direct control: in episode 11 we learn Bolt, Puppet's open source orchestration tool that stands on its own without PE. Bolt runs tasks, plans, commands, and scripts against many targets at once over SSH, WinRM, or other connections — complementing the Puppet agent's pull model with push power.

The workflow is simple: define targets in an inventory, choose an action, then run it. Bolt handles parallel connections, per-target results, and output collection.

Installing Bolt

Bolt is available as an official package for the main Linux distros and macOS:

Install Bolt on Debian/Ubuntu
wget https://apt.puppet.com/puppet8-release-focal.deb
sudo dpkg -i puppet8-release-focal.deb
sudo apt-get update
sudo apt-get install puppet-bolt
Verify the installation
bolt --version
bolt task show

bolt --version confirms the binary is installed, while bolt task show lists the built-in tasks. Bolt ships with a standard task set like service, package, and reboot that you can use right away.

Note

Bolt doesn't need an agent or a Puppet server. It works directly from a workstation — ideal for an admin workstation, CI pipeline, or emergency paths where agents can't be relied on.

inventory.yaml

Targets are grouped in an inventory.yaml file. It's the source of truth for which nodes are reachable and how:

inventory.yaml
version: 2
groups:
  - name: web
    targets:
      - web01.example.com
      - web02.example.com
    config:
      transport: ssh
      ssh:
        user: deploy
        private-key: ~/.ssh/id_ed25519
        run-as: root
  - name: windows
    targets:
      - win01.corp.local
    config:
      transport: winrm
      winrm:
        user: svc-bolt
        password: '$${winrm_password}'
  - name: all
    targets:
      - 10.0.0.0

Groups can be nested: the all group unites the web and windows groups, so one target line runs against everything. The default transport is SSH for Linux and WinRM for Windows, and both can be set per group.

Warning

Don't put plaintext passwords in an inventory.yaml that goes into git. Use secret variables from the environment (for example with the env: mechanism in the inventory) or integration with a secret store — Bolt supports pulling values from environment variables.

Running Tasks

Tasks are run with bolt task run. The simplest form uses the built-in service task:

Restart nginx on all web targets
bolt task run service action=restart name=nginx --targets web

The result is shown per target with success or failure status. For tasks from a module, call it by its full name:

Run a custom task
bolt task run profile::collect_logs --targets web --params '{"days": 7}'

The bolt command run command executes a shell command directly, and bolt script run runs a script from your local machine without having to package it as a task first:

Run a command and a script
bolt command run 'df -h /' --targets web
bolt script run ./scripts/collect-logs.sh --targets web

Tip

Pick the right tool: bolt command run for one-line commands, bolt script run for throwaway scripts, and bolt task run for operations defined with metadata and structured parameters.

Tasks and Plans

A custom task is just a script plus a metadata.json. The script receives parameters via stdin in JSON format:

tasks/restart_nginx.sh
#!/bin/bash
systemctl restart nginx
tasks/restart_nginx/metadata.json
{
  "description": "Restart layanan nginx",
  "input_method": "stdin",
  "parameters": {
    "service": {
      "type": "String[1]",
      "description": "Nama layanan"
    }
  }
}

A plan combines several steps and can make decisions along the way:

plans/upgrade_web.pp
plan upgrade::web(
  TargetSpec $targets,
  String[1] $version,
) {
  $targets.apply_prep
  run_task('deploy::stop', $targets)
  run_task('deploy::update', $targets, version => $version)
  run_task('deploy::start', $targets)
}

Run the plan with bolt plan run:

Run a plan
bolt plan run upgrade::web version=1.2.0 --targets web

Notice the magic of $targets.apply_prep — that line automatically installs Puppet modules on the targets so tasks can run. If the tasks are already available on the targets, this step can be skipped.

Combining Bolt and the Puppet Agent

The Puppet agent works on the pull model: it waits for its schedule to fetch and apply the catalog. Bolt works on the push model: we command an action directly. They aren't competitors but complements.

The most common combination is triggering an agent run from Bolt when you want changes applied immediately, for example after a deploy:

Trigger an agent run via Bolt
bolt command run 'puppet agent -t' --targets web
bolt command run 'puppet agent -t --noop' --targets web

puppet agent -t runs one agent run immediately, while --noop shows what would change without applying it — safe for inspection. This way, configuration stays managed through manifests (pull), while the execution timing is controlled from outside (push).

ModelTriggerExample use
PullAgent on a scheduleNormal config changes, maintaining desired state
PushBolt / OrchestratorAd-hoc actions, sudden deploys, emergency fixes

Important

Don't use Bolt to change configuration that should be managed by manifests. If you do, that change will be overridden on the next agent run — and nobody else can track it. Push for actions, pull for state.

Case Study: Rolling Restart

Combining plans and target batching makes operations safe on large fleets. Here's a plan that restarts the service two nodes at a time so downtime never happens all at once:

plans/rolling_restart.pp
plan web::rolling_restart(
  TargetSpec $targets,
) {
  $batches = $targets.slice(2)
  $batches.each |$batch| {
    run_task('service', $batch, action => 'restart', name => 'nginx')
    run_command('sleep 5', $batch)
  }
  run_command('curl -f http://localhost/healthz', $targets)
}

Each batch is restarted, given a pause, then all targets are health-checked with curl. If a batch fails, the plan output shows it clearly and execution continues with the next batch.

Conclusion

Bolt gives you a direct hand on your infrastructure without giving up manifest control.

  • Bolt is a push orchestration tool that runs without a Puppet server.
  • inventory.yaml groups targets and sets up SSH or WinRM transport per group.
  • bolt task run, bolt command run, and bolt script run execute actions in parallel with per-target results.
  • Plans orchestrate many steps complete with logic and checks.
  • Pull for state, push for actions — combine the Puppet agent and Bolt according to each one's strengths.

With this you can move an entire fleet in seconds. But who deploys the manifest code itself? In episode 12, you'll learn Code Manager and r10k: branch-based environments from git, production vs staging deployment, module versions via the Puppetfile, and a version control workflow for environments. See you there!

Learn Puppet - Bolt & Orchestration | Learn Puppet