Building a Catalog

Build a Catalog of Operators using Operator-Registry

Manifest format

We refer to a directory of files with one ClusterServiceVersion as a “bundle”. A bundle typically includes a ClusterServiceVersion and the CRDs that define the owned APIs of the CSV in its manifest directory, though additional objects may be included. It 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.

 # example bundle
 etcd
 ├── manifests
 │   ├── etcdcluster.crd.yaml
 │   └── etcdoperator.clusterserviceversion.yaml
 └── metadata
     └── annotations.yaml

When loading manifests into the database, the following invariants are validated:

 * The bundle must have at least one channel defined in the annotations.
 * Every bundle has exactly one ClusterServiceVersion.
 * If a ClusterServiceVersion `owns` a CRD, that CRD must exist in the bundle.

Bundle directories are identified solely by the fact that they contain a ClusterServiceVersion, which provides an amount of freedom for layout of manifests.

Check out the operator bundle design proposal for more detail on the bundle format.

Bundle images

Using OCI spec container images as a method of storing the manifest and metadata contents of individual bundles, opm interacts directly with these images to generate and incrementally update the database. 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:

FROM scratch

# We are pushing an operator-registry bundle
# that has both metadata and manifests.
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
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.

Building an index of Operators using opm

Index images are additive, so you can add a new version of your operator bundle when you publish a new version:

opm index add --bundles quay.io/my-container-registry-namespace/my-manifest-bundle:0.0.2 --from-index quay.io/my-container-registry-namespace/my-index:1.0.0 --tag quay.io/my-container-registry-namespace/my-index:1.0.1

For more detail on using opm to generate index images, take a look at the documentation.

Where should I go next?


Last modified April 27, 2020: Clean up operator-registry (be92ab6)