Repositories and Images¶
CAPTF lives in eleven repositories in the captf-io GitHub organization. This page lists what each one holds, what it publishes, which container images exist and how they are tagged, and how the pieces fit together.
How the pieces fit¶
A module image is built FROM a base image that supplies the runtime. The module image is what a Terraform* resource names in spec.source.image. The provider runs it as a Kubernetes Job: an init container started from the provider’s own image copies the /runner binary into a shared volume, and the main container runs your module image with that runner as its command.
flowchart LR
base["opentofu-base / terraform-base<br/>runtime at /captf/runtime"]
mod["module image<br/>module + provider mirror"]
prov["cluster-api-provider-terraform image<br/>manager + /runner"]
res["TerraformCluster, TerraformMachine,<br/>TerraformMachinePool<br/>spec.source.image"]
job["Job"]
init["init container: copies /runner<br/>from the provider image"]
main["main container: your module image<br/>runs /captf/bin/runner run"]
base -->|FROM| mod
mod -->|referenced by| res
res -->|reconciled by manager in| prov
prov -->|creates| job
job --> init
job --> main
prov -.->|image of| init
mod -.->|image of| main The init container, the /captf/bin/runner path and the rule that the image’s own ENTRYPOINT never runs are described in Job Environment. The runner image defaults to the manager’s own image and can be overridden with --runner-image; see Manager Flags and The manager image and the runner image. The module image half of the contract is in Image Contract.
Repositories¶
| Repository | Kind | What it holds | What it publishes |
|---|---|---|---|
cluster-api-provider-terraform | Provider | The manager (controllers and webhooks), the runner (the in-Job driver) and the tfcapi-lint linter, with the API types, CRDs, kustomize bases and clusterctl templates. | The manager and runner image, and the clusterctl components, templates and tfcapi-lint binaries as release assets. |
opentofu-base | Base image | The Dockerfile for the OpenTofu runtime layer of the image contract. | ghcr.io/captf-io/opentofu-base. |
terraform-base | Base image | The same layer for the Terraform runtime. | ghcr.io/captf-io/terraform-base. |
aws-modules | Modules | Reference cluster, machine and machinepool modules for AWS. | ghcr.io/captf-io/aws-<role>. |
azure-modules | Modules | Reference cluster, machine and machinepool modules for Azure. | ghcr.io/captf-io/azure-<role>. |
gcp-modules | Modules | Reference cluster, machine and machinepool modules for Google Cloud. | ghcr.io/captf-io/gcp-<role>. |
oci-modules | Modules | Reference cluster, machine and machinepool modules for Oracle Cloud. | ghcr.io/captf-io/oci-<role>. |
openstack-modules | Modules | Reference cluster and machine modules for OpenStack. There is no machinepool. | ghcr.io/captf-io/openstack-<role>. |
noop-modules | Modules | No-op cluster, machine and machinepool modules that create nothing, for trying CAPTF and for end-to-end tests. | ghcr.io/captf-io/noop-<role>. |
captf-io.github.io | Website | The captf.io site: landing page, this docs book and the blog. | The site, deployed to GitHub Pages from main by pages.yml. |
.github | Organization | The organization profile, the community health files and the shared README fragments synced into every repository’s README. | Nothing is built. Its workflow only checks license headers. |
The module repositories are described together in Cloud Modules; their layout is in Module Repository Layout.
Images¶
All images are in GitHub Container Registry under ghcr.io/captf-io/.
| Image | Published by | Tags | Platforms |
|---|---|---|---|
cluster-api-provider-terraform | The publish workflow: every push to main, and a vX.Y.Z tag push | edge and sha-<commit> on a push to main; vX.Y.Z (or vX.Y.Z-rc.N) on a tag. Never latest. | linux/amd64, linux/arm64 |
opentofu-base, terraform-base | The build workflow of each repository: every push to main, plus a weekly rebuild | <version>, <major.minor>, <version>-YYYYMMDD, latest, where <version> is the runtime version. | linux/amd64, linux/arm64 |
aws-<role>, azure-<role>, gcp-<role>, oci-<role> with <role> one of cluster, machine, machinepool | The build workflow of each repository | edge-<runtime> on a push to main; vX.Y.Z-<runtime> and <runtime> on a vX.Y.Z tag. <runtime> is opentofu or terraform. | linux/amd64, linux/arm64 |
openstack-<role> with <role> one of cluster, machine | The build workflow | The same scheme as the other clouds. | linux/amd64, linux/arm64 |
noop-<role> with <role> one of cluster, machine, machinepool | The build workflow | The same scheme as the cloud modules. | linux/amd64, linux/arm64 |
What exists today follows from those triggers:
- The provider image is published by the
publishworkflow on every push tomain(:edgeand:sha-<commit>) and on every release tag (:vX.Y.Z);workflow_dispatchrepublishes:edge. No release has been made yet, so no:vX.Y.Ztag exists. Until one does, use:edgeor pin a:sha-<commit>tag or a digest. To build your own, usemake docker-buildandmake docker-push IMG=.... A maintainer can fall back tomake releasewhen CI cannot run; see Releasing. - The base images are published on every push to
mainand weekly, so they exist now. See Base Images for how to pin them. - The module images publish
edge-<runtime>from every push tomain. ThevX.Y.Z-<runtime>and<runtime>tags appear only when avX.Y.Ztag is pushed, so before the first module release only theedge-tags are available. Pin a release tag or a digest in anything you keep.
Every pushed module and base image carries an SBOM and provenance attestations (mode=max), and the manifests carry the org.opencontainers.image.* title, description and licence annotations. The provider image has its own scheme: every pushed digest gets a keyless cosign signature, a SLSA provenance attestation and an SPDX SBOM attestation, and its manifests carry the org.opencontainers.image.* source, revision, version, licenses and description annotations and labels. See Releasing for the verification commands.
Release assets¶
A provider release, created by the publish workflow when a release tag is pushed, attaches these files to the GitHub release:
| Asset | Source |
|---|---|
infrastructure-components.yaml | config/default rendered by kustomize, with the manager image pinned by digest. |
metadata.yaml | The file at the repository root: the clusterctl release series. |
cluster-template.yaml, cluster-template-clusterclass.yaml, clusterclass-noop.yaml, identity.yaml | The templates/ directory. |
tfcapi-lint-<os>-<arch> and tfcapi-lint-checksums.txt | GoReleaser, configured in .goreleaser.yaml. It builds the linter only, not the image. |
provenance.intoto.jsonl | The provenance attestation bundle for the assets above. Every asset also has a provenance attestation in GitHub. |
The publish workflow runs make release-assets and make release-github on the tag push; make release is the manual fallback. The steps and the checklist are in Releasing. The module and base repositories attach no release assets: their output is the images above.
Versioning at a glance¶
| Repository | Version scheme | Owned by |
|---|---|---|
cluster-api-provider-terraform | Tags vX.Y.Z and vX.Y.Z-rc.N. metadata.yaml lists the clusterctl release series, append-only, currently 0.1 on contract v1beta2. | Releasing |
opentofu-base, terraform-base | Not tagged in git. The image tags follow the runtime version (1.12.6, 1.12), with a date-stamped build tag. | Tags and pinning |
<cloud>-modules, noop-modules | Tags vX.Y.Z. Image tags add the runtime: vX.Y.Z-opentofu, vX.Y.Z-terraform. | Releasing a Module |
Which provider, Cluster API and runtime versions are tested together is in Compatibility.
Shared across repositories¶
Every repository carries the same CONTRIBUTING.md, CODE_OF_CONDUCT.md, SECURITY.md and LICENSE.md, and every source file is Apache-2.0 licensed with a license header that CI checks. The provider also has a SECURITY_CONTACTS file. The .github repository holds the organization’s community health files, and its make readme target keeps the banner, status note and footer of each repository’s README identical. See Working Across Repositories for changes that span repositories, and Contributing for how to contribute.