How to create a bundle for an operator?

In the last blog posts, we run our example frontend operator as:

In that blog post we will focus on: Creating a bundle for the example operator. That bundle will be used to install the example frontend operator using an Operator Lifecycle Manager (OLM).

Let’s get started to build a bundle for the example operator and surely the Go lang tutorial and bundle tutorial of the Operator SDK can be useful in that context.

Here is a simplified architectural overview of the bundle. Simplified we can say the bundle will contain all information for the operator to run on a cluster and can be managed by an Operator Lifecycle Manager (OLM). The bundle does reference the controller-manager container image we created in the last blog post.

We will …

  • … create a bundle
  • … verify the created bundle content
  • … build the bundle locally
  • … push the bundle to the container registry

Step 1: Create a bundle

  • Define the location of the existing controller-manager image for the operator
export REGISTRY=''
export ORG='tsuedbroecker'
export IMAGE='frontendcontroller:v3'

  • Execute the command
make bundle IMG="$REGISTRY/$ORG/$IMAGE"

  • Makefile implementation

In the implementation of the make file we see that there is a parameter for the controller-manager image. We created in the last blog post the controller-manager image for the deployment and pushed that image to the container registry. We pointed our new bundle creation to that existing container image location in the make command above.

.PHONY: bundle
bundle: manifests kustomize ## Generate bundle manifests and metadata, then validate generated files.
    operator-sdk generate kustomize manifests -q
    cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG)
    $(KUSTOMIZE) build config/manifests | operator-sdk generate bundle -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS)
    operator-sdk bundle validate ./bundle

  • Interaction during the bundle creation
/frontendOperator/bin/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
operator-sdk generate kustomize manifests -q

Display name for the operator (required): 
> FrontendOperator

Description for the operator (required): 
> This is an example operator to deploy a simple web application

Provider's name for the operator (required): 
> Thomas Suedbroecker

Any relevant URL for the provider name (optional): 

Comma-separated list of keywords for your operator (required): 
> example,go,webapplication,ngnix

Comma-separated list of maintainers and their emails (e.g. 'name1:email1, name2:email2') (required): 

  • Finally creating the bundle
cd config/manager && /Users/thomassuedbroecker/Downloads/dev/multi-tenancy-frontend-operator/frontendOperator/bin/kustomize edit set image
/Users/thomassuedbroecker/Downloads/dev/multi-tenancy-frontend-operator/frontendOperator/bin/kustomize build config/manifests | operator-sdk generate bundle -q --overwrite --version 0.0.1  
INFO[0000] Creating bundle.Dockerfile                   
INFO[0000] Creating bundle/metadata/annotations.yaml    
INFO[0000] Bundle metadata generated suceessfully       
operator-sdk bundle validate ./bundle
INFO[0000] All validation tests have completed successfully

Step 2: Verify the created bundle content

  • The bundle folder

As we see the bundle folder contains subfolders with information which still were on the local machine when we executed our example operator as a deployment on the Kubernetes cluster using the  make deploy command.

The bundle does contain all needed information to install, run and handle versioning for the operator so that Operator Lifecycle Manager (OLM) can manage the example frontend operator later in a Kubernetes cluster.

These are the newly created folders:

  • manifests
  • metadata
  • test/scorecard
  • The reference to the controller-manager image

In the bundle.mainfests folder we find the frontendoperator.clusterserviceversion.yaml file, that file contains the location information of the controller-manager container image . We provided that information as a parameter in the make bundle command.

  • Also in the config.manifests folder a new subfolder called bases was created

Here we see important Cluster Service Version (CSV)

This the content of the ClusterServiceVersion yaml.

kind: ClusterServiceVersion
    alm-examples: '[]'
    capabilities: Basic Install
  name: frontendoperator.v0.0.0
  namespace: placeholder
  apiservicedefinitions: {}
    - description: TenancyFrontend is the Schema for the tenancyfrontends API
      displayName: Tenancy Frontend
      kind: TenancyFrontend
      version: v1alpha1
  description: This is an example operator to deploy a simple web application
  displayName: FrontendOperator
  - base64data: ""
    mediatype: ""
      deployments: null
    strategy: ""
  - supported: false
    type: OwnNamespace
  - supported: false
    type: SingleNamespace
  - supported: false
    type: MultiNamespace
  - supported: true
    type: AllNamespaces
  - example
  - go
  - webapplication
  - ngnix
  - name: Frontendoperator
    url: https://frontendoperator.domain
  maturity: alpha
    name: Thomas Suedbroecker
  version: 0.0.0
  • The bundle.Dockerfile
FROM scratch

# Core bundle labels.

# Labels for testing.

# Copy files to locations specified by labels.
COPY bundle/manifests /manifests/
COPY bundle/metadata /metadata/
COPY bundle/tests/scorecard /tests/scorecard/

Step 3: Build the bundle locally

Now we will build the image using the makefile. We use as the container registry for the container image.

docker login

export REGISTRY=''
export ORG='tsuedbroecker'
export BUNDLEIMAGE='bundlefrontendoperator:v3'

In the makefile we see how the command to build-bundle is realized and which parameter we need to specify.

.PHONY: bundle-build
bundle-build: ## Build the bundle image.
    docker build -f bundle.Dockerfile -t $(BUNDLE_IMG) .

  • Build the container using the make file

Step 4: Push the bundle to the container registry



We created a bundle for our operator, but we can’t run the bundle without an Operator Lifecycle Manager (OLM). The next blog post will cover that topic. (Run an operator using a bundle with an Operator Lifecycle Manager (OLM))

I hope this was useful to you and let’s see what’s next?



#operator, #operatorsdk, #kubernetes, #bundle, #olm, #operatorlearningjourney

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Blog at

Up ↑

%d bloggers like this: