That is the next blog post related to operators. Now it’s about deploy an operator without the Operator SDK. In the last blog post we used the operator-sdk run bundle
command which created for us all needed specifications and images to run the bundle. Therefor we need to take a closer look into the Operator Lifecycle Manager (OLM). We are still using the example GitHub project Multi Tenancy Frontend Operator
.
Let’s have a brief look on a very simplified overview of the basic dependencies for the given assets. In the image below you see the container images already created:
- Bundle image
- Controller manager image
Now we will create a catalog image, that references the bundle image. We will also define a Catalog Source
and a Subscription
. The Subscription
references the Catalog Source
.

I tried to follow the steps in the Operator Lifecycle Manager (OLM) documentation to create a catalog image, but that didn’t work for me. (documentation issue) But, Adam de Leeuw reminded me that is also possible to create the catalog image with the Operator SDK. The Red Hat OpenShift documentation also points to the Operator SDK to create a catalog image. I took the path with the Operator SDK and it worked.
The blog post is structured in following main sections:
- Prerequisites
- Clone the git project
- Create a catalog image and upload to container registry
- Create a
Catalog source
and aSubscription
specification - Deploy both specifications to the Kubernetes cluster
- Verify if the operator works by creating an instance of a frontend application
Prerequisites:¶
- Operator SDK installed
- Docker installed
- A Kubernetes cluster available
- Operator Lifecycle Manager (OLM) is installed on that Kubernetes
Clone the project¶
git clone https://github.com/thomassuedbroecker/multi-tenancy-frontend-operator.git
- Navigate to the
frontendOperator
folder
cd frontendOperator
Create a catalog image and upload to container registry¶
Step 1: Prepare the needed parameter for the make command¶
export REGISTRY=quay.io
export ORG=tsuedbroecker
export BUNDLE_IMAGE="bundlefrontendoperator:v3"
export CATALOG_IMAGE=frontend-catalog
export CATALOG_TAG=v0.0.1
Step 2: Verify the make catalog-build
command we going to use
As we see in the source code of the makefile below, we need to specify --bundles
which will be a part of a catalog. The make command will create a catalog container image for use. In our case we will use the parameter CATALOG_IMG
and BUNDLE_IMGS
.
# Build a catalog image by adding bundle images to an empty catalog using the operator package manager tool, 'opm'.
# This recipe invokes 'opm' in 'semver' bundle add mode. For more information on add modes, see:
# https://github.com/operator-framework/community-operators/blob/7f1438c/docs/packaging-operator.md#updating-your-existing-operator
.PHONY: catalog-build
catalog-build: opm ## Build a catalog image.
$(OPM) index add --container-tool docker --mode semver --tag $(CATALOG_IMG) --bundles $(BUNDLE_IMGS) $(FROM_INDEX_OPT)
Note: The makefile also installs operator package manager (opm) from the OLM for you as you see in the following source code.
Source: Operator Registry
“opm, which generates and updates registry databases as well as the index images that encapsulate them.” The following source code shows the relevant part of the makefile used by the Operator SDK.
.PHONY: opm
OPM = ./bin/opm
opm: ## Download opm locally if necessary.
ifeq (,$(wildcard $(OPM)))
ifeq (,$(shell which opm 2>/dev/null))
@{ \
set -e ;\
mkdir -p $(dir $(OPM)) ;\
OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \
curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/v1.19.1/$${OS}-$${ARCH}-opm ;\
chmod +x $(OPM) ;\
}
else
OPM = $(shell which opm)
endif
endif
Step 3: Create the catalog image¶
make catalog-build CATALOG_IMG="$REGISTRY/$ORG/$CATALOG_IMAGE:$CATALOG_TAG" BUNDLE_IMGS="$REGISTRY/$ORG/$BUNDLE_IMAGE"
Step 4: Upload the image to the container registry
docker login quay.io
docker push "$REGISTRY/$ORG/$CATALOG_IMAGE:$CATALOG_TAG"
Create a Catalog source
and a Subscription
specification
Step 1: Define the catalog source specification
Create a file called catalogsource.yaml
and past the content of yaml below into that file. As we see the CatalogSource
references the quay.io/tsuedbroecker/frontend-catalog:v0.0.1
image we created before.
apiVersion: operators.coreos.com/v1alpha1
kind: CatalogSource
metadata:
name: frontend-operator
namespace: operators
spec:
displayName: Frontend Operator
publisher: Thomas Suedbroecker
sourceType: grpc
image: quay.io/tsuedbroecker/frontend-catalog:v0.0.1
updateStrategy:
registryPoll:
interval: 10m
- Apply that
CatalogSource
to the cluster.
kubectl apply -f catalogsource.yaml -n operators
- Verify the
CatalogSource
.
kubectl get catalogsource -n operators
- Example output:
NAME DISPLAY TYPE PUBLISHER AGE
frontend-operator-catalog Frontend Operator grpc Thomas Suedbroecker 141m
Step 2: Define the subscription source¶
Create a file called subscprition.yaml
and past the content of yaml below into that file.
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
name: frontendoperator-v0-0-1-sub
namespace: operators
spec:
channel: alpha
name: frontendoperator
source: frontend-operator-catalog
sourceNamespace: operators
- Apply the
Subscription
to the cluster.
kubectl apply -f subscription.yaml -n operators
- Verify the
Subscription
.
kubectl get subscription -n operators
- Example output:
NAME PACKAGE SOURCE CHANNEL
frontendoperator-v0-0-1-sub frontendoperator frontend-operator-catalog alpha
Verify if the operator works by creating an instance of a frontend application¶
kubectl apply -f config/samples/multitenancy_v1alpha1_tenancyfrontend.yaml -n default
- Verify the create Kubernetes objects:
kubectl get customresourcedefinition -n default | grep "frontend"
kubectl get tenancyfrontend -n default | grep "frontend"
kubectl get deployment -n default | grep "frontend"
kubectl get service -n default | grep "frontend"
kubectl get pod -n default | grep "frontend"
- Example output:
tenancyfrontends.multitenancy.example.net 2022-03-22T
tenancyfrontendsample 123m
tenancyfrontendsample 1/1 1 1 123m
tenancyfrontendsample NodePort 172.21.76.237 <none> 8080:31614/TCP 123m
tenancyfrontendsampleclusterip ClusterIP 172.21.160.33 <none> 80/TCP 123m
tenancyfrontendsample-557fd697dc-qz84l 1/1 Running 0 123m
The gif below shows the finial status of the operator deployment.

Summary¶
There are more remaining topics to explore in the operator area like how to update an existing operator with a new operator api or how to use webhooks.
I hope this was useful to you and let’s see what’s next?
Greetings,
Thomas
#olm, #operatorsdk, #kubernetes, #bundle, #operator, #operatorlearningjourney