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