×

Operator Lifecycle Manager (OLM) v1 仅为技术预览功能。技术预览功能不受 Red Hat 生产服务级别协议 (SLA) 的支持,并且可能功能不完整。Red Hat 不建议在生产环境中使用它们。这些功能可让客户提前访问即将推出的产品功能,从而能够在开发过程中测试功能并提供反馈。

有关 Red Hat 技术预览功能的支持范围的更多信息,请参阅 技术预览功能支持范围

OpenShift Container Platform 中的 Operator Lifecycle Manager (OLM) v1 支持基于文件的目录,用于发现和获取集群扩展(包括 Operator)在集群上的来源。

目前,Operator Lifecycle Manager (OLM) v1 无法验证私有注册表(例如 Red Hat 提供的 Operator 目录)的身份。这是一个已知问题。因此,依赖于安装 Red Hat Operators 目录的 OLM v1 流程无法正常工作。(OCPBUGS-36364

重点

基于文件的目录是 Operator Lifecycle Manager (OLM) 中目录格式的最新迭代。它是早期 SQLite 数据库格式的基于纯文本(JSON 或 YAML)和声明性配置的演变,并且完全向后兼容。此格式的目标是启用 Operator 目录编辑、组合和扩展。

编辑

使用基于文件的目录,与目录内容交互的用户能够直接更改格式并验证其更改是否有效。由于此格式是纯文本 JSON 或 YAML,因此目录维护者可以使用手动或使用广泛已知和支持的 JSON 或 YAML 工具(例如jq CLI)轻松操作目录元数据。

此可编辑性支持以下功能和用户定义的扩展

  • 将现有捆绑包提升到新通道

  • 更改包的默认通道

  • 用于添加、更新和删除升级边的自定义算法

组合性

基于文件的目录存储在任意目录层次结构中,这使得目录组合成为可能。例如,考虑两个单独的基于文件的目录:catalogAcatalogB。目录维护者可以通过创建一个新的目录catalogC并将catalogAcatalogB复制到其中来创建一个新的组合目录。

这种组合性支持分散式目录。此格式允许 Operator 作者维护特定于 Operator 的目录,并且允许维护者轻松构建由单个 Operator 目录组成的目录。可以通过组合多个其他目录、提取一个目录的子集或同时使用这两种方法来组合基于文件的目录。

不允许在包中出现重复的包和重复的捆绑包。如果发现任何重复项,opm validate 命令将返回错误。

由于 Operator 作者最熟悉他们的 Operator、其依赖项及其升级兼容性,因此他们能够维护他们自己特定于 Operator 的目录并直接控制其内容。使用基于文件的目录,Operator 作者拥有在目录中构建和维护其包的任务。但是,组合式目录维护者只拥有管理其目录中包的任务以及向用户发布目录的任务。

可扩展性

基于文件的目录规范是目录的低级表示。虽然可以直接以其低级形式维护它,但目录维护者可以在其之上构建有趣的扩展,这些扩展可以被他们自己的自定义工具用于进行任意数量的变异。

例如,工具可以将高级 API(例如(mode=semver))转换为低级基于文件的目录格式,用于升级边。或者,目录维护者可能需要通过向满足特定条件的捆绑包添加新属性来自定义所有捆绑包元数据。

虽然此可扩展性允许在低级 API 之上开发用于未来 OpenShift Container Platform 版本的附加官方工具,但主要好处是目录维护者也具有此功能。

目录结构

基于文件的目录可以存储和加载自基于目录的文件系统。opm CLI 通过遍历根目录并递归进入子目录来加载目录。CLI 尝试加载它找到的每个文件,如果出现任何错误则失败。

可以使用.indexignore文件忽略非目录文件,这些文件的模式和优先级规则与.gitignore文件相同。

示例.indexignore文件
# Ignore everything except non-object .json and .yaml files
**/*
!*.json
!*.yaml
**/objects/*.json
**/objects/*.yaml

目录维护者可以灵活地选择他们想要的布局,但是建议将每个包的基于文件的目录 Blob 存储在单独的子目录中。每个单独的文件可以是 JSON 或 YAML;目录中的每个文件不必都使用相同的格式。

基本的推荐结构
catalog
├── packageA
│   └── index.yaml
├── packageB
│   ├── .indexignore
│   ├── index.yaml
│   └── objects
│       └── packageB.v0.1.0.clusterserviceversion.yaml
└── packageC
    └── index.json
    └── deprecations.yaml

此推荐结构具有以下属性:目录层次结构中的每个子目录都是一个自包含的目录,这使得目录组合、发现和导航成为简单文件系统操作。还可以通过将其复制到父目录的根目录中来将目录包含在父目录中。

模式

基于文件的目录使用基于CUE 语言规范的格式,可以使用任意模式进行扩展。以下_Meta CUE 模式定义了所有基于文件的目录 Blob 必须遵守的格式

_Meta 模式
_Meta: {
  // schema is required and must be a non-empty string
  schema: string & !=""

  // package is optional, but if it's defined, it must be a non-empty string
  package?: string & !=""

  // properties is optional, but if it's defined, it must be a list of 0 or more properties
  properties?: [... #Property]
}

#Property: {
  // type is required
  type: string & !=""

  // value is required, and it must not be null
  value: !=null
}

本规范中列出的任何 CUE 模式都不应被认为是详尽无遗的。opm validate 命令具有其他验证功能,这些功能难以或无法在 CUE 中简洁地表达。

操作符生命周期管理器 (OLM) 目录当前使用三个模式 (olm.packageolm.channelolm.bundle),它们对应于 OLM 现有的包和捆绑包概念。

目录中的每个操作符包都正好需要一个 olm.package 块,至少一个 olm.channel 块和一个或多个 olm.bundle 块。

所有 olm.* 模式都保留供 OLM 定义的模式使用。自定义模式必须使用唯一的前缀,例如您拥有的域名。

olm.package 模式

olm.package 模式定义操作符的包级元数据。这包括其名称、描述、默认通道和图标。

olm.package 模式
#Package: {
  schema: "olm.package"

  // Package name
  name: string & !=""

  // A description of the package
  description?: string

  // The package's default channel
  defaultChannel: string & !=""

  // An optional icon
  icon?: {
    base64data: string
    mediatype:  string
  }
}

olm.channel 模式

olm.channel 模式定义包中的通道、作为通道成员的捆绑包条目以及这些捆绑包的升级边缘。

如果捆绑包条目在多个 olm.channel 块中表示边缘,则它每个通道只能出现一次。

条目的 replaces 值引用此目录或其他目录中找不到的另一个捆绑包名称是有效的。但是,所有其他通道不变量都必须成立,例如通道不应具有多个头。

olm.channel 模式
#Channel: {
  schema: "olm.channel"
  package: string & !=""
  name: string & !=""
  entries: [...#ChannelEntry]
}

#ChannelEntry: {
  // name is required. It is the name of an `olm.bundle` that
  // is present in the channel.
  name: string & !=""

  // replaces is optional. It is the name of bundle that is replaced
  // by this entry. It does not have to be present in the entry list.
  replaces?: string & !=""

  // skips is optional. It is a list of bundle names that are skipped by
  // this entry. The skipped bundles do not have to be present in the
  // entry list.
  skips?: [...string & !=""]

  // skipRange is optional. It is the semver range of bundle versions
  // that are skipped by this entry.
  skipRange?: string & !=""
}

使用 skipRange 字段时,跳过的操作符版本将从更新图中修剪,并且使用 Subscription 对象的 spec.startingCSV 属性的用户将不再能够安装这些版本。

您可以通过同时使用 skipRangereplaces 字段,在保持以前安装的版本可供用户将来安装的同时,增量更新操作符。确保 replaces 字段指向相关操作符版本的直接先前版本。

olm.bundle 模式

olm.bundle 模式
#Bundle: {
  schema: "olm.bundle"
  package: string & !=""
  name: string & !=""
  image: string & !=""
  properties: [...#Property]
  relatedImages?: [...#RelatedImage]
}

#Property: {
  // type is required
  type: string & !=""

  // value is required, and it must not be null
  value: !=null
}

#RelatedImage: {
  // image is the image reference
  image: string & !=""

  // name is an optional descriptive name for an image that
  // helps identify its purpose in the context of the bundle
  name?: string & !=""
}

olm.deprecations 模式

可选的 olm.deprecations 模式定义目录中包、捆绑包和通道的弃用信息。操作符作者可以使用此模式向从目录运行这些操作符的用户提供有关其操作符的相关消息,例如支持状态和推荐的升级路径。

定义此模式时,OpenShift Container Platform Web 控制台会在操作符的受影响元素上显示警告徽章,包括任何自定义弃用消息,这些徽章同时显示在 OperatorHub 的安装前和安装后页面上。

olm.deprecations 模式条目包含一个或多个以下 reference 类型,这表示弃用范围。安装操作符后,任何指定的邮件都可以在相关的 Subscription 对象上显示为状态条件。

表 1. 弃用 reference 类型
类型 范围 状态条件

olm.package

表示整个包

PackageDeprecated

olm.channel

表示一个通道

ChannelDeprecated

olm.bundle

表示一个捆绑包版本

BundleDeprecated

每个 reference 类型都有其自身的要求,如下例中详细说明。

包含每个 reference 类型的示例 olm.deprecations 模式
schema: olm.deprecations
package: my-operator (1)
entries:
  - reference:
      schema: olm.package (2)
    message: | (3)
    The 'my-operator' package is end of life. Please use the
    'my-operator-new' package for support.
  - reference:
      schema: olm.channel
      name: alpha (4)
    message: |
    The 'alpha' channel is no longer supported. Please switch to the
    'stable' channel.
  - reference:
      schema: olm.bundle
      name: my-operator.v1.68.0 (5)
    message: |
    my-operator.v1.68.0 is deprecated. Uninstall my-operator.v1.68.0 and
    install my-operator.v1.72.0 for support.
1 每个弃用模式都必须具有 package 值,并且该包引用在整个目录中必须唯一。不应有相关的 name 字段。
2 olm.package 模式不应包含 name 字段,因为它是由模式前面定义的 package 字段确定的。
3 对于任何 reference 类型,所有 message 字段都必须是非零长度,并表示为不透明文本块。
4 olm.channel 模式的 name 字段是必需的。
5 olm.bundle 模式的 name 字段是必需的。

弃用功能不考虑重叠弃用,例如包与通道与捆绑包。

操作符作者可以将 olm.deprecations 模式条目保存为包的 index.yaml 文件同一目录中的 deprecations.yaml 文件

包含弃用的目录的示例目录结构
my-catalog
└── my-operator
    ├── index.yaml
    └── deprecations.yaml

属性

属性是可以附加到基于文件的目录模式的任意元数据片段。type 字段是一个字符串,它有效地指定了 value 字段的语义和句法含义。该值可以是任何任意 JSON 或 YAML。

OLM 定义了一些属性类型,同样使用保留的 olm.* 前缀。

olm.package 属性

olm.package 属性定义包名称和版本。这是捆绑包上的必需属性,并且必须只有一个此类属性。packageName 字段必须与捆绑包的第一类 package 字段匹配,version 字段必须是有效的语义版本。

olm.package 属性
#PropertyPackage: {
  type: "olm.package"
  value: {
    packageName: string & !=""
    version: string & !=""
  }
}

olm.gvk 属性

olm.gvk 属性定义此捆绑包提供的 Kubernetes API 的组/版本/种类 (GVK)。OLM 使用此属性来解析具有此属性的捆绑包,作为列出相同 GVK 作为必需 API 的其他捆绑包的依赖项。GVK 必须符合 Kubernetes GVK 验证。

olm.gvk 属性
#PropertyGVK: {
  type: "olm.gvk"
  value: {
    group: string & !=""
    version: string & !=""
    kind: string & !=""
  }
}

olm.package.required

olm.package.required 属性定义此捆绑包所需的另一个包的包名称和版本范围。对于捆绑包列出的每个必需包属性,OLM 都会确保群集上安装了列出包的操作符,并且版本范围在要求范围内。versionRange 字段必须是有效的语义版本 (semver) 范围。

olm.package.required 属性
#PropertyPackageRequired: {
  type: "olm.package.required"
  value: {
    packageName: string & !=""
    versionRange: string & !=""
  }
}

olm.gvk.required

olm.gvk.required 属性定义此捆绑包所需的 Kubernetes API 的组/版本/种类 (GVK)。对于捆绑包列出的每个必需 GVK 属性,OLM 都会确保安装了提供它的操作符。GVK 必须符合 Kubernetes GVK 验证。

olm.gvk.required 属性
#PropertyGVKRequired: {
  type: "olm.gvk.required"
  value: {
    group: string & !=""
    version: string & !=""
    kind: string & !=""
  }
}

示例目录

使用基于文件的目录,目录维护者可以专注于操作符管理和兼容性。由于操作符作者已经为其操作符生成了特定于操作符的目录,因此目录维护者可以通过将每个操作符目录渲染到目录根目录的子目录中来构建其目录。

构建基于文件的目录有很多可能的方法;以下步骤概述了一种简单的方法

  1. 为目录维护单个配置文件,其中包含目录中每个操作符的镜像引用

    示例目录配置文件
    name: community-operators
    repo: quay.io/community-operators/catalog
    tag: latest
    references:
    - name: etcd-operator
      image: quay.io/etcd-operator/index@sha256:5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03
    - name: prometheus-operator
      image: quay.io/prometheus-operator/index@sha256:e258d248fda94c63753607f7c4494ee0fcbe92f1a76bfdac795c9d84101eb317
  2. 运行一个脚本,解析配置文件并根据其引用创建一个新的目录。

    示例脚本
    name=$(yq eval '.name' catalog.yaml)
    mkdir "$name"
    yq eval '.name + "/" + .references[].name' catalog.yaml | xargs mkdir
    for l in $(yq e '.name as $catalog | .references[] | .image + "|" + $catalog + "/" + .name + "/index.yaml"' catalog.yaml); do
      image=$(echo $l | cut -d'|' -f1)
      file=$(echo $l | cut -d'|' -f2)
      opm render "$image" > "$file"
    done
    opm generate dockerfile "$name"
    indexImage=$(yq eval '.repo + ":" + .tag' catalog.yaml)
    docker build -t "$indexImage" -f "$name.Dockerfile" .
    docker push "$indexImage"

指导原则

维护基于文件的目录时,请考虑以下指导原则。

不可变的包

Operator Lifecycle Manager (OLM) 的一般建议是,包镜像及其元数据应被视为不可变的。

如果已将损坏的包推送到目录,则必须假设至少有一位用户已升级到该包。基于此假设,必须发布另一个包,其中包含从损坏包升级的边,以确保安装了损坏包的用户收到升级。如果目录中包的内容已更新,OLM 将不会重新安装已安装的包。

但是,在某些情况下,更改目录元数据是更好的选择。

  • 通道升级:如果您已经发布了一个包,并且稍后决定要将其添加到另一个通道,则可以在另一个olm.channel blob 中添加您的包的条目。

  • 新的升级边:例如,如果您发布了新的1.2.z包版本,例如1.2.4,但1.3.0已经发布,则可以更新1.3.0的目录元数据以跳过1.2.4

源代码管理

目录元数据应存储在源代码管理中,并视为真实来源。更新目录镜像应包括以下步骤:

  1. 使用新的提交更新源代码控制的目录。

  2. 构建和推送目录镜像。使用一致的标记分类法,例如:latest:<target_cluster_version>,以便用户可以在目录更新可用时收到更新。

CLI 使用

有关使用opm CLI 创建基于文件的目录的说明,请参阅管理自定义目录

有关与管理基于文件的目录相关的opm CLI 命令的参考文档,请参阅CLI 工具

自动化

鼓励操作员作者和目录维护者使用 CI/CD 工作流程自动化其目录维护。目录维护者可以通过构建 GitOps 自动化来进一步改进此过程,以完成以下任务:

  • 检查拉取请求 (PR) 作者是否有权进行请求的更改,例如通过更新其软件包的镜像引用。

  • 检查目录更新是否通过opm validate命令。

  • 检查更新的包或目录镜像引用是否存在,目录镜像是否在集群中成功运行,以及来自该包的操作符是否可以成功安装。

  • 自动合并通过先前检查的 PR。

  • 自动重新构建和重新发布目录镜像。