Shipwright Build: container image builds expressed as Kubernetes objects
Shipwright - a framework for building container images on Kubernetes
At a glance
- What is it?
- Shipwright moves container image building into the cluster and expresses it as two small custom resources, a Build that says what to build and a BuildRun that says run it now. The builder is a strategy, so Kaniko, Cloud Native Buildpacks, BuildKit and Buildah can all sit behind the same YAML, and the installation is a couple of kubectl applies.
- Who is it for?
- Adopt Shipwright Build if you build container images from source in a Kubernetes cluster and want a build to be a first class API object that other automation can create, watch and retry, rather than a job definition in a CI system. Do not adopt it if your builds are not running in the cluster, since the whole design assumes the builder runs there, and read the OpenShift section if that is your platform.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The pitch is a small YAML instead of container knowledge
Shipwright is described as an extensible framework for building container images on Kubernetes, and the reason section states the case in plain terms.
Developers get a simplified approach for building container images by defining a minimal YAML that does not require any previous knowledge of containers or container tooling. All you need is your source code in git and access to a container registry.
That is a narrower claim than it first sounds, and a more useful one. The problem Shipwright addresses is not that building images is hard, it is that the machinery around it is: build definitions that live in a CI configuration file, builders that need their own deployment, credentials that have to be wired into that CI system, and results that are not visible to anything else running in the cluster.
By making the build a Kubernetes object, the build becomes something the cluster can watch. That is what makes the rest of the design possible, because a build that is an object can be triggered by something other than a CI job, can be retried by a controller, and can be inspected with the same tools as everything else in the cluster.
The project status badge in the readme says work in progress, which is worth keeping in mind, and the repository also carries an OpenSSF best practices badge, a scorecard badge and a Go report card badge, so the project is at least measuring itself against the usual hygiene standards.
One binary, several builders, selected by strategy
The list of supported builders is the clearest statement of what extensible means here. Shipwright supports any tool that can build container images in a Kubernetes cluster, and the README names Kaniko, Cloud Native Buildpacks, BuildKit and Buildah.
That list spans two rather different philosophies. Kaniko and Buildah build images by running steps in a container without a Docker daemon. BuildKit is a daemon-based builder with a rich cache and parallelism model. Cloud Native Buildpacks take a completely different approach, detecting the language of the source and choosing a buildpack for it, which is why the example build in the tutorial is called a buildpacks build and why the sample source repository is a Node.js project.
The abstraction is visible in the resource definitions. A build names a strategy and the kind of strategy, and the example uses the cluster-wide kind with a name that identifies the buildpacks version, so the strategy itself is a cluster resource that an administrator installs and a developer selects. That separation is what makes the framework extensible in a meaningful sense: adding a builder means adding a strategy, and a user switching between builders means changing one field in a build definition.
The API is versioned and the repository carries samples for two generations, a v1alpha1 and a v1beta1 directory, with the tutorial using the beta version. Two API versions still in the samples directory is a small sign of how recently the interface changed.
The two resources divide the work cleanly. The Build object describes the source, the strategy and the output, and it is the thing you keep. The BuildRun refers to a build by name and is the thing that actually starts work, with a generated name so that the same build can be run again and again.
Installing means a Kubernetes cluster, Tekton, and a few applies
The tutorial is unusually concrete about prerequisites, which is welcome in a project that asks you to install a controller.
You need a Kubernetes cluster, version 1.34 or later, and if you do not have one you can use KinD, installed by running the script in the hack directory. You also need a Tekton installation, version 1.6 or later, applied from a release manifest, with a note that OpenShift users need extra configuration.
Then the Shipwright deployment itself, which is a version lookup, an apply and two scripts:
VERSION=$(curl -s https://api.github.com/repos/shipwright-io/build/releases/latest | jq -r .tag_name)
kubectl apply --filename https://github.com/shipwright-io/build/releases/download/${VERSION}/release.yaml --server-side
curl --silent --location https://raw.githubusercontent.com/shipwright-io/build/${VERSION}/hack/setup-webhook-cert.sh | bash
curl --silent --location https://raw.githubusercontent.com/shipwright-io/build/${VERSION}/hack/storage-version-migration.sh | bashTwo details in that block are worth noting. The server-side apply flag is used because the resources are large enough that the client-side annotation based apply struggles, and the two scripts do the two things a manifest cannot: they set up the webhook certificate and they run the storage version migration, which is what a project with a changed stored schema has to offer.
There is a parallel set of instructions for the nightly channel, and a separate step to install the strategies themselves, because the strategies are shipped as a separate sample manifest. In other words, the controller and the builders are two different installations, and you need both.
The versions are 0.21.x, with releases on 2026-10-01, 2026-10-10 and 2026-10-14, and the last push on 2026-10-20, so this is a project shipping frequently.
The tutorial ends with a registry secret, a Build and a BuildRun
The remainder of the tutorial is the part an adopter will copy, and it is worth reading in full because it shows the shape of the API.
First, credentials. The registry access is a standard Docker registry secret in the cluster:
REGISTRY_SERVER=https://index.docker.io/v1/ REGISTRY_USER=<your_registry_user> REGISTRY_PASSWORD=<your_registry_password>
kubectl create secret docker-registry push-secret \
--docker-server=$REGISTRY_SERVER \
--docker-username=$REGISTRY_USER \
--docker-password=$REGISTRY_PASSWORD \
--docker-email=<your_email>Then the Build object, which is the whole configuration surface:
apiVersion: shipwright.io/v1beta1
kind: Build
spec:
source:
type: Git
git:
url: https://github.com/shipwright-io/sample-nodejs
contextDir: source-build
strategy:
name: buildpacks-v3
kind: ClusterBuildStrategy
output:
image: docker.io/${REGISTRY_ORG}/sample-nodejs:latest
pushSecret: push-secretThe source is a git URL with a context directory, the strategy names a cluster strategy, and the output names the image and the secret used to push it.
The BuildRun then refers to the build by name, with a generated name so every run is distinct. And the way to wait for it is worth copying, because it is the kind of command that belongs in a script:
kubectl get buildrun --output name | xargs kubectl wait --for=condition=Succeeded --timeout=180sThat is a build pipeline in one line, and the same expression works in a CI job, in a GitOps tool or on a laptop.
A Go controller with vendored dependencies and an image builder of its own
The repository layout shows what kind of project this is.
The Go code lives in a command directory and a package directory, with the module named for the repository and a recent Go toolchain in its go.mod. There is a vendored dependency directory, which in a project of this size usually means reproducible builds are a requirement rather than a nicety, and there is a configuration file for the ko image builder, which is how the controller and the sample images get built and published.
The documentation set is broad for a controller. There is a document about adapters, which is presumably where the builder integrations are described, a development guide, a hacking guide and a roadmap, plus a directory of the project documentation itself and a directory of samples split by API version. There is also an owners file, which is how a distributed project assigns review responsibility.
The tooling is conventional and well signposted. There is a linter configuration, a Makefile, and a tools file that pins the tool dependencies, which is the usual way a Go project keeps its development tooling in the same build as the code.
The last thing the directory listing reveals is the scope of the project. This is not a small controller that wraps one builder. It is a framework with a public API, a plugin model for builders, a migration story for stored objects, a webhook that needs a certificate, and a strategy installation path that is separate from the controller installation. The two API versions still present in the samples directory are the clearest evidence of how much of that is still in motion.
What to check before you put this in a cluster
A few practical warnings, gathered from the tutorial and the repository state.
The version floor is not trivial. The documented requirement is Kubernetes 1.34 or later and Tekton 1.6 or later, and both of those are recent enough that an older cluster will need an upgrade before this fits into it at all. The tutorial assumes you can run privileged workloads, and the OpenShift section says so explicitly: you need a service account, the privileged security context constraint added to the user, and the edit role. A build tool that runs build steps inside the cluster is a build tool that wants privileges, and that is worth understanding before an administrator sees the request.
The second is the credentials. The registry password becomes a Kubernetes secret in the cluster, and the tutorial puts it in a shell variable first, which is the shape of a credential that ends up in a terminal history. Using a secret from a proper secret manager is the better path, and the tutorial does not mention one.
The third is the API surface. The project labels itself work in progress, the samples still include an earlier version of the API, and the release numbers are still in the zero series. The Build and BuildRun objects you write today are an interface that is still moving, so if you plan to put a controller or a GitOps tool in front of it, plan for that too.
The last is the build isolation question. Shipwright chooses a builder for you and runs it in the cluster, which means your build steps execute with cluster credentials in a namespace you choose. That is inherent to the approach rather than a flaw in it, and it is the thing to think about hardest before adopting it, because it is a different security posture from a CI system that builds elsewhere and pushes an image.
Editorial conclusion
Adopt Shipwright Build if you build container images from source in a Kubernetes cluster and want a build to be a first class API object that other automation can create, watch and retry, rather than a job definition in a CI system. Do not adopt it if your builds are not running in the cluster, since the whole design assumes the builder runs there, and read the OpenShift section if that is your platform. Before you install, check the cluster and Tekton versions you have, because the documented requirements are recent, and note that the project still labels itself work in progress, so the API version you depend on may move.
Frequently asked questions
What is Shipwright Build?
It is an extensible framework for building container images on Kubernetes, written in Go and Apache-2.0 licensed. A developer defines a minimal YAML with a source, a strategy and an output, so no previous knowledge of container tooling is required, and the project also ships a command line interface.
Which container build tools does Shipwright support?
Any tool that can build container images in a Kubernetes cluster, and the README names Kaniko, Cloud Native Buildpacks, BuildKit and Buildah. The builder is selected as a strategy, with the cluster-wide strategy kind in the example, so a new builder is added as a strategy resource rather than as a code change.
What do I need before installing Shipwright?
A Kubernetes cluster at version 1.34 or later, which you can create with KinD using the install script in the hack directory, and a Tekton installation at version 1.6 or later applied from a release manifest. The Shipwright deployment is then installed with a server-side apply, followed by scripts that set up the webhook certificate and run the storage version migration.
How do I push the image Shipwright builds to a registry?
You create a Docker registry secret in the cluster and reference it from the Build object's output as the push secret. The output also names the image reference, and the build strategy does the pushing once the run succeeds.
Is the Shipwright project stable?
The readme carries a work in progress status badge, and the samples directory still contains both an alpha and a beta version of the API, with the tutorial using the beta. Releases are frequent, at 0.21.7, 0.21.8 and 0.21.9 within October 2026, and the last push was on 2026-10-20.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/shipwright-io-build)Was this useful?