Rakefile and libraries for managing container image builds with Podman.
Forked from docker-rakefile. If you need Docker support, use the original project.
- Ruby with
rake - Podman (builds use
podman build, which runs buildah internally)
brew install podman
podman machine init
podman machine startInstall Podman via your package manager. See podman.io/docs/installation.
Clone container-template as the starting point for a new container image repository:
git clone https://github.com/itsbcit/container-template ~/Devel/my-new-imageUpdate the Rakefile and support library in the existing code with rake update.
Update .gitignore to exclude the Rakefile library and .build_id marker file.
.gitignore contents:
.build_id
lib
Rakefile can be updated to the latest release version with rake update.
The majority of the Rakefile support code is contained in the lib directory, which should be excluded from individual Git repositories using this system. This way, the latest release code is always used.
See rake install
This will pull the latest release of the lib support files from GitHub.
metadata.yaml defines the layout and handling of the container image(s) in this repository.
A simple example for an image without versions or variants:
---
image_name: template_test
registries:
- url: registry.example.com
project: myorg
vars:
foo_version: '1.2.3'Inside ERB templated files, these parameters are available as eg. image.vars['foo_version']. Eg in a Containerfile.erb:
RUN yum install \
foo-<%= image.vars['foo_version'] %>Labels, vars, and tags can all be ERB-templated with inline values, but note that the context is the image, so no image. prefix. This example will add a label foo_version = 1.2.3 using the value of foo_version from the image vars:
labels:
foo_version: '<%= vars['foo_version'] %>'Important: parameters are rendered in the order: vars -> labels -> tags.
- vars can only include replacements from the image top-level, and other non-templatable image properties
- labels can include vars
- tags can include vars and labels
By default, all builds target linux/amd64. Override per-image in metadata.yaml:
build_platform: 'linux/arm64'Or via environment variable: BUILD_PLATFORM=linux/arm64 rake build
By default, images are tagged with a build ID suffix (e.g. image:1.0-b1567100182). To disable:
tag_build_id: falseThis can be set at the top level, per-version, or per-variant.
Set VERSION and/or VARIANT environment variables to restrict any rake task to a subset of the matrix. This works for all tasks: build, tag, push, template, scan, etc.
VERSION=17 rake build # build all variants of version 17
VARIANT=pgvector rake build # build pgvector across all versions
VERSION=17 VARIANT=pgvector rake build # build exactly one imageAny file in lib can be overridden by the same file name in local/. For example, if you need a custom test task, copy lib/tasks/test.rake to local/tasks/test.rake and modify it. Test helpers from lib/test_helpers.rb are available for composing multi-container test setups.
- Make
Containerfilechanges inContainerfile.erb rake updateto pull down Rakefile and library updatesrake(runs template, build, test, and tag)rake pushto push to registries defined inmetadata.yaml
Install the Rakefile support files from the latest release.
rake install
To install from a specific branch or tag instead of the latest release:
CRUCIBLE_REF=main rake install
When CRUCIBLE_REF is set, both lib/ and the Rakefile are fetched from that ref's archive. This is useful for testing unreleased crucible changes in a consumer repo before cutting a release.
Rakefile self-update. Download and overwrite the Rakefile and lib/ directory with the latest release.
rake update
CRUCIBLE_REF=main rake update — update from a specific branch or tag (delegates to rake install, which already fetches both lib/ and the Rakefile from the archive).
Side-effect: also calls install
Create or overwrite Containerfile(s) from ERB templates and render any templated files listed for the versions and variants into their build directories. Dockerfile.erb is also accepted as a fallback for backwards compatibility.
rake template
Build the container image(s) using podman build (buildah internally).
rake build
Add standard and metadata.yaml configured tags to the image(s).
rake tag
Standard tags:
- image_name:b(
build id) eg.mybusybox:b1567100182(unlesstag_build_id: false) - image_name:latest
Run automated tests against the image(s). Uses composable helpers from lib/test_helpers.rb.
Apply security updates to an existing image without a full rebuild.
rake patch — patches all images using apk upgrade --no-cache
PATCH_CMD='yum update -y' rake patch — custom patch command
PATCH_BASE='myimage:b1567100182' rake patch — patch a specific build
Produces images tagged with a -pN suffix (e.g. image:b1567100182-p1).
Scan built container images for vulnerabilities using Trivy.
rake scan — fails if any HIGH or CRITICAL vulnerabilities are found
SEVERITY=CRITICAL rake scan — only fail on CRITICAL vulnerabilities
Requires trivy to be installed. See aquasecurity/trivy for installation.
Push all images and tags to the registries configured in metadata.yaml. Authentication must be set up before calling this task, either via podman login or by setting REGISTRY_AUTH_FILE to a valid auth config.
rake push
Render .woodpecker/build.yaml from the image matrix in metadata.yaml. Each version×variant combination becomes a parallel Woodpecker CI step with VERSION and VARIANT set. A render step runs first to stamp a shared build ID and re-render all Containerfiles.
rake woodpecker
The generated file should be committed to the repository. Re-run rake woodpecker whenever metadata.yaml changes and commit the result.
See Woodpecker CI integration for the full parallel build workflow.
Removes all tags, images, "FROM images" and runs podman system prune.
Shows rendered tags, vars, labels, platform, and predicted commands. Use to preview what your metadata will produce.
Sample metadata.yaml with most options used:
---
image_name: php-fpm
maintainer: 'jesse@weisner.ca, chriswood.ca@gmail.com'
build_platform: 'linux/amd64'
tag_build_id: true
labels:
php_version: '<%= vars["php_version"] %>'
vars:
pecl_oci8_version: '2.2.0'
pecl_xdebug_version: '3.1.0'
pecl_igbinary_version: '3.2.6'
oracle_version: '18.3.0.0.0'
oracle_major: '18.3'
variants:
'builder':
registries:
- url: registry.example.com
project: myorg
'':
registries:
- url: registry.example.com
project: myorg
'oci':
depends_on: '' # must be built after the base ('') variant
registries:
- url: registry.example.com:5000
labels:
oracle_version: '<%= vars["oracle_major"] %>'
versions:
'7.3':
vars:
php_version: '7.3.30'
'7.4':
vars:
php_version: '7.4.24'The registry project/namespace can be specified as project, org, or org_name — all three are equivalent. project is preferred. If more than one is set, org_name takes priority, then project, then org.
Reusable Containerfile fragments in lib/snippets/. Include them in Containerfile.erb with:
<%= snippet('name', binding) -%>Any snippet can be overridden by placing a file with the same name in local/snippets/.
Downloads and installs the entrypoint script framework from itsbcit/container-entrypoint.
Variable: ce_version (default: 1.0)
Backward-compatible stub that delegates to container-entrypoint.
Downloads and installs catatonit, a minimal container init process. Drop-in replacement for tini, and the same init used internally by Podman.
Variable: catatonit_version (default: 0.2.1)
<%= snippet('catatonit', binding) -%>ENTRYPOINT ["/catatonit", "--", "/container-entrypoint.sh"]Downloads and installs tini, a lightweight init process.
Variable: tini_version (default: 0.19.0)
Downloads and installs dockerize for template rendering and service readiness checks.
Variable: dockerize_version (default: 0.13.0)
Renders LABEL instructions from the image's labels hash.
The de_version variable (used by the old docker-entrypoint snippet to download from itsbcit/docker-entrypoint) is obsolete. Use ce_version instead, which downloads from itsbcit/container-entrypoint.
Setting de_version in base_vars or vars at any level will raise an error during config parsing.
Crucible supports parallel builds in Woodpecker CI via rake woodpecker. Each version×variant combination builds in its own parallel step. Steps that depend on another variant (e.g. a pgvector image that FROMs the base image) are sequenced automatically via Woodpecker's depends_on.
Two pipelines are used:
Render pipeline (triggered by upstream automation or manually when metadata.yaml changes):
rake install && rake template && rake woodpecker
git add .woodpecker/build.yaml Containerfile* && git commit -m "..." && git pushThis stamps a new build ID, re-renders all Containerfiles, and regenerates .woodpecker/build.yaml. The commit triggers the build pipeline.
Build pipeline (.woodpecker/build.yaml, generated by rake woodpecker):
renderstep: runsrake install && rake template && rake woodpeckerto stamp a fresh build ID- One parallel step per version×variant: runs
rake install && rake template && rake build && rake test && rake scan && rake tag && rake pushwithVERSION,VARIANT, andKEEP_BUILD=1set
If a variant's Containerfile FROMs another variant's published image, declare the dependency in metadata.yaml:
variants:
'': {}
'pgvector':
depends_on: '' # wait for base variant to be built and pushed firstrake woodpecker uses this to add depends_on to the generated Woodpecker step, so build-17-pgvector waits for build-17-base to complete before starting. Variants without depends_on run fully in parallel.
Each step requires a harbor_config Woodpecker secret containing a Docker-format config.json:
{"auths":{"registry.example.com":{"auth":"<base64-encoded-user:password>"}}}Add it via: woodpecker-cli repo secret add <ORG/REPO> --name harbor_config --value "$(cat ~/.docker/config.json)"
Every GitHub release must include two assets that rake install and rake update download:
crucible-lib.zip— a zip of thelib/directory contents (flat.rb/.yamlfiles at root,tasks/andsnippets/subdirectories preserved)Rakefile— the currentRakefilefrom the repo root
To create a release:
# build the lib zip (must contain lib/ as top-level directory)
zip -r /tmp/crucible-lib.zip lib/
# create the release with assets
gh release create vX.Y.Z --title "vX.Y.Z" --notes "..." /tmp/crucible-lib.zip Rakefile