HOW-TO make your Operator available in OpenShift

HOW-TO make your Operator available in OpenShift

Have you ever wondered how Operators show up inside OpenShift OperatorHub?

Let's say you have just written your brand new Operator using the operator-sdk and you would like to make it available for installing inside some OpenShift cluster: this post shows the steps to follow.

The step are:

  • Create the Operator image (using the operator-sdk)
  • Create the Operator Bundle: a bunch of files with information about the operator image you just created
  • Create the Operator Bundle Image: just an image created “FROM scratch” containing the Operator Bundle files
  • Create the Operator Catalog Image: an image that contains bundles (in our case just one)
  • Create the CatalogSource resource in OpenShift: an OLM specific Custom Resource pointing to an Operator Catalog Image

Create the Operator image

This is the regular workflow for creating an Operator in GO;

Create a dumb Operator that monitors when a Custom Resource named "PippoBaudo" is created but then takes no action:

mkdir operator-test
cd operator-test
operator-sdk init --domain sample.com --repo github.com/<YOUR_GITHUB_ACCOUNT>/operator-test
operator-sdk create api --group sample --version v1alpha1 --kind PippoBaudo --resource --controller
make docker-build docker-push IMG="quay.io/<YOUR_QUAY_ACCOUNT>/operator-test:v0.0.1"

Create the Operator Bundle

The bundle basically describes your operator to OLM. The “make bundle” command creates folder bundle containing a bunch of files with information about the operator image you just created:

make bundle IMG="quay.io/<YOUR_QUAY_ACCOUNT>/operator-test:v0.0.1"

if you inspect the the bundle folder (inside the operator-test folder) you can see the bundle files:

tree bundle
bundle
├── manifests
│   ├── operator-test.clusterserviceversion.yaml
│   ├── operator-test-controller-manager-metrics-service_v1_service.yaml
│   ├── operator-test-manager-config_v1_configmap.yaml
│   ├── operator-test-metrics-reader_rbac.authorization.k8s.io_v1_clusterrole.yaml
│   └── sample.sample.com_pippobaudoes.yaml
├── metadata
│   └── annotations.yaml
└── tests
    └── scorecard
        └── config.yaml

Create the Operator Bundle Image

After creating the bundle, wrap it into an image:

make bundle-build bundle-push BUNDLE_IMG="quay.io/<YOUR_QUAY_ACCOUNT>/operator-test-bundle:v0.0.1"

Create the Operator Catalog Image

This is the so called “index image” which is used by OLM and Operator Registry; It contains bundles forming a sort of catalog; In our specific case it's going to contain just one bundle:

make catalog-build catalog-push \
CATALOG_IMG="quay.io/<YOUR_QUAY_ACCOUNT>/operator-test-catalog:v0.0.1" \
BUNDLE_IMG="quay.io/<YOUR_QUAY_ACCOUNT>/operator-test-bundle:v0.0.1" \
IMG="quay.io/<YOUR_QUAY_ACCOUNT>/operator-test:v0.0.1"

Create the CatalogSource

Finally, tell OpenShift to load this new catalog by creating a specific resource called CatalogSource;

Create file CatalogSource.yaml with the following content:

apiVersion: operators.coreos.com/v1alpha1
kind: CatalogSource
metadata:
  name: operator-test-catalog
  namespace: openshift-marketplace
spec:
  sourceType: grpc
  image: quay.io/<YOUR_QUAY_ACCOUNT>/operator-test-catalog:v0.0.1
  displayName: Test Operator 
  publisher: sample.com

and load it in your OpenShift cluster:

oc apply -f CatalogSource.yaml

Please note namespace openshift-marketplace was used because all catalog PODs run inside this namespace:

oc get CatalogSource --all-namespaces 
NAMESPACE               NAME                    DISPLAY                  TYPE   PUBLISHER    AGE
openshift-marketplace   certified-operators     Certified Operators      grpc   Red Hat      8d
openshift-marketplace   community-operators     Community Operators      grpc   Red Hat      8d
openshift-marketplace   operator-test-catalog   Test Operator    grpc   sample.com   20s
...

Create a Subscription

Now install our Operator from the catalog using the usual proedure:

create file Subscription.yaml:

kind: Subscription
metadata:
  name: operator-test
  namespace: my-namespace
spec:
  channel: alpha
  name: operator-test
  source: operator-test-catalog
  sourceNamespace: openshift-marketplace
  startingCSV: operator-test.v0.0.1

and apply it to your namespace:

oc apply -f Subscription.yaml

Create Custom Resource

In the very last step, create a PippoBaudo resource:

create file PippoBaudo.yaml:

apiVersion: sample.sample.com/v1alpha1
kind: PippoBaudo
metadata:
  name: pippobaudo-sample
  namespace: my-namespace

and apply it to your namespace:

oc apply -f PippoBaudo.yaml

Now, if you look at the Operators POD logs you see the Operator noticed PippoBaudo resource creation :

oc logs operator-test-controller-manager-99f659974-8vc2z manager -n openshift-operators
...
2021-12-03T13:37:15.423Z    INFO    controller.pippobaudo    Starting EventSource    {"reconciler group": "sample.sample.com", "reconciler kind": "PippoBaudo", "source": "kind source: /, Kind="}
2021-12-03T13:37:15.423Z    INFO    controller.pippobaudo    Starting Controller    {"reconciler group": "sample.sample.com", "reconciler kind": "PippoBaudo"}
2021-12-03T13:37:15.533Z    INFO    controller.pippobaudo    Starting workers    {"reconciler group": "sample.sample.com", "reconciler kind": "PippoBaudo", "worker count": 1}

Obviously nothing else happend at this point since our Operator is a dummy operator.