Getting Started
Bakery is a CLI tool that binds together various tools to manage a matrixed build of container images.
Prerequisites
3rd Party Tools
| Tool | Used By | Purpose |
|---|---|---|
| docker buildx bake | bakery build --strategy bake |
Build containers in parallel |
| docker, podman, or nerdctl | bakery build --strategy build |
Build containers in series |
| dgoss | bakery dgoss run |
Test container images for expected content & behavior |
| hadolint | bakery hadolint run |
Lint Containerfiles for best practices |
| oras | bakery imagetools merge |
Merge multi-platform images into an OCI index |
| wizcli | bakery wizcli scan |
Scan container images for vulnerabilities |
Additional tool integrations (trivy, openscap) are planned. See the architecture diagrams for the full roadmap.
Installation
Install bakery from PyPI using uv tool:
uv tool install posit-bakeryTo install an unreleased development version directly from GitHub:
uv tool install 'git+https://github.com/posit-dev/images-shared.git@main#subdirectory=posit-bakery&egg=posit-bakery'Examples
See the Bakery Examples repository for step-by-step tutorials on creating and managing container image projects with Bakery.
Usage
See the architecture diagrams for detailed tool behavior.
Show the commands available in bakery.
bakery --help
# or
bakery helpStep 1. Create a project
Create a new project
bakery create projectThis command will create a new project configuration file in the bakery context.
Make changes to the
bakery.yamlfileUpdate the contents of the project configuration file. A new project configuration file includes a default set of values.
- Document the source code Repository
- Configure image Registry entries to tag and push images to specific registries
Step 2. Create an image
Create a new image
bakery create image fancy-imageThis command:
- Creates a directory for the image (
fancy-imagein this example) - Creates a
template/subdirectory - Writes a default set of template files
- Adds the image to the
imagessection of thebakery.yamlfile
- Creates a directory for the image (
Make changes to the
bakery.yamlfileUpdate the Image definition.
- Define Image Variants
- Set Dependency Constraints
Make changes to the default Jinja2 templates
The default set of templates provide only a basic skeleton of what is required to define and build an image; you will need to modify these generic templates.
See the available Jinja variables in the templating documentation.
Add additional templates that will be rendered for each image version
You can add additional template files that will be created for each new image version.
Template files must end with the
.jinja2file extension.
Step 3. Create an image version
Create a new version of the image
bakery create version fancy-image 2025.01.0This command
Creates a subdirectory for the image version (
fancy-image/2025.01.0in this example)The
--subpathflag can be used to create the version directory in a different locationUpdates the
bakery.yamlfile with the new image versionSets the new image to
latestThe
--no-mark-latestflag skips marking the image as the latestRenders the templates created in Step 2, replacing the values
Make changes to the
bakery.yamlfileUpdate the ImageVersion definition.
Step 4. Build the image(s)
Preview the bake plan [OPTIONAL]
bakery build --planThe
build --strategy bakecommand creates a temporary JSON file that is passed todocker buildx bake.Build the container images
bakery build
Step 5. Run the tests
Run the
dgosstests against all the imagesbakery dgoss runAdditional run options can be specified using Goss options in
bakery.yamlon a per image or per variant basis
Bakery Concepts
Project Structure
Bakery establishes a directory structure, referred to as a project. The project configuration is stored in the bakery.yaml.
By default, bakery uses the invocation directory as the project context. You can use the --context flag to override the default behavior.
bakery --context /path/to/directory
A bakery project can include one or more images. Each image can optionally have one or more variants. By default, there are two variants: Standard and Minimal. Each image should have one or more versions. Each version can have one or more OSes.
.
├── bakery.yaml
├── fancy-image/
│ ├── 2024.11.0/
│ ├── 2025.01.0/
│ └── template/
└── more-fancy-image/
├── 2024.12.0/
├── 2024.12.1/
├── 2025.02.0/
└── template/
Build Strategies
bakery build supports two strategies, selected with --strategy. Both emit the same --metadata-file contract, so either can feed bakery dgoss run and bakery imagetools merge.
| Aspect | --strategy bake (default) |
--strategy build |
|---|---|---|
| Builder | docker buildx bake (requires Docker Buildkit) |
Docker, Podman, or nerdctl |
| Parallelism | Builds all targets in parallel | Concurrent, bounded by --jobs |
--plan |
Supported (prints the bake plan) | Not supported; errors out |
--fail-fast |
Buildx stops the whole bake on first failure | Stops scheduling new targets after the first failure |
--metadata-file write |
Buildx owns the file | Written only after all targets succeed |
Metadata file semantics
The --metadata-file JSON is keyed by image-target UID, one entry per target. Because --strategy build writes the file only after every target succeeds, a failed target leaves the file absent entirely; under --strategy bake a failed bake means buildx leaves a missing file. Either way, downstream dgoss run / ci publish see no file rather than a partial one.
One platform per invocation
A target built for more than one platform in a single invocation produces one metadata entry describing an index/manifest-list descriptor with no platform field. This has two concrete consequences for consumers:
bakery dgoss run --metadata-filecan no longer match the exact built digest and falls back to a tag-based reference, so it stops testing the digest that was actually built.bakery imagetools mergeloses its per-platform merge inputs, collapsing them to a single unkeyed source.
For this reason bakery build requires --image-platform to select a single platform whenever --metadata-file is set and any target supports more than one platform. Build one platform per invocation when the metadata file is consumed downstream — this is what bakery-build-native.yml already does (one image/version/platform per runner).