第 4 章 目录
4.1. 基于文件的目录
Operator Lifecycle Manager (OLM) v1 只是一个技术预览功能。技术预览功能不受红帽产品服务等级协议(SLA)支持,且功能可能并不完整。红帽不推荐在生产环境中使用它们。这些技术预览功能可以使用户提早试用新的功能,并有机会在开发阶段提供反馈意见。
有关红帽技术预览功能支持范围的更多信息,请参阅技术预览功能支持范围。
OpenShift Container Platform 中的 Operator Lifecycle Manager (OLM) v1 支持 基于文件的目录来发现和源集群扩展,包括集群中的 Operator。
目前,Operator Lifecycle Manager (OLM) v1 无法验证私有 registry,如红帽提供的 Operator 目录。这是个已知问题。因此,依赖 Red Hat Operator 目录的 OLM v1 流程无法正常工作。(OCPBUGS-36364)
4.1.1. 亮点
基于文件的目录是 Operator Lifecycle Manager (OLM) 中目录格式的最新迭代。它是基于纯文本(JSON 或 YAML)和早期 SQLite 数据库格式的声明式配置演变,并且完全向后兼容。此格式的目标是启用 Operator 目录编辑、可组合性和可扩展性。
- 编辑
使用基于文件的目录,与目录内容交互的用户可以对格式进行直接更改,并验证其更改是否有效。由于这种格式是纯文本 JSON 或 YAML,因此目录维护人员可以通过手动或广泛支持的 JSON 或 YAML 工具(如
jq
CLI)轻松操作目录元数据。此可编辑功能启用以下功能和用户定义的扩展:
- 将现有捆绑包提升到新频道
- 更改软件包的默认频道
- 用于添加、更新和删除升级边缘的自定义算法
- Composability
基于文件的目录存储在任意目录层次结构中,从而启用目录组成。例如,考虑两个单独的基于文件的目录目录:
catalogA
和catalogB
。目录维护人员可以通过生成新目录catalogC
并将catalogA
和catalogB
复制到其中来创建新的组合目录。这种可组合性支持分散的目录。格式允许 Operator 作者维护特定于 Operator 的目录,它允许维护人员轻松构建由单个 Operator 目录组成的目录。基于文件的目录可以通过组合多个其他目录、提取一个目录的子集或两者的组合来组成。
注意不允许软件包中重复软件包和重复捆绑包。如果找到任何重复项,
opm validate
命令将返回错误。因为 Operator 作者最熟悉其 Operator、其依赖项及其升级兼容性,所以他们可以维护自己的 Operator 目录并直接控制其内容。对于基于文件的目录,Operator 作者负责在目录中构建和维护其软件包的任务。但是,复合目录维护者仅拥有在其目录中管理软件包并将目录发布到用户的任务。
- 可扩展性
基于文件的目录规格是目录的一个低级别表示。虽然目录维护器可以直接以低级形式维护,但目录维护人员可以在其自己的自定义工具上构建有趣的扩展,以供其自身的自定义工具用于实现任意数量的变异。
例如,工具可以将一个高级 API (如
(mode=semver)
) 转换为升级边缘基于文件的低级别目录格式。或目录维护人员可能需要通过添加新属性到符合特定标准的捆绑包来自定义所有捆绑包元数据。虽然这种可扩展性允许在低级别 API 上开发额外的官方工具,用于将来的 OpenShift Container Platform 版本,但目录维护人员也具有此功能。
4.1.2. 目录结构
基于文件的目录可从基于目录的文件系统进行存储和加载。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
此推荐结构具有目录层次结构中的每个子目录都是自包含目录的属性,它使得目录组成、发现和导航简单文件系统操作。通过将目录复制到父目录的根目录,目录也可以包含在父目录中。
4.1.3. 模式
基于文件的目录使用基于 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 中简洁地表达。
Operator Lifecycle Manager (OLM) 目录目前使用三种模式(olm.package
、olm.channel
和 olm.bundle
),它们对应于 OLM 的现有软件包和捆绑包概念。
目录中的每个 Operator 软件包都需要一个 olm.package
blob、至少一个 olm.channel
blob 以及一个或多个 olm.bundle
blob。
所有 olm.*
模式都为 OLM 定义的模式保留。自定义模式必须使用唯一前缀,如您拥有的域。
4.1.3.1. olm.package schema
olm.package
模式为 Operator 定义软件包级别的元数据。这包括其名称、描述、默认频道和图标。
例 4.1. olm.package
schema
#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 } }
4.1.3.2. olm.channel schema
olm.channel
模式在软件包中定义频道、属于频道成员的捆绑包条目,以及这些捆绑包的升级边缘。
如果捆绑包条目代表多个 olm.channel
blob 中的边缘,则每个频道只能显示一次。
它对条目的 replaces
值有效,以引用无法在此目录或其他目录中找到的另一捆绑包名称。但是,所有其他频道变量都必须为 true,比如频道没有多个磁头。
例 4.2. olm.channel
schema
#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
字段时,跳过的 Operator 版本会从更新图中删除,因此不再可以被带有 Subscription
对象的 spec.startingCSV
属性的用户安装。
您可以使用 skipRange
和 replaces
字段以递增方式更新 Operator,同时保留以前安装的版本供用户使用。确保 replaces
字段指向相关的 Operator 版本前一个版本。
4.1.3.3. olm.bundle schema
例 4.3. olm.bundle
schema
#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 & !="" }
4.1.3.4. olm.deprecations schema
可选的 olm.deprecations
模式定义了目录中软件包、捆绑包和频道的弃用信息。Operator 作者可使用此模式向从目录运行这些 Operator 的用户提供与 Operator 相关的信息,如支持状态和推荐的升级路径。
当定义此模式时,OpenShift Container Platform Web 控制台会在 OperatorHub 的预安装页面上为 Operator 受影响元素显示警告徽标,包括任何自定义弃用信息。
olm.deprecations
schema 条目包含一个或多个 reference
类型,这表示弃用范围。安装 Operator 后,可以在相关的 Subscription
对象上查看任何指定的信息作为状态条件。
类型 | 影响范围 | 状态条件 |
---|---|---|
| 代表整个软件包 |
|
| 代表一个频道 |
|
| 表示一个捆绑包版本 |
|
每个 reference
类型都有自己的要求,如下例所示。
例 4.4. 带有每个 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.
弃用功能没有考虑重叠的弃用,例如,软件包与频道与捆绑包的比较。
Operator 作者可在与软件包的 index.yaml
文件相同的目录中将 olm.deprecations
schema 条目保存为 deprecations.yaml
文件:
带有弃用的目录的目录结构示例
my-catalog └── my-operator ├── index.yaml └── deprecations.yaml
其他资源
4.1.4. Properties
属性是可附加到基于文件的目录方案的任意元数据片段。type
字段是一个有效指定 value
字段语义和语法含义的字符串。该值可以是任意 JSON 或 YAML。
OLM 定义几个属性类型,再次使用保留的 olm.*
前缀。
4.1.4.1. olm.package 属性
olm.package
属性定义软件包名称和版本。这是捆绑包上的必要属性,必须正好有一个这些属性。packageName
字段必须与捆绑包的 first-class package
字段匹配,并且 version
字段必须是有效的语义版本。
例 4.5. olm.package
属性
#PropertyPackage: { type: "olm.package" value: { packageName: string & !="" version: string & !="" } }
4.1.4.2. olm.gvk 属性
olm.gvk
属性定义此捆绑包提供的 Kubernetes API 的 group/version/kind (GVK)。OLM 使用此属性解析捆绑包,作为列出与所需 API 相同的 GVK 的其他捆绑包的依赖项。GVK 必须遵循 Kubernetes GVK 验证。
例 4.6. olm.gvk
属性
#PropertyGVK: { type: "olm.gvk" value: { group: string & !="" version: string & !="" kind: string & !="" } }
4.1.4.3. olm.package.required
olm.package.required
属性定义此捆绑包需要的另一软件包的软件包名称和版本范围。对于捆绑包列表的每个所需软件包属性,OLM 确保集群中为列出的软件包和所需版本范围安装了一个 Operator。versionRange
字段必须是有效的语义版本(模拟)范围。
例 4.7. olm.package.required
属性
#PropertyPackageRequired: { type: "olm.package.required" value: { packageName: string & !="" versionRange: string & !="" } }
4.1.4.4. olm.gvk.required
olm.gvk.required
属性定义此捆绑包需要的 Kubernetes API 的 group/version/kind (GVK)。对于捆绑包列表的每个必需的 GVK 属性,OLM 确保集群中安装了提供它的 Operator。GVK 必须遵循 Kubernetes GVK 验证。
例 4.8. olm.gvk.required
属性
#PropertyGVKRequired: { type: "olm.gvk.required" value: { group: string & !="" version: string & !="" kind: string & !="" } }
4.1.5. 目录示例
对于基于文件的目录,目录维护人员可以专注于 Operator 策展和兼容性。由于 Operator 作者已为其 Operator 创建了特定于 Operator 的目录,因此目录维护人员可以通过将每个 Operator 目录渲染到目录根目录的子目录来构建其目录。
构建基于文件的目录的方法有很多;以下步骤概述了一个简单的方法:
为目录维护一个配置文件,其中包含目录中每个 Operator 的镜像引用:
目录配置文件示例
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
运行一个脚本,该脚本将解析配置文件并从其引用中创建新目录:
脚本示例
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"
4.1.6. 指南
在维护基于文件的目录时,请考虑以下准则。
4.1.6.1. 不可变捆绑包
Operator Lifecycle Manager (OLM) 的常规建议是捆绑包镜像及其元数据应视为不可变。
如果一个错误的捆绑包被推送到目录,您必须假设至少有一个用户已升级到该捆绑包。基于这种假设,您必须从损坏的捆绑包中发布另一个带有升级边缘的捆绑包,以确保安装了有问题的捆绑包的用户收到升级。如果目录中更新了该捆绑包的内容,OLM 将不会重新安装已安装的捆绑包。
然而,在某些情况下首选更改目录元数据:
-
频道升级:如果您已发布了捆绑包,且之后决定将其添加到另一个频道,您可以在另一个
olm.channel
blob 中添加捆绑包条目。 -
新的升级边缘:如果您发布一个新的
1.2.z
捆绑包版本,如1.2.4
,但1.3.0
已发布,您可以更新1.3.0
的目录元数据以跳过1.2.4
。
4.1.6.2. 源控制
目录元数据应存储在源控制中,并被视为事实来源。目录镜像的更新应包括以下步骤:
- 使用新的提交来更新源控制的目录目录。
-
构建并推送目录镜像。使用一致的标记分类,如
:latest
或:<target_cluster_version>
,以便用户可以在目录可用时接收到更新。
4.1.7. CLI 用法
有关使用 opm
CLI 创建基于文件的目录的说明,请参阅管理自定义目录。
有关管理基于文件的目录的 opm
CLI 命令的参考文档,请参阅 CLI 工具。
4.1.8. 自动化
建议 Operator 作者和目录维护人员使用 CI/CD 工作流自动化其目录维护。目录维护人员可通过构建 GitOps 自动化以完成以下任务来进一步改进:
- 检查是否允许拉取请求 (PR) 作者进行请求的更改,例如更新其软件包的镜像引用。
-
检查目录更新是否通过
opm validate
命令。 - 检查是否有更新的捆绑包或目录镜像引用,目录镜像在集群中成功运行,来自该软件包的 Operator 可以成功安装。
- 自动合并通过之前检查的 PR。
- 自动重新构建和重新发布目录镜像。