github.com/operator-framework/operator-lifecycle-manager@v0.30.0/doc/design/building-your-csv.md (about) 1 <!-- START doctoc generated TOC please keep comment here to allow auto update --> 2 <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> 3 **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* 4 5 - [Building a Cluster Service Version (CSV) for the Operator Framework](#building-a-cluster-service-version-csv-for-the-operator-framework) 6 - [What is a Cluster Service Version (CSV)?](#what-is-a-cluster-service-version-csv) 7 - [CSV Metadata](#csv-metadata) 8 - [Your Custom Resource Definitions](#your-custom-resource-definitions) 9 - [Owned CRDs](#owned-crds) 10 - [Required CRDs](#required-crds) 11 - [CRD Templates](#crd-templates) 12 - [Your API Services](#your-api-services) 13 - [Owned APIServices](#owned-apiservices) 14 - [APIService Resource Creation](#apiservice-resource-creation) 15 - [APIService Serving Certs](#apiservice-serving-certs) 16 - [Required APIServices](#required-apiservices) 17 - [Operator Metadata](#operator-metadata) 18 - [Operator Install](#operator-install) 19 - [Full Examples](#full-examples) 20 21 <!-- END doctoc generated TOC please keep comment here to allow auto update --> 22 23 # Building a Cluster Service Version (CSV) for the Operator Framework 24 25 This guide is intended to guide an Operator author to package a version of their Operator to run with the [Operator Lifecycle Manager](https://github.com/operator-framework/operator-lifecycle-manager). This will be a manual method that will walk through each section of the file, what it’s used for and how to populate it. 26 27 ## What is a Cluster Service Version (CSV)? 28 29 A CSV is the metadata that accompanies your Operator container image. It can be used to populate user interfaces with info like your logo/description/version and it is also a source of technical information needed to run the Operator, like the RBAC rules it requires and which Custom Resources it manages or depends on. 30 31 The Lifecycle Manager will parse this and do all of the hard work to wire up the correct Roles and Role Bindings, ensure that the Operator is started (or updated) within the desired namespace and check for various other requirements, all without the end users having to do anything. 32 33 You can read about the [full architecture in more detail](architecture.md#what-is-a-clusterserviceversion). 34 35 ## CSV Metadata 36 37 The object has the normal Kubernetes metadata. Since the CSV pertains to the specific version, the naming scheme is the name of the Operator + the semantic version number, eg `mongodboperator.v0.3`. 38 39 The namespace is used when a CSV will remain private to a specific namespace. Only users of that namespace will be able to view or instantiate the Operator. If you plan on distributing your Operator to many namespaces or clusters, you may want to explore bundling it into a [Catalog](architecture.md#catalog-registry-design). 40 41 The namespace listed in the CSV within a catalog is actually a placeholder, so it is common to simply list `placeholder`. Otherwise, loading a CSV directly into a namespace requires that namespace, of course. 42 43 ```yaml 44 apiVersion: operators.coreos.com/v1alpha1 45 kind: ClusterServiceVersion 46 metadata: 47 name: mongodboperator.v0.3 48 namespace: placeholder 49 ``` 50 51 ## Your Custom Resource Definitions 52 There are two types of CRDs that your Operator may use, ones that are “owned” by it and ones that it depends on, which are “required”. 53 ### Owned CRDs 54 55 The CRDs owned by your Operator are the most important part of your CSV. This establishes the link between your Operator and the required RBAC rules, dependency management and other under-the-hood Kubernetes concepts. 56 57 It’s common for your Operator to use multiple CRDs to link together concepts, such as top-level database configuration in one object and a representation of replica sets in another. List out each one in the CSV file. 58 59 **DisplayName**: A human readable version of your CRD name, eg. “MongoDB Standalone” 60 61 **Description**: A short description of how this CRD is used by the Operator or a description of the functionality provided by the CRD. 62 63 **Group**: The API group that this CRD belongs to, eg. database.example.com 64 65 **Kind**: The machine readable name of your CRD 66 67 **Name**: The full name of your CRD 68 69 The next two sections require more explanation. 70 71 **Resources**: 72 Your CRDs will own one or more types of Kubernetes objects. These are listed in the resources section to inform your end-users of the objects they might need to troubleshoot or how to connect to the application, such as the Service or Ingress rule that exposes a database. 73 74 It’s recommended to only list out the objects that are important to a human, not an exhaustive list of everything you orchestrate. For example, ConfigMaps that store internal state that shouldn’t be modified by a user shouldn’t appear here. 75 76 **SpecDescriptors, StatusDescriptors, and ActionDescriptors**: 77 These are a way to hint UIs with certain inputs or outputs of your Operator that are most important to an end user. If your CRD contains the name of a Secret or ConfigMap that the user must provide, you can specify that here. These items will be linked and highlighted in compatible UIs. 78 79 There are three types of descriptors: 80 81 ***SpecDescriptors***: A reference to fields in the `spec` block of an object. 82 83 ***StatusDescriptors***: A reference to fields in the `status` block of an object. 84 85 ***ActionDescriptors***: A reference to actions that can be performed on an object. 86 87 All Descriptors accept the following fields: 88 89 **DisplayName**: A human readable name for the Spec, Status, or Action. 90 91 **Description**: A short description of the Spec, Status, or Action and how it is used by the Operator. 92 93 **Path**: A dot-delimited path of the field on the object that this descriptor describes. 94 95 **X-Descriptors**: Used to determine which "capabilities" this descriptor has and which UI component to use. A canonical list of React UI X-Descriptors for OpenShift can be found [here](https://github.com/openshift/console/blob/master/frontend/packages/operator-lifecycle-manager/src/components/descriptors/types.ts). 96 97 More information on Descriptors can be found [here](https://github.com/openshift/console/tree/master/frontend/packages/operator-lifecycle-manager/src/components/descriptors). 98 99 Below is an example of a MongoDB “standalone” CRD that requires some user input in the form of a Secret and ConfigMap, and orchestrates Services, StatefulSets, Pods and ConfigMaps. 100 101 ```yaml 102 - displayName: MongoDB Standalone 103 group: mongodb.com 104 kind: MongoDbStandalone 105 name: mongodbstandalones.mongodb.com 106 resources: 107 - kind: Service 108 name: '' 109 version: v1 110 - kind: StatefulSet 111 name: '' 112 version: v1beta2 113 - kind: Pod 114 name: '' 115 version: v1 116 - kind: ConfigMap 117 name: '' 118 version: v1 119 specDescriptors: 120 - description: Credentials for Ops Manager or Cloud Manager. 121 displayName: Credentials 122 path: credentials 123 x-descriptors: 124 - 'urn:alm:descriptor:com.tectonic.ui:selector:core:v1:Secret' 125 - description: Project this deployment belongs to. 126 displayName: Project 127 path: project 128 x-descriptors: 129 - 'urn:alm:descriptor:com.tectonic.ui:selector:core:v1:ConfigMap' 130 - description: MongoDB version to be installed. 131 displayName: Version 132 path: version 133 x-descriptors: 134 - 'urn:alm:descriptor:com.tectonic.ui:label' 135 statusDescriptors: 136 - description: The status of each of the Pods for the MongoDB cluster. 137 displayName: Pod Status 138 path: pods 139 x-descriptors: 140 - 'urn:alm:descriptor:com.tectonic.ui:podStatuses' 141 version: v1 142 description: >- 143 MongoDB Deployment consisting of only one host. No replication of 144 data. 145 ``` 146 147 ### Required CRDs 148 149 Relying on other “required” CRDs is completely optional and only exists to reduce the scope of individual Operators and provide a way to compose multiple Operators together to solve an end-to-end use case. An example of this is an Operator that might set up an application and install an etcd cluster (from an etcd Operator) to use for distributed locking and a Postgres database (from a Postgres Operator) for data storage. 150 151 The Lifecycle Manager will check against the available CRDs and Operators in the cluster to fulfill these requirements. If suitable versions are found, the Operators will be started within the desired namespace and a Service Account created for each Operator to create/watch/modify the Kubernetes resources required. 152 153 **Name**: The full name of the CRD you require 154 155 **Version**: The version of that object API 156 157 **Kind**: The Kubernetes object kind 158 159 **DisplayName**: A human readable version of the CRD 160 161 **Description**: A summary of how the component fits in your larger architecture 162 163 ```yaml 164 required: 165 - name: etcdclusters.etcd.database.coreos.com 166 version: v1beta2 167 kind: EtcdCluster 168 displayName: etcd Cluster 169 description: Represents a cluster of etcd nodes. 170 ``` 171 ## CRD Templates 172 Users of your Operator will need to be aware of which options are required vs optional. You can provide templates for each of your CRDs with a minimum set of configuration as an annotation named `alm-examples`. Metadata for each template, for example an expanded description, can be included in an annotation named `alm-examples-metadata`, which should be a hash indexed with the `metadata.name` of the example in the `alm-examples` list. Compatible UIs will pre-enter the `alm-examples` template for users to further customize, and use the `alm-examples-metadata` to help users decide which template to select. 173 174 The annotation consists of a list of the `kind`, eg. the CRD name, and the corresponding `metadata` and `spec` of the Kubernetes object. Here’s a full example that provides templates for `EtcdCluster`, `EtcdBackup` and `EtcdRestore`: 175 176 ```yaml 177 metadata: 178 annotations: 179 alm-examples-metadata: >- 180 {"example-etcd-cluster":{"description":"Example EtcdCluster CR"},"example-etcd-restore":{"description":"Example EtcdRestore CR that restores data from S3"},"example-etcd-backup":{"description":"Example EtcdBackup CR that stores backups on S3"}} 181 alm-examples: >- 182 [{"apiVersion":"etcd.database.coreos.com/v1beta2","kind":"EtcdCluster","metadata":{"name":"example-etcd-cluster","namespace":"default"},"spec":{"size":3,"version":"3.2.13"}},{"apiVersion":"etcd.database.coreos.com/v1beta2","kind":"EtcdRestore","metadata":{"name":"example-etcd-restore"},"spec":{"etcdCluster":{"name":"example-etcd-cluster"},"backupStorageType":"S3","s3":{"path":"<full-s3-path>","awsSecret":"<aws-secret>"}}},{"apiVersion":"etcd.database.coreos.com/v1beta2","kind":"EtcdBackup","metadata":{"name":"example-etcd-backup"},"spec":{"etcdEndpoints":["<etcd-cluster-endpoints>"],"storageType":"S3","s3":{"path":"<full-s3-path>","awsSecret":"<aws-secret>"}}}] 183 ``` 184 185 ## Your API Services 186 As with CRDs, there are two types of APIServices that your Operator may use, “owned” and "required". 187 188 ### Owned APIServices 189 190 When a CSV owns an APIService, it is responsible for describing the deployment of the extension api-server that backs it and the group-version-kinds it provides. 191 192 An APIService is uniquely identified by the group-version it provides and can be listed multiple times to denote the different kinds it is expected to provide. 193 194 **DisplayName**: A human readable version of your APIService name, eg. “MongoDB Standalone” 195 196 **Description**: A short description of how this APIService is used by the Operator or a description of the functionality provided by the APIService. 197 198 **Group**: Group that the APIService provides, eg. database.example.com. 199 200 **Version**: Version of the APIService, eg v1alpha1 201 202 **Kind**: A kind that the APIService is expected to provide. 203 204 **DeploymentName**: 205 Name of the deployment defined by your CSV that corresponds to your APIService (required for owned APIServices). During the CSV pending phase, the OLM Operator will search your CSV's InstallStrategy for a deployment spec with a matching name, and if not found, will not transition the CSV to the install ready phase. 206 207 **Resources**: 208 Your APIServices will own one or more types of Kubernetes objects. These are listed in the resources section to inform your end-users of the objects they might need to troubleshoot or how to connect to the application, such as the Service or Ingress rule that exposes a database. 209 210 It’s recommended to only list out the objects that are important to a human, not an exhaustive list of everything you orchestrate. For example, ConfigMaps that store internal state that shouldn’t be modified by a user shouldn’t appear here. 211 212 **SpecDescriptors, StatusDescriptors, and ActionDescriptors**: 213 Essentially the same as for owned CRDs. 214 215 ### APIService Resource Creation 216 The Lifecycle Manager is responsible for creating or replacing the Service and APIService resources for each unique owned APIService. 217 * Service pod selectors are copied from the CSV deployment matching the APIServiceDescription's DeploymentName. 218 * A new CA key/cert pair is generated for for each installation and the base64 encoded CA bundle is embedded in the respective APIService resource. 219 220 ### APIService Serving Certs 221 The Lifecycle Manager handles generating a serving key/cert pair whenever an owned APIService is being installed. The serving cert has a CN containing the host name of the generated Service resource and is signed by the private key of the CA bundle embedded in the corresponding APIService resource. The cert is stored as a type `kubernetes.io/tls` Secret in the deployment namespace and a Volume named "apiservice-cert" is automatically appended to the Volumes section of the deployment in the CSV matching the APIServiceDescription's `DeploymentName` field. If one does not already exist, a VolumeMount with a matching name is also appended to all containers of that deployment. This allows users to define a VolumeMount with the expected name to accommodate any custom path requirements. The generated VolumeMount's path defaults to `/apiserver.local.config/certificates` and any existing VolumeMounts with the same path are replaced. 222 223 ### Required APIServices 224 225 The Lifecycle Manager will ensure all required CSVs have an APIService that is available and all expected group-version-kinds are discoverable before attempting installation. This allows a CSV to rely on specific kinds provided by APIServices it does not own. 226 227 **DisplayName**: A human readable version of your APIService name, eg. “MongoDB Standalone” 228 229 **Description**: A short description of how this APIService is used by the Operator or a description of the functionality provided by the APIService. 230 231 **Group**: Group that the APIService provides, eg. database.example.com. 232 233 **Version**: Version of the APIService, eg v1alpha1 234 235 **Kind**: A kind that the APIService is expected to provide. 236 237 ## Operator Metadata 238 The metadata section contains general metadata around the name, version and other info that aids users in discovery of your Operator. 239 240 **DisplayName**: Human readable name that describes your Operator and the CRDs that it implements 241 242 **Keywords**: A list of categories that your Operator falls into. Used for filtering within compatible UIs. 243 244 **Provider**: The name of the publishing entity behind the Operator 245 246 **Maturity**: Level of maturity the Operator has achieved at this version, eg. planning, pre-alpha, alpha, beta, stable, mature, inactive, or deprecated. 247 248 **Version**: The semanic version of the Operator. This value should be incremented each time a new Operator image is published. 249 250 **Icon**: a base64 encoded image of the Operator logo or the logo of the publisher. The `base64data` parameter contains the data and the `mediatype` specifies the type of image, eg. `image/png` or `image/svg+xml`. 251 252 **Links**: A list of relevant links for the Operator. Common links include documentation, how-to guides, blog posts, and the company homepage. 253 254 **Maintainers**: A list of names and email addresses of the maintainers of the Operator code. This can be a list of individuals or a shared email alias, eg. support@example.com. 255 256 **Description**: A markdown blob that describes the Operator. Important information to include: features, limitations and common use-cases for the Operator. If your Operator manages different types of installs, eg. standalone vs clustered, it is useful to give an overview of how each differs from each other, or which ones are supported for production use. 257 258 **MinKubeVersion**: A minimum version of Kubernetes that server is supposed to have so operator(s) can be deployed. The Kubernetes version must be in "Major.Minor.Patch" format (e.g: 1.11.0). 259 260 **Labels** (optional): Any key/value pairs used to organize and categorize this CSV object. 261 262 **Selectors** (optional): A label selector to identify related resources. Set this to select on current labels applied to this CSV object (if applicable). 263 264 **InstallModes**: A set of `InstallMode`s that tell OLM which `OperatorGroup`s an Operator can belong to. Belonging to an `OperatorGroup` means that OLM provides the set of targeted namespaces as an annotation on the Operator's CSV and any deployments defined therein. These deployments can then utilize [the Downward API](https://kubernetes.io/docs/tasks/inject-data-application/downward-api-volume-expose-pod-information/#the-downward-api) to inject the list of namespaces into their container(s). An `InstallMode` consists of an `InstallModeType` field and a boolean `Supported` field. There are four `InstallModeTypes`: 265 * `OwnNamespace`: If supported, the operator can be a member of an `OperatorGroup` that selects its own namespace 266 * `SingleNamespace`: If supported, the operator can be a member of an `OperatorGroup` that selects one namespace 267 * `MultiNamespace`: If supported, the operator can be a member of an `OperatorGroup` that selects more than one namespace 268 * `AllNamespaces`: If supported, the operator can be a member of an `OperatorGroup` that selects all namespaces (target namespace set is the empty string "") 269 270 Here's an example: 271 272 ```yaml 273 keywords: ['etcd', 'key value', 'database', 'coreos', 'open source'] 274 version: 0.9.2 275 maturity: alpha 276 replaces: etcdoperator.v0.9.0 277 maintainers: 278 - name: CoreOS, Inc 279 email: support@coreos.com 280 provider: 281 name: CoreOS, Inc 282 labels: 283 alm-owner-etcd: etcdoperator 284 operated-by: etcdoperator 285 selector: 286 matchLabels: 287 alm-owner-etcd: etcdoperator 288 operated-by: etcdoperator 289 links: 290 - name: Blog 291 url: https://coreos.com/etcd 292 - name: Documentation 293 url: https://coreos.com/operators/etcd/docs/latest/ 294 - name: etcd Operator Source Code 295 url: https://github.com/coreos/etcd-operator 296 icon: 297 - base64data: <base64-encoded-data> 298 mediatype: image/png 299 installModes: 300 - type: OwnNamespace 301 supported: true 302 - type: SingleNamespace 303 supported: true 304 - type: MultiNamespace 305 supported: false 306 - type: AllNamespaces 307 supported: true 308 ``` 309 310 ## Operator Install 311 The install block is how the Lifecycle Manager will instantiate the Operator on the cluster. There are two subsections within install: one to describe the `deployment` that will be started within the desired namespace and one that describes the Role `permissions` required to successfully run the Operator. 312 313 Ensure that the `serviceAccountName` used in the `deployment` spec matches one of the Roles described under `permissions`. 314 315 Multiple Roles should be described to reduce the scope of any actions needed containers that the Operator may run on the cluster. For example, if you have a component that generates a TLS Secret upon start up, a Role that allows `create` but not `list` on Secrets is more secure than using a single all-powerful Service Account. 316 317 It is also possible to set custom labels for Deployment in addition to the system labels set by the OLM. This labels should be present in the `label` fields of the `deployments` section. 318 319 Here’s a full example: 320 321 ```yaml 322 install: 323 spec: 324 deployments: 325 - name: example-operator 326 label: 327 application: example-operator 328 technology: general 329 spec: 330 replicas: 1 331 selector: 332 matchLabels: 333 k8s-app: example-operator 334 template: 335 metadata: 336 labels: 337 k8s-app: example-operator 338 spec: 339 containers: 340 image: 'quay.io/example/example-operator:v0.0.1' 341 imagePullPolicy: Always 342 name: example-operator 343 resources: 344 limits: 345 cpu: 200m 346 memory: 100Mi 347 requests: 348 cpu: 100m 349 memory: 50Mi 350 imagePullSecrets: 351 - name: '' 352 nodeSelector: 353 kubernetes.io/os: linux 354 serviceAccountName: example-operator 355 permissions: 356 - serviceAccountName: example-operator 357 rules: 358 - apiGroups: 359 - '' 360 resources: 361 - configmaps 362 - secrets 363 - services 364 verbs: 365 - get 366 - list 367 - create 368 - update 369 - delete 370 - apiGroups: 371 - apps 372 resources: 373 - statefulsets 374 verbs: 375 - '*' 376 - apiGroups: 377 - apiextensions.k8s.io 378 resources: 379 - customresourcedefinitions 380 verbs: 381 - get 382 - list 383 - watch 384 - create 385 - delete 386 - apiGroups: 387 - mongodb.com 388 resources: 389 - '*' 390 verbs: 391 - '*' 392 - serviceAccountName: example-operator-list 393 rules: 394 - apiGroups: 395 - '' 396 resources: 397 - services 398 verbs: 399 - get 400 - list 401 strategy: deployment 402 ``` 403 404 ## Full Examples 405 406 Several [complete examples of CSV files](https://github.com/operator-framework/community-operators) are stored in Github.