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='quay.io'
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 Quay.io 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):
> thomas@tmn-drummer.de
- Finally creating the bundle
cd config/manager && /Users/thomassuedbroecker/Downloads/dev/multi-tenancy-frontend-operator/frontendOperator/bin/kustomize edit set image controller=quay.io/tsuedbroecker/frontendcontroller:v3
/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 thefrontendoperator.clusterserviceversion.yaml
file, that file contains the location information of thecontroller-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.
apiVersion: operators.coreos.com/v1alpha1
kind: ClusterServiceVersion
metadata:
annotations:
alm-examples: '[]'
capabilities: Basic Install
name: frontendoperator.v0.0.0
namespace: placeholder
spec:
apiservicedefinitions: {}
customresourcedefinitions:
owned:
- description: TenancyFrontend is the Schema for the tenancyfrontends API
displayName: Tenancy Frontend
kind: TenancyFrontend
name: tenancyfrontends.multitenancy.example.net
version: v1alpha1
description: This is an example operator to deploy a simple web application
displayName: FrontendOperator
icon:
- base64data: ""
mediatype: ""
install:
spec:
deployments: null
strategy: ""
installModes:
- supported: false
type: OwnNamespace
- supported: false
type: SingleNamespace
- supported: false
type: MultiNamespace
- supported: true
type: AllNamespaces
keywords:
- example
- go
- webapplication
- ngnix
links:
- name: Frontendoperator
url: https://frontendoperator.domain
maturity: alpha
provider:
name: Thomas Suedbroecker
version: 0.0.0
- The
bundle.Dockerfile
FROM scratch
# Core bundle labels.
LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1
LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/
LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/
LABEL operators.operatorframework.io.bundle.package.v1=frontendoperator
LABEL operators.operatorframework.io.bundle.channels.v1=alpha
LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.17.0
LABEL operators.operatorframework.io.metrics.mediatype.v1=metrics+v1
LABEL operators.operatorframework.io.metrics.project_layout=go.kubebuilder.io/v3
# Labels for testing.
LABEL operators.operatorframework.io.test.mediatype.v1=scorecard+v1
LABEL operators.operatorframework.io.test.config.v1=tests/scorecard/
# 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 Quay.io as the container registry for the container image.
- Login to Quay.io
docker login quay.io
- Set the custom container name (the default of the
Multi Tenancy Frontend Operator
don’t fit for an default usage of the make file )
export REGISTRY='quay.io'
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
make bundle-build BUNDLE_IMG="$REGISTRY/$ORG/$BUNDLEIMAGE"
Step 4: Push the bundle to the container registry
docker push "$REGISTRY/$ORG/$BUNDLEIMAGE"
Summary
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?
Greetings,
Thomas
#operator, #operatorsdk, #kubernetes, #bundle, #olm, #operatorlearningjourney