--- title: Publish Kubernetes Operator to OperatorHub url: https://devopstales.github.io/kubernetes/oml/ date: 2021-12-21 keywords: ansible, openshift 3.11, openshift 4, openshift container platform, rad hat openshift, rad hat, configuration management --- In this post I will show you how you can publish your operator to OperatorHub. <!--more--> I assume you have a pre built and publised docker image with the operator in it. ### Install requirement * [operator-registry-tools](https://github.com/operator-framework/operator-registry/releases) * [operator-sdk](https://github.com/operator-framework/operator-sdk/releases) ```bash brew install opm brew install operator-sdk ``` ### Stucture Your Operator submission can be formatted following the `bundle` or `packagemanifest` format. he `packagemanifest` format is a legacy format which is kept for backwards compatibility only so I will use `bundle` format. ```bash tree OLM OLM └── 0.0.1    ├── manifests    │   ├── trivy-operator.v0.0.1.clusterserviceversion.yaml    │   └── crds.yaml    └── metadata    └── annotations.yaml ``` ### Create clusterserviceversion To add your operator to any of the supported platforms, you will need to submit metadata for your Operator to be used by the `Operator Lifecycle Manager` (OLM). This is YAML file called `ClusterServiceVersion` which contains references to all of the CRDs, RBAC rules, Deployment and container image needed to install and securely run your Operator. ```yaml nano OLM/0.0.1/manifests/trivy-operator.v0.0.1.clusterserviceversion.yaml ``` First start with a CSV that only contains some descriptive metadata: ```yaml apiVersion: operators.coreos.com/v1alpha1 kind: ClusterServiceVersion metadata: annotations: capabilities: Basic Install categories: "Security" description: Trivy Operator for scheduled imagescans and an Admission Control. certified: "false" containerImage: devopstales/trivy-operator:0.0.1 name: trivy-operator.v0.0.1 spec: description: Trivy Operator for scheduled imagescans and an Admission Control. displayName: Trivy Operator keywords: - trivy - security maintainers: - email: devopstales@mydomain.intra name: devopstales maturity: alpha provider: name: Blog url: devopstales.hithub.io version: 0.10.0 ``` The next section to add to the CSV is the Install Strategy - this tells OLM about the runtime components of your operator and their requirements. ```yaml apiVersion: operators.coreos.com/v1alpha1 kind: ClusterServiceVersion metadata: annotations: # ... name: trivy-operator.v0.0.1 spec: install: # ... # strategy indicates what type of deployment artifacts are used strategy: deployment # spec for the deployment strategy is a list of deployment specs and required permissions - similar to a pod template used in a deployment spec: permissions: - serviceAccountName: trivy-operator rules: - apiGroups: - "" resources: - pods verbs: - '*' # the rest of the rules # permissions required at the cluster scope clusterPermissions: - serviceAccountName: trivy-operator rules: - apiGroups: - "" resources: - serviceaccounts verbs: - '*' # the rest of the rules deployments: - name: trivy-operator spec: replicas: 1 # the rest of a deployment spec ``` > For Openshift you can append SCC to the serviceaccount in the rules section It’s also important to tell OLM the ways in which your operator can be deployed: ```yaml apiVersion: operators.coreos.com/v1alpha1 kind: ClusterServiceVersion metadata: annotations: # ... name: trivy-operator.v0.0.1 spec: # ... installModes: - supported: true type: OwnNamespace - supported: true type: SingleNamespace - supported: false type: MultiNamespace - supported: true type: AllNamespaces ``` By definition, operators are programs that can talk to the Kubernetes API and they are also extend the Kubernetes API, by `CustomResourceDefinitions`. Which APIs are watched or owned is important metadata for OLM so we need to define thease too. ```yaml apiVersion: operators.coreos.com/v1alpha1 kind: ClusterServiceVersion metadata: annotations: # ... alm-examples: |- [ { "apiVersion": "trivy-operator.devopstales.io/v1", "kind": "NamespaceScanner", "metadata": { "name": "trivy-operator-main-config" }, "spec": { "crontab": "*/5 * * * *", "namespace_selector": "trivy-scan", "registry": [ { "name": "docker.io", "user": "", "password": "" } ] } } ] name: trivy-operator.v0.0.1 spec: spec: # ... customresourcedefinitions: owned: # a list of CRDs that this operator owns # name is the metadata.name of the CRD - name: namespace-scanners.trivy-operator.devopstales.io # version is the version of the CRD (one per entry) version: v1 # spec.names.kind from the CRD kind: NamespaceScanner ``` You must place the `CustomResourceDefinitions` to the `manifests` folder andy any other object like `service` what you want to deploy by the `Operator Framework`. If you created your `` you can test with OperatorHub's [Operator Preview](https://operatorhub.io/preview) page. # Test operator You can test your files with `operator-sdk` locally: ```bash operator-sdk bundle validate ./OLM/0.0.1 --select-optional suite=operatorframework INFO[0000] All validation tests have completed successfully ``` ### Generate bundle To test the functions all working correctly you need first to install the operator with Operato framework. To do so you need a build the `bundle` image the the catalog index: ```bash cd OML opm alpha bundle build -c stable -d 0.0.1/manifests -t devopstales/trivy-operator-bundle:0.0.1 -p trivy-operator docker push docker.io/devopstales/trivy-operator-bundle:0.0.1 opm index add -b docker.io/devopstales/trivy-operator-bundle:0.0.1 -t docker.io/devopstales/trivy-operator-index:0.0.1 -c docker docker push docker.io/devopstales/trivy-operator-index:0.0.1 ``` ### Install OML To install the operator from your catalog index first you need to install the `operator-lifecycle-manager`. ```bash curl -sL https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.19.1/install.sh | bash -s v0.19.1 ``` ### Add your index as CatalogSource ```yaml nano cs-trivy-operator.yaml apiVersion: operators.coreos.com/v1alpha1 kind: CatalogSource metadata: name: devopstales-catalog namespace: olm spec: displayName: devopstales publisher: devopstales sourceType: grpc image: docker.io/devopstales/trivy-operator-index:0.0.1 updateStrategy: registryPoll: interval: 1m ``` ```bash kubectl apply -f cs-trivy-operator.yaml kubectl get catalogsource --all-namespaces NAMESPACE NAME DISPLAY TYPE PUBLISHER AGE olm devopstales-catalog devopstales grpc devopstales 13m olm operatorhubio-catalog Community Operators grpc OperatorHub.io 7h20m kubectl get packagemanifest | grep trivy trivy-operator devopstales 6h54m ``` Subscribe to this operator: ```yaml $ cat og.yaml apiVersion: operators.coreos.com/v1 kind: OperatorGroup metadata: name: test-og namespace: default spec: targetNamespaces: - default $ cat sub_devopstales-catalog.yaml apiVersion: operators.coreos.com/v1alpha1 kind: Subscription metadata: name: trivy-operator namespace: default spec: channel: alpha installPlanApproval: Automatic name: trivy-operator source: devopstales-catalog sourceNamespace: olm startingCSV: trivy-operator.v0.0.1 ``` After create them, you will get the below objects: ```yaml $ oc get sub -n default NAME PACKAGE SOURCE CHANNEL trivy-operator trivy-operator devopstales-catalog alpha $ oc get ip -n default NAME CSV APPROVAL APPROVED install-tvpq4 trivy-operator.v0.0.1 Automatic true $ oc get csv -n default NAME DISPLAY VERSION REPLACES PHASE trivy-operator.v0.0.1 Trivy Operator 0.0.1 Succeeded ``` The you can create the Custo Resource to test the functionality. ### Publicate operato on OperatoHub To publish your bundled operator you need to create a pull requuest to the [operatorhub community-operators](https://github.com/k8s-operatorhub/community-operators) repo or [RedHat Opeshift community-operators](https://github.com/redhat-openshift-ecosystem/community-operators-prod) repo.