Skip to main content
The make run command is convenient for local development, but to deploy the operator to another Kubernetes cluster you must publish a container image that cluster nodes can pull and run. Kubebuilder has already scaffolded the important pieces for building that image: a Dockerfile, Makefile targets, and Kubernetes manifests under config/. This document inspects the Dockerfile and Makefile pieces that go into the operator image. Building and pushing the image will be covered later in an end-to-end flow. References

Dockerfile overview

The repository Dockerfile uses a multi-stage build pattern:
  • Stage 1 (builder): compiles the Go-based operator manager binary using an official Go image.
  • Stage 2 (runtime): packages only the compiled binary into a minimal runtime image (distroless).
This produces a small, secure runtime image suitable for production clusters.

First stage — builder (compiles the manager binary)

Key notes about this stage:
  • Copying go.mod and go.sum before the rest of the source enables Docker to cache dependencies. Changing application source code afterwards won’t force a re-download of modules.
  • CGO_ENABLED=0 produces a statically-linked binary, required when using distroless base images that lack C libraries.
  • TARGETOS and TARGETARCH are build arguments that let Buildx inject platform values for multi-architecture images.

Second stage — runtime (minimal image containing only the binary)

Why this works well for operators:
  • The final image contains only the compiled manager binary — no package managers, shells, or interpreters — reducing image size and attack surface.
  • Running as a non-root user increases runtime security.
  • Distroless images are ideal for production but limit in-container debugging because typical tooling is absent.
Using a distroless image with a static binary improves security and minimizes image size, but it also means debugging inside the container is limited since shells and typical tooling are absent.

Makefile targets for building and publishing

The Makefile in the project exposes basic single-architecture build/push targets and a Buildx-based cross-platform workflow for producing multi-architecture images.

Simple single-architecture build and push

Use these targets when you only need a single-architecture image (for example, linux/amd64). Do not run these if you intend to publish multi-architecture images — use the Buildx workflow instead.

Cross-platform build and push (buildx)

Why this Buildx workflow matters:
  • PLATFORMS enumerates the CPU architectures to include in the image manifest list served by the registry.
  • The sed command writes a temporary Dockerfile.cross that forces BuildKit to respect the BUILDPLATFORM on each FROM instruction. This is critical so that the correct base image for each target architecture is used during the multi-arch build.
  • buildx build --push --platform=... builds images for multiple architectures and pushes a single tag that points to a manifest list (multi-arch image). The registry then serves the appropriate architecture image for each node automatically.
Table: Makefile targets summary
If a tag only points to an amd64 image, an arm64 node cannot run that image. Use a multi-arch manifest list (via Buildx) to support heterogeneous clusters.

Separating image and install manifests

It’s important to keep the container image build pipeline distinct from Kubernetes installation manifests:
  • Image: contains only the controller binary and runtime configuration (Dockerfile, build process).
  • Install manifests: CRDs, RBAC, Deployment, Service, and sample manifests are under config/ and are generated or applied by other Make targets.
This separation simplifies CI/CD: image builds and registry publishing are one concern; packaging and installing the operator into a cluster are another.

What’s next

This article toured the Dockerfile and Makefile pieces used to produce a minimal, secure operator image and explained how to produce a multi-architecture manifest list using Buildx. Later you can perform the end-to-end build and push flow:
  • Choose an image tag and registry (for example, docker.io/<your-org>/webapp-operator:v0.1.0).
  • Run the docker-buildx target to publish a multi-arch image.
  • Update your operator Deployment manifests under config/ to reference the published image tag.
Further reading and references

Watch Video