Creating an Operator Bundle
Prerequisites
Operator Bundle
An Operator Bundle is a container image that stores Kubernetes manifests and metadata associated with an operator. A bundle is meant to represent a specific version of an operator on cluster. Once you have the ClusterServiceVersion(CSV) for your operator, you can create an operator bundle using the CSV and the CRDs for your operator.
We refer to a directory of files with one ClusterServiceVersion as a bundle
that includes a CSV and the CRDs in its manifest directory, though additional kubernetes objects may be included. The directory also includes an annotations file in its metadata folder which defines some higher level aggregate data that helps to describe the format and package information about how the bundle should be added into an index of bundles. Finally, a Dockerfile can be built from the information in the directory to build the operator bundle image.
# example bundle
etcd
├── manifests
│ ├── etcdcluster.crd.yaml
│ └── etcdoperator.clusterserviceversion.yaml
├── metadata
│ └── annotations.yaml
└── Dockerfile
Contents of annotations.yaml and the Dockerfile
The annotations.yaml
and the Dockerfile
can be generated using the opm
tool’s alpha bundle generate
command.
Usage:
opm alpha bundle generate [flags]
Flags:
-c, --channels string The list of channels that bundle image belongs to
-e, --default string The default channel for the bundle image
-d, --directory string The directory where bundle manifests for a specific version are located.
-h, --help help for generate
-u, --output-dir string Optional output directory for operator manifests
-p, --package string The name of the package that bundle image belongs to
Note:
* All manifests yaml must be in the same directory.
For example, to generate the annotations.yaml
and Dockerfile
for the example bundle mentioned above, the command for the generate
task is:
$ opm alpha bundle generate --directory /etcd --package etcd --channels stable --default stable
After the generate command is executed, the Dockerfile
is generated in the directory where command is run. By default, the annotations.yaml
file is located in a folder named metadata
in the same root directory as the input directory containing manifests.
If the --output-dir
parameter is specified, that directory becomes the parent for a new pair of folders manifests/
and metadata/
, where manifests/
is a copy of the passed in directory of manifests and metadata/
is the folder containing annotations.yaml:
$ tree etcd
etcd
├── manifests
│ ├── etcdcluster.crd.yaml
│ └── etcdoperator.clusterserviceversion.yaml
├── my-output-manifest-dir
│ ├── manifests
│ │ ├── etcdcluster.crd.yaml
│ │ └── etcdoperator.clusterserviceversion.yaml
│ └── metadata
│ └── annotations.yaml
└── Dockerfile
The annotations.yaml
contains the following information as labels that are used to annotate the operator bundle container image:
- The label
operators.operatorframework.io.bundle.mediatype.v1
reflects the media type or format of the operator bundle. It could be helm charts, plain Kubernetes manifests etc. - The label
operators.operatorframework.io.bundle.manifests.v1
reflects the path in the image to the directory that contains the operator manifests. This label is reserved for the future use and is set tomanifests/
for the time being. - The label
operators.operatorframework.io.bundle.metadata.v1
reflects the path in the image to the directory that contains metadata files about the bundle. This label is reserved for the future use and is set tometadata/
for the time being. - The
manifests.v1
andmetadata.v1
labels imply the bundle type:- The value
manifests.v1
implies that this bundle contains operator manifests. - The value
metadata.v1
implies that this bundle has operator metadata.
- The value
- The label
operators.operatorframework.io.bundle.package.v1
reflects the package name of the bundle. - The label
operators.operatorframework.io.bundle.channels.v1
reflects the list of channels the bundle is subscribing to when added into an operator registry - The label
operators.operatorframework.io.bundle.channel.default.v1
reflects the default channel an operator should be subscribed to when installed from a registry. This label is optional if the default channel has been set by previous bundles and the default channel is unchanged for this bundle.
The annotations.yaml
file generated in the example above would look like:
annotations:
operators.operatorframework.io.bundle.mediatype.v1: "registry+v1"
operators.operatorframework.io.bundle.manifests.v1: "manifests/"
operators.operatorframework.io.bundle.metadata.v1: "metadata/"
operators.operatorframework.io.bundle.package.v1: "etcd"
operators.operatorframework.io.bundle.channels.v1: "stable"
operators.operatorframework.io.bundle.channel.default.v1: "stable"
The Dockerfile
generated in the example above would look like:
FROM scratch
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=test-operator
LABEL operators.operatorframework.io.bundle.channels.v1=beta,stable
LABEL operators.operatorframework.io.bundle.channel.default.v1=stable
ADD test/*.yaml /manifests
ADD test/metadata/annotations.yaml /metadata/annotations.yaml
Bundle images
An Operator Bundle is built as a scratch (i.e non-runnable) container image that contains information about the operator manifests and metadata inside the image(stored in a database inside the image). The image can then be pushed and pulled from an OCI-compliant container registry.
The opm
tool can be used to interact directly with these images. Once you have your manifests defined and have created a directory in the format defined above, building the image is as simple as defining a Dockerfile and building that image:
$ podman build -t quay.io/my-container-registry-namespace/my-manifest-bundle:latest -f bundle.Dockerfile .
Once you have built the container, you can publish it like any other container image:
$ podman push quay.io/my-container-registry-namespace/my-manifest-bundle:latest
Of course, this build step can be done with any other OCI spec container tools like docker
, buildah
, libpod
, etc
Validating your bundle
Once you’ve created your bundle, you will want to ensure that your bundle is valid and in the correct format. The api library contains a validation library that is used by operator-framework tools like operator-sdk
and opm
to validate operator bundles. For more information on validating via the operator-sdk
see the operator-sdk bundle validate
documentation.
The opm alpha bundle validate
command will validate a bundle image from a remote registry to determine if its format and content information are accurate.
The following validators will run by default on every invocation of the command.
- CSV validator - validates the CSV name and replaces fields.
- CRD validator - validates the CRDs OpenAPI V3 schema.
- Bundle validator - validates the bundle format and annotations.yaml file as well as the optional dependencies.yaml file.
For example:
$ opm alpha bundle validate --tag quay.io/test/test-operator:latest --image-builder docker
Optional Validation
Some validators are disabled by default and can be optionally enabled via the --optional-validators
or -o
flag.
- Operatorhub validator - performs operatorhub.io validation which will check your bundle against the common criteria to distributed with OLM. To validate a bundle using custom categories use the
OPERATOR_BUNDLE_CATEGORIES
environmental variable to point to a json-encoded categories file. Enable this option via--optional-validators=operatorhub
. This validator allows you to validate that your manifests can work with a Kubernetes cluster of a particular version using thek8s-version
optional key value. (e.g.--optional-values=k8s-version=1.22
) - Bundle objects validator - performs validation on resources like
PodDisruptionBudgets
andPriorityClasses
. Enable this option via--optional-validators=bundle-objects
. Multiple optional validators can be enabled at once, for example--optional-validators=operatorhub,bundle-objects
. - Community validator - performs community operator bundle validation which will check your bundle against the criteria to distribute your project on the Community Catalogs. For further information see its docs. This validator allows you to validate the required labels in the index image by using the
index-path
optional key value. (e.g.--optional-values=index-path=bundle.Dockerfile
).
Custom bundle categories
The operatorhub validator can verify against custom bundle categories by setting the OPERATOR_BUNDLE_CATEGORIES
environment variable.
Setting the OPERATOR_BUNDLE_CATEGORIES
environment variable to the path to a json file containing a list of categories will enable those categories to be used when comparing CSV categories for operatorhub validation. The json file should be in the following format:
{
"categories":[
"Cloud Pak",
"Registry",
"MyCoolThing",
]
}
For example:
$ OPERATOR_BUNDLE_CATEGORIES=./validate/categories.json ./bin/opm alpha bundle validate --tag <bundle-tag> --image-builder docker -o operatorhub
will validate the bundle using the provided categories file.
If OPERATOR_BUNDLE_CATEGORIES
is not set, and operatorhub validation is enabled, the default categories will be used when performing operatorhub validation. The default categories are the following:
- AI/Machine Learning
- Application Runtime
- Big Data
- Cloud Provider
- Developer Tools
- Database
- Integration & Delivery
- Logging & Tracing
- Monitoring
- Networking
- OpenShift Optional
- Security
- Storage
- Streaming & Messaging