Generating Manifests and Metadata

  • Generate your first release - encapsulate the metadata needed to install your Operator with the and configure the permissions it needs from the generated SDK files.
  • Update your Operator - apply any updates to Operator manifests made during development.
  • Upgrade your Operator - carry over any customizations you have made and ensure a rolling update to the next version of your Operator.

Several subcommands manage operator-framework manifests and metadata, in particular ClusterServiceVersion’s (CSVs), for an Operator: , generate packagemanifests, and . See this CLI overview for details on each command. These manifests come in two different formats, and package manifests, which are described in detail below. Ideally the bundle format should be used as this is the default packaging format in operator-framework. However the package manifests format is still supported by operator-framework tooling.

operator-sdk generate kustomize manifests generates a CSV kustomize base config/manifests/bases/<project-name>.clusterserviceversion.yaml and a config/manifests/bases/kustomization.yaml by default. These files are required as kustomize build input in downstream commands.

By default, the command starts an interactive prompt if a CSV base in config/manifests/bases is not present to collect . You can disable the interactive prompt by passing --kustomize=false.

Once this base is written, you may modify any of the fields labeled user in the fields section below.

For Go Operators only: the command parses from Go API type definitions, located in ./api for single group projects and ./apis for multigroup projects, to populate certain CSV fields. You can set an alternative path to the API types root directory with --apis-dir. These markers are not available to Ansible or Helm project types.

CSV’s are manifests that define all aspects of an Operator, from what CustomResourceDefinitions (CRDs) it uses to metadata describing the Operator’s maintainers. They are typically versioned by semver, much like Operator projects themselves; this version is present in both their metadata.name and spec.version fields. The CSV generator called by generate <bundle|packagemanifests> requires certain input manifests to construct a CSV manifest; all inputs are read when either command is invoked, along with a CSV’s base, to idempotently regenerate a CSV.

The following resource kinds are typically included in a CSV, which are addressed by config/manifests/bases/kustomization.yaml:

  • Role: define Operator permissions within a namespace.
  • ClusterRole: define cluster-wide Operator permissions.
  • Deployment: define how the Operator’s operand is run in pods.
  • CustomResourceDefinition: definitions of custom objects your Operator reconciles.
  • Custom resource examples: examples of objects adhering to the spec of a particular CRD.

You can optionally specify an input ClusterServiceVersion manifest to the set of manifests passed to these generate subcommands instead of having them read from the . This is advantageous for those who would like to take full advantage of kustomize for their base. All fields unlabeled or labeled with marker below will be overwritten by these command, so make sure you do not kustomize build those fields!

You’ve recently run operator-sdk init and created your APIs with operator-sdk create api. Now you’d like to package your Operator for deployment by OLM. Your Operator is at version v0.0.1; the Makefile variable VERSION should be set to 0.0.1. You’ve also built your operator image, quay.io/<user>/memcached-operator:v0.0.1.

A consists of manifests (CSV, CRDs, and other supported kinds) and metadata that define an Operator at a particular version, and an optional scorecard configuration file. You may have also heard of a bundle image. From the bundle docs:

At this stage in your Operator’s development, we only need to worry about generating bundle files; bundle images become important once you’re ready to your Operator.

SDK projects are scaffolded with a Makefile containing the bundle recipe by default, which wraps generate kustomize manifests, generate bundle, and other related commands.

  1. $ make bundle
  2. $ tree ./bundle
  3. ./bundle
  4. ├── manifests
  5. ├── cache.example.com_memcacheds.yaml
  6. ├── memcached-operator.clusterserviceversion.yaml
  7. ├── memcached-operator-controller-manager-metrics-monitor_monitoring.coreos.com_v1_servicemonitor.yaml
  8. ├── memcached-operator-controller-manager-metrics-service_v1_service.yaml
  9. ├── memcached-operator-metrics-reader_rbac.authorization.k8s.io_v1beta1_clusterrole.yaml
  10. └── memcached-operator-webhook-service_v1_service.yaml
  11. ├── metadata
  12. └── annotations.yaml
  13. └── tests
  14. └── scorecard

Bundle metadata in bundle/metadata/annotations.yaml contains information about a particular Operator version available in a registry. OLM uses this information to install specific Operator versions and resolve dependencies. That file and bundle.Dockerfile contain the same annotations, the latter as LABELs, which do not need to be modified in most cases; if you do decide to modify them, both sets of annotations must be the same to ensure consistent Operator deployment.

Channels

Metadata for each bundle contains channel information as well:

Channels become important when publishing, but we should still be aware of them beforehand as they’re required values in our metadata. make bundle writes the channel alpha by default.

Validation

The bundle recipe includes a call to operator-sdk bundle validate, which runs a set of required object validators on your bundle that ensure both its format and content meet the . These will always be run and cannot be disabled.

You may also have added CSV fields containing useful UI metadata for cluster console display, and want to ensure that metadata matches some hosted catalog’s submission requirements. The bundle validate command supports optional validators that can validate these bundle metadata. These validators are disabled by default, and can be selectively enabled with . You can list all available optional validators by setting the --list-optional flag:

  1. $ operator-sdk bundle validate --list-optional
  2. NAME LABELS DESCRIPTION
  3. operatorhub name=operatorhub OperatorHub.io metadata validation
  4. suite=operatorframework
  5. ...

For example, you want to turn on the operatorhub validator shown above so you can publish the 0.0.1 operator you recently created on . To do so, you can modify your Makefile’s bundle recipe to validate any further changes you make to bundle UI metadata related to OperatorHub requirements:

  1. bundle: ...
  2. ...
  3. operator-sdk bundle validate ./bundle --select-optional name=operatorhub

Documentation on optional validators:

A format consists of on-disk manifests (CSV, CRDs and other supported kinds) and metadata that define an Operator at all versions of that Operator. Each version is contained in its own directory, with a parent package manifest YAML file containing channel-to-version mappings, much like a bundle’s metadata.

If your Operator is already formatted as a package manifests and you do not wish to migrate to the bundle format yet, you should add the following to your Makefile to make development easier:

For Go-based Operator projects

For Helm/Ansible-based Operator projects

  1. # Options for "packagemanifests".
  2. ifneq ($(origin FROM_VERSION), undefined)
  3. PKG_FROM_VERSION := --from-version=$(FROM_VERSION)
  4. endif
  5. ifneq ($(origin CHANNEL), undefined)
  6. PKG_CHANNELS := --channel=$(CHANNEL)
  7. endif
  8. ifeq ($(IS_CHANNEL_DEFAULT), 1)
  9. PKG_IS_DEFAULT_CHANNEL := --default-channel
  10. endif
  11. PKG_MAN_OPTS ?= $(PKG_FROM_VERSION) $(PKG_CHANNELS) $(PKG_IS_DEFAULT_CHANNEL)
  12. # Generate package manifests.
  13. packagemanifests: kustomize
  14. operator-sdk generate kustomize manifests -q
  15. cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG)
  16. $(KUSTOMIZE) build config/manifests | operator-sdk generate packagemanifests -q --version $(VERSION) $(PKG_MAN_OPTS)

By default make packagemanifests will generate a CSV, a package manifest file, and copy CRDs in the package manifests format:

  1. $ make packagemanifests IMG=quay.io/<user>/memcached-operator:v0.0.1
  2. $ tree ./packagemanifests
  3. ./packagemanifests
  4. ├── 0.0.1
  5. ├── cache.my.domain_memcacheds.yaml
  6. └── memcached-operator.clusterserviceversion.yaml
  7. └── memcached-operator.package.yaml

If using a bundle format, the current version of your CSV can be updated by running:

    If using a package manifests format, run:

    Running the command for either format will append your new CRD to spec.customresourcedefinitions.owned, replace the old data at spec.install.spec.deployments with your updated Deployment, and update your existing CSV manifest. The SDK will not overwrite user-defined fields like spec.maintainers.

    Let’s say you’re upgrading your Operator to version v0.0.2, you’ve already updated the VERSION variable in your Makefile to 0.0.2, and built a new operator image quay.io/<user>/memcached-operator:v0.0.2. You also want to add a new channel beta, and use it as the default channel.

    First, update spec.replaces in your to the current CSV name. In this case, the change would look like:

    1. spec:
    2. ...
    3. replaces: memcached-operator.v0.0.1

    Next, upgrade your bundle. If using a bundle format, a new version of your CSV can be created by running:

    If using a package manifests format, run:

    1. $ make packagemanifests FROM_VERSION=0.0.1 CHANNEL=beta IS_CHANNEL_DEFAULT=1 IMG=quay.io/<user>/memcached-operator:v0.0.2

    Running the command for either format will persist user-defined fields, and updates spec.version and metadata.name.

    For packagemanifests only The command will also populate spec.replaces with the old CSV version’s name.

    Below are two lists of fields: the first is a list of all fields the SDK and OLM expect in a CSV, and the second are optional.

    For Go Operators only: Several fields require user input (labeled user) or a CSV marker (labeled marker). This list may change as the SDK becomes better at generating CSV’s. These markers are not available to Ansible or Helm project types.

    Required:

    • metadata.name _(user*)_: a *unique* name for this CSV of the format <project-name>.vX.Y.Z, ex. app-operator.v0.0.1.
    • spec.displayName (user) : a name to display for the Operator in Operator Hub.
    • spec.version _(user*)_: semantic version of the Operator, ex. 0.0.1.
    • spec.installModes (user): what mode of OLM should use. Currently all but MultiNamespace are supported by SDK Operators.
    • spec.customresourcedefinitions: any CRDs the Operator uses. Certain fields in elements of owned will be filled by the SDK.
      • owned: all CRDs the Operator deploys itself from it’s bundle.
        • name: CRD’s metadata.name.
        • kind: CRD’s metadata.spec.names.kind.
        • version: CRD’s metadata.spec.version.
        • description (marker) : description of the CRD.
        • displayName (marker) : display name of the CRD.
        • resources (marker) : any Kubernetes resources used by the CRD, ex. Pod‘s and ConfigMap‘s.
        • specDescriptors (marker) : UI hints for inputs and outputs of the Operator’s spec.
        • statusDescriptors (marker) : UI hints for inputs and outputs of the Operator’s status.
        • actionDescriptors (user) : UI hints for an Operator’s in-cluster actions.
      • required (user) : all CRDs the Operator expects to be present in-cluster, if any. All required element fields must be populated manually.

    Optional:

    • spec.description (user) : a thorough description of the Operator’s functionality.
    • spec.keywords (user) : a list of keywords describing the Operator.
    • spec.maintainers (user) : a list of human or organizational entities maintaining the Operator, with a name and email.
    • spec.provider (user) : the Operator provider, with a name; usually an organization.
    • spec.labels (user) : a list of key:value pairs to be used by Operator internals.
    • metadata.annotations.alm-examples: CR examples, in JSON string literal format, for your CRD’s. Ideally one per CRD.
    • metadata.annotations.capabilities: level of Operator capability. See the Operator maturity model for a list of valid values.
    • spec.replaces (user): the name of the CSV being replaced by this CSV.
    • spec.links (user) : a list of URL’s to websites, documentation, etc. pertaining to the Operator or application being managed, each with a name and url.
    • spec.selector (user) : selectors by which the Operator can pair resources in a cluster.
    • spec.icon (user) : a base64-encoded icon unique to the Operator, set in a base64data field with a mediatype.
    • spec.maturity (user): the Operator’s maturity, ex. alpha.