2.2. Operator Framework 打包格式


本指南概述了 OpenShift Container Platform 中 Operator Lifecycle Manager (OLM) 所支持的 Operator 打包格式。

2.2.1. 捆绑包格式

Operator 的 Bundle Format 是 Operator Framework 引入的新打包格式。为提高可伸缩性并为自行托管目录的上游用户提供更好地支持,Bundle Format 规格简化了 Operator 元数据的发布。

Operator 捆绑包代表 Operator 的单一版本。磁盘上的捆绑包清单是容器化的,并作为捆绑包镜像提供,该镜像是一个不可运行的容器镜像,其中存储了 Kubernetes 清单和 Operator 元数据。然后,使用现有容器工具(如 podmandocker)和容器 registry(如 Quay)来管理捆绑包镜像的存储和发布。

Operator 元数据可以包括:

  • 标识 Operator 的信息,如名称和版本。
  • 驱动 UI 的额外信息,例如其图标和一些示例自定义资源 (CR)。
  • 所需的和所提供的 API。
  • 相关镜像。

将清单加载到 Operator Registry 数据库中时,会验证以下要求:

  • 该捆绑包必须在注解中至少定义一个频道。
  • 每个捆绑包都只有一个集群服务版本(CSV)。
  • 如果 CSV 拥有自定义资源定义(CRD),则该 CRD 必须存在于捆绑包中。

2.2.1.1. 清单

捆绑包清单指的是一组 Kubernetes 清单,用于定义 Operator 的部署和 RBAC 模型。

捆绑包包括每个目录的一个 CSV,一般情况下,用来定义 CRD 所拥有的 API 的 CRD 位于 /manifest 目录中。

捆绑包格式布局示例

etcd
├── manifests
│   ├── etcdcluster.crd.yaml
│   └── etcdoperator.clusterserviceversion.yaml
│   └── secret.yaml
│   └── configmap.yaml
└── metadata
    └── annotations.yaml
    └── dependencies.yaml

额外支持的对象

以下对象类型也可以包括在捆绑包的 /manifests 目录中:

支持的可选对象类型

  • ClusterRole
  • ClusterRoleBinding
  • ConfigMap
  • ConsoleCLIDownload
  • ConsoleLink
  • ConsoleQuickStart
  • ConsoleYamlSample
  • PodDisruptionBudget
  • PriorityClass
  • PrometheusRule
  • 角色
  • RoleBinding
  • Secret
  • 服务
  • ServiceAccount
  • ServiceMonitor
  • VerticalPodAutoscaler

当捆绑包中包含这些可选对象时,Operator Lifecycle Manager(OLM)可以从捆绑包创建对象,并随 CSV 一起管理其生命周期:

可选对象的生命周期

  • 删除 CSV 后,OLM 会删除可选对象。
  • 当 CSV 被升级时:

    • 如果可选对象的名称相同,OLM 会更新它。
    • 如果可选对象的名称在版本间有所变化,OLM 会删除并重新创建它。

2.2.1.2. 注解

捆绑包还在其 /metadata 文件夹中包含 annotations.yaml 文件。此文件定义了更高级别的聚合数据,以帮助描述有关如何将捆绑包添加到捆绑包索引中的格式和软件包信息:

annotations.yaml 示例

annotations:
  operators.operatorframework.io.bundle.mediatype.v1: "registry+v1" 1
  operators.operatorframework.io.bundle.manifests.v1: "manifests/" 2
  operators.operatorframework.io.bundle.metadata.v1: "metadata/" 3
  operators.operatorframework.io.bundle.package.v1: "test-operator" 4
  operators.operatorframework.io.bundle.channels.v1: "beta,stable" 5
  operators.operatorframework.io.bundle.channel.default.v1: "stable" 6

1
Operator 捆绑包的介质类型或格式。registry+v1 格式表示它包含 CSV 及其关联的 Kubernetes 对象。
2
镜像中的该路径指向含有 Operator 清单的目录。该标签保留给以后使用,当前默认为 manifests/manifests.v1 值表示捆绑包包含 Operator 清单。
3
镜像中的该路径指向包含捆绑包元数据文件的目录。该标签保留给以后使用,当前默认为 metadata/metadata.v1 值表示这个捆绑包包含 Operator 元数据。
4
捆绑包的软件包名称。
5
捆绑包添加到 Operator Registry 时订阅的频道列表。
6
从 registry 安装时,Operator 应该订阅到的默认频道。
注意

如果出现不匹配的情况,则以 annotations.yaml 文件为准,因为依赖这些注解的集群 Operator Registry 只能访问此文件。

2.2.1.3. 依赖项

Operator 的依赖项列在捆绑包的 metadata/ 目录中的 dependencies.yaml 文件中。此文件是可选的,目前仅用于指明 Operator-version 依赖项。

依赖项列表中,每个项目包含一个 type 字段,用于指定这一依赖项的类型。支持以下 Operator 依赖项:

olm.package
这个类型表示特定 Operator 版本的依赖项。依赖项信息必须包含软件包名称以及软件包的版本,格式为 semver。例如,您可以指定具体版本,如 0.5.2,也可指定一系列版本,如 >0.5.1
olm.gvk
使用这个类型,作者可以使用 group/version/kind(GVK)信息指定依赖项,类似于 CSV 中现有 CRD 和基于 API 的使用量。该路径使 Operator 作者可以合并所有依赖项、API 或显式版本,使它们处于同一位置。
olm.constraint
这个类型在任意 Operator 属性上声明通用限制。

在以下示例中,为 Prometheus Operator 和 etcd CRD 指定依赖项:

dependencies.yaml 文件示例

dependencies:
  - type: olm.package
    value:
      packageName: prometheus
      version: ">0.27.0"
  - type: olm.gvk
    value:
      group: etcd.database.coreos.com
      kind: EtcdCluster
      version: v1beta2

2.2.1.4. 关于 opm CLI

opm CLI 工具由 Operator Framework 提供,用于 Operator 捆绑格式。您可以通过此工具从与软件存储库类似的 Operator 捆绑包列表中创建和维护 Operator 目录。其结果是一个容器镜像,它可以存储在容器的 registry 中,然后安装到集群中。

目录包含一个指向 Operator 清单内容的指针数据库,可通过在运行容器镜像时提供的已包含 API 进行查询。在 OpenShift Container Platform 中,Operator Lifecycle Manager (OLM) 可以引用由 CatalogSource 对象定义的目录源中的镜像,它会定期轮询镜像,以对集群上安装的 Operator 进行更新。

  • 有关安装 opm CLI 的步骤,请参阅 CLI 工具

2.2.2. 基于文件的目录

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

编辑

使用基于文件的目录,与目录内容交互的用户可以对格式进行直接更改,并验证其更改是否有效。由于这种格式是纯文本 JSON 或 YAML,因此目录维护人员可以通过手动或广泛支持的 JSON 或 YAML 工具(如 jq CLI)轻松操作目录元数据。

此可编辑功能启用以下功能和用户定义的扩展:

  • 将现有捆绑包提升到新频道
  • 更改软件包的默认频道
  • 用于添加、更新和删除升级边缘的自定义算法
Composability

基于文件的目录存储在任意目录层次结构中,从而启用目录组成。例如,考虑两个单独的基于文件的目录目录:catalogAcatalogB。目录维护人员可以通过生成新目录 catalogC 并将 catalogAcatalogB 复制到其中来创建新的组合目录。

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

注意

不允许软件包中重复软件包和重复捆绑包。如果找到任何重复项,opm validate 命令将返回错误。

因为 Operator 作者最熟悉其 Operator、其依赖项及其升级兼容性,所以他们可以维护自己的 Operator 目录并直接控制其内容。对于基于文件的目录,Operator 作者负责在目录中构建和维护其软件包的任务。但是,复合目录维护者仅拥有在其目录中管理软件包并将目录发布到用户的任务。

可扩展性

基于文件的目录规格是目录的一个低级别表示。虽然目录维护器可以直接以低级形式维护,但目录维护人员可以在其自己的自定义工具上构建有趣的扩展,以供其自身的自定义工具用于实现任意数量的变异。

例如,工具可以将一个高级 API (如(mode=semver)) 转换为升级边缘基于文件的低级别目录格式。或目录维护人员可能需要通过添加新属性到符合特定标准的捆绑包来自定义所有捆绑包元数据。

虽然这种可扩展性允许在低级别 API 上开发额外的官方工具,用于将来的 OpenShift Container Platform 版本,但目录维护人员也具有此功能。

重要

从 OpenShift Container Platform 4.11 开始,默认的红帽提供的 Operator 目录以基于文件的目录格式发布。通过以过时的 SQLite 数据库格式发布的 4.10,用于 OpenShift Container Platform 4.6 的默认红帽提供的 Operator 目录。

与 SQLite 数据库格式相关的 opm 子命令、标志和功能已被弃用,并将在以后的版本中删除。功能仍被支持,且必须用于使用已弃用的 SQLite 数据库格式的目录。

许多 opm 子命令和标志都用于 SQLite 数据库格式,如 opm index prune,它们无法使用基于文件的目录格式。有关使用基于文件的目录的更多信息,请参阅管理自定义目录以及使用 oc-mirror 插件为断开连接的安装 mirror 镜像

2.2.2.1. 目录结构

基于文件的目录可从基于目录的文件系统进行存储和加载。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

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

2.2.2.2. 模式

基于文件的目录使用基于 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.packageolm.channelolm.bundle),它们对应于 OLM 的现有软件包和捆绑包概念。

目录中的每个 Operator 软件包都需要一个 olm.package blob、至少一个 olm.channel blob 以及一个或多个 olm.bundle blob。

注意

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

2.2.2.2.1. olm.package schema

olm.package 模式为 Operator 定义软件包级别的元数据。这包括其名称、描述、默认频道和图标。

例 2.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
  }
}
2.2.2.2.2. olm.channel schema

olm.channel 模式在软件包中定义频道、属于频道成员的捆绑包条目,以及这些捆绑包的升级边缘。

捆绑包可作为条目包含在多个 olm.channel blob 中,但它每个频道只能有一个条目。

它对条目的 replaces 值有效,以引用无法在此目录或其他目录中找到的另一捆绑包名称。但是,所有其他频道变量都必须为 true,比如频道没有多个磁头。

例 2.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 属性的用户安装。

如果要为来自多个之前的版本的 Operator 版本直接(一个版本递增)更新,并保留以前版本的安装可供用户使用,请始终使用 skipRange 字段以及 replaces 字段。确保 replaces 字段指向相关的 Operator 版本前一个版本。

2.2.2.2.3. olm.bundle schema

例 2.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 & !=""
}

2.2.2.3. 属性

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

OLM 定义几个属性类型,再次使用保留的 olm.* 前缀。

2.2.2.3.1. olm.package 属性

olm.package 属性定义软件包名称和版本。这是捆绑包上的必要属性,必须正好有一个这些属性。packageName 字段必须与捆绑包的 first-class package 字段匹配,并且 version 字段必须是有效的语义版本。

例 2.4. olm.package 属性

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

olm.gvk 属性定义此捆绑包提供的 Kubernetes API 的 group/version/kind (GVK)。OLM 使用此属性解析捆绑包,作为列出与所需 API 相同的 GVK 的其他捆绑包的依赖项。GVK 必须遵循 Kubernetes GVK 验证。

例 2.5. olm.gvk 属性

#PropertyGVK: {
  type: "olm.gvk"
  value: {
    group: string & !=""
    version: string & !=""
    kind: string & !=""
  }
}
2.2.2.3.3. olm.package.required

olm.package.required 属性定义此捆绑包需要的另一软件包的软件包名称和版本范围。对于捆绑包列表的每个所需软件包属性,OLM 确保集群中为列出的软件包和所需版本范围安装了一个 Operator。versionRange 字段必须是有效的语义版本(模拟)范围。

例 2.6. olm.package.required 属性

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

olm.gvk.required 属性定义此捆绑包需要的 Kubernetes API 的 group/version/kind (GVK)。对于捆绑包列表的每个必需的 GVK 属性,OLM 确保集群中安装了提供它的 Operator。GVK 必须遵循 Kubernetes GVK 验证。

例 2.7. olm.gvk.required 属性

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

2.2.2.4. 目录示例

对于基于文件的目录,目录维护人员可以专注于 Operator 策展和兼容性。由于 Operator 作者已为其 Operator 创建了特定于 Operator 的目录,因此目录维护人员可以通过将每个 Operator 目录渲染到目录根目录的子目录来构建其目录。

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

  1. 为目录维护一个配置文件,其中包含目录中每个 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

  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 alpha generate dockerfile "$name"
    indexImage=$(yq eval '.repo + ":" + .tag' catalog.yaml)
    docker build -t "$indexImage" -f "$name.Dockerfile" .
    docker push "$indexImage"

2.2.2.5. 指南

在维护基于文件的目录时,请考虑以下准则。

2.2.2.5.1. 不可变捆绑包

Operator Lifecycle Manager (OLM) 的常规建议是捆绑包镜像及其元数据应视为不可变。

如果一个错误的捆绑包被推送到目录,您必须假设至少有一个用户已升级到该捆绑包。基于这种假设,您必须从损坏的捆绑包中发布另一个带有升级边缘的捆绑包,以确保安装了有问题的捆绑包的用户收到升级。如果目录中更新了该捆绑包的内容,OLM 将不会重新安装已安装的捆绑包。

然而,在某些情况下首选更改目录元数据:

  • 频道升级:如果您已发布了捆绑包,且之后决定将其添加到另一个频道,您可以在另一个 olm.channel blob 中添加捆绑包条目。
  • 新的升级边缘:如果您发布一个新的 1.2.z 捆绑包版本,如 1.2.4,但 1.3.0 已发布,您可以更新 1.3.0 的目录元数据以跳过 1.2.4
2.2.2.5.2. 源控制

目录元数据应存储在源控制中,并被视为事实来源。目录镜像的更新应包括以下步骤:

  1. 使用新的提交来更新源控制的目录目录。
  2. 构建并推送目录镜像。使用一致的标记分类,如 :latest:<target_cluster_version>,以便用户可以在目录可用时接收到更新。

2.2.2.6. CLI 用法

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

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

2.2.2.7. 自动化

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

  • 检查是否允许拉取请求 (PR) 作者进行请求的更改,例如更新其软件包的镜像引用。
  • 检查目录更新是否通过 opm validate 命令。
  • 检查是否有更新的捆绑包或目录镜像引用,目录镜像在集群中成功运行,来自该软件包的 Operator 可以成功安装。
  • 自动合并通过之前检查的 PR。
  • 自动重新构建和重新发布目录镜像。

2.2.3. RukPak (技术预览)

重要

RukPak 只是一个技术预览功能。技术预览功能不受红帽产品服务等级协议(SLA)支持,且功能可能并不完整。红帽不推荐在生产环境中使用它们。这些技术预览功能可以使用户提早试用新的功能,并有机会在开发阶段提供反馈意见。

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

OpenShift Container Platform 4.12 引入了 平台 Operator 类型作为技术预览功能。平台 Operator 机制依赖于 RukPak 组件,也包含在 OpenShift Container Platform 4.12 中,及其用于管理内容的资源。

RukPak 由一系列控制器组成,称为 provisioners,后者在 Kubernetes 集群上安装和管理内容。RukPak 还提供两个主要 API:BundleBundleDeployment。这些组件协同工作,将内容整合到集群中,并安装它,并在集群中生成资源。

置备程序会在 BundleBundleDeployment 资源上明确观察到引用置备程序的资源。对于给定捆绑包,置备程序会将 Bundle 资源的内容解压缩到集群中。然后,如果一个指向该捆绑包的 BundleDeployment 资源,置备程序会安装捆绑包内容,并负责管理这些资源的生命周期。

目前,两个置备程序被实施并捆绑到 RukPak:plain provisioner source 并解包 plain+v0 捆绑包; registry provisioner source Operator Lifecycle Manager (OLM) registry+v1 捆绑包。

2.2.3.1. 捆绑包(Bundle)

RukPak Bundle 对象代表可供集群中的其他使用者使用的内容。就像需要拉取和解包容器镜像的内容一样,pod 才能开始使用它们,使用 Bundle 对象来引用可能需要拉取和解包的内容。因此,捆绑包是镜像概念的规范化,可用于表示任何类型的内容。

捆绑包无法自行执行;它们需要置备程序来解包并在集群中提供其内容。它们可以解包到任何任意存储介质,如挂载到 provisioner pod 目录中的 tar.gz 文件。每个 Bundle 对象都有一个关联的 spec.provisionerClassName 字段,它指示 Provisioner 对象监视和解包该特定捆绑包类型。

配置为与普通置备程序一起使用的 Bundle 对象示例

apiVersion: core.rukpak.io/v1alpha1
kind: Bundle
metadata:
  name: my-bundle
spec:
  source:
    type: image
    image:
      ref: my-bundle@sha256:xyz123
  provisionerClassName: core-rukpak-io-plain

注意

捆绑包在创建后被视为不可变。

2.2.3.1.1. 捆绑包不可变

在 API 服务器接受 Bundle 对象后,捆绑包被视为 RukPak 系统的其余部分的不可变工件。这个行为强制捆绑包代表集群中要 source 的一些唯一静态内容。用户可以放心,特定捆绑包指向特定的清单集合,在没有创建新捆绑包的情况下无法更新。对于由嵌入式 BundleTemplate 对象创建的单机捆绑包和动态捆绑包,此属性为 true。

捆绑包的不可变性由核心 RukPak webhook 强制执行。此 webhook 监视 Bundle 对象事件,并对捆绑包的任何更新,检查现有捆绑包的 spec 字段是否与建议的捆绑包中的 spec 字段相同。如果它们不相等,则 Webhook 将拒绝更新。在捆绑包的生命周期中,其他 Bundle 对象字段(如 metadatastatus)会更新,它只是被视为不可变的 spec 字段。

应用 Bundle 对象,然后尝试更新其 spec 会失败。例如,以下示例会创建一个捆绑包:

$ oc apply -f -<<EOF
apiVersion: core.rukpak.io/v1alpha1
kind: Bundle
metadata:
  name: combo-tag-ref
spec:
  source:
    type: git
    git:
      ref:
        tag: v0.0.2
      repository: https://github.com/operator-framework/combo
  provisionerClassName: core-rukpak-io-plain
EOF

输出示例

bundle.core.rukpak.io/combo-tag-ref created

然后,修补捆绑包以指向较新的标签会返回错误:

$ oc patch bundle combo-tag-ref --type='merge' -p '{"spec":{"source":{"git":{"ref":{"tag":"v0.0.3"}}}}}'

输出示例

Error from server (bundle.spec is immutable): admission webhook "vbundles.core.rukpak.io" denied the request: bundle.spec is immutable

核心 RukPak 准入 Webhook 会拒绝补丁,因为捆绑包的 spec 是不可变的。推荐的修改捆绑包内容的方法是通过创建一个新的 Bundle 对象而不是原位更新。

进一步的不可变注意事项

虽然 Bundle 对象的 spec 字段不可变,但 BundleDeployment 对象仍有可能变为较新的捆绑包内容版本,而无需更改底层 spec 字段。这个非预期的行为可能会在以下情况中出现:

  1. 用户在 Bundle 对象的 spec.source 字段中设置镜像标签、Git 分支或 Git 标签。
  2. 镜像标签移到新的摘要、用户将更改推送到 Git 分支,或者用户删除并在不同的提交上重新推送 Git 标签。
  3. 用户执行一些操作,以便重新创建捆绑包解包 pod,如删除解包 pod。

如果发生这种情况,步骤 2 中的新内容会因为第 3 步而解包。捆绑包部署会检测更改,并探测到新版本的内容。

这与 pod 的行为类似,其中一个 pod 的容器镜像使用标签,标签将移到不同的摘要中,然后在将来将现有 pod 重新调度到其他节点上。此时,节点会将新镜像拉取到新摘要中,并在没有用户明确要求的情况下运行不同的镜像。

为了确定底层 Bundle spec 内容没有改变,请在创建捆绑包时使用基于摘要的镜像或 Git 提交引用。

2.2.3.1.2. 普通捆绑包规格

RukPak 中的普通捆绑包是给定目录中静态、任意的 Kubernetes YAML 清单的集合。

当前实施的普通捆绑包格式是 plain+v0 格式。捆绑包格式的名称 (plain+v0) 组合了捆绑包类型 (plain) 和当前模式版本 (v0)。

注意

plain+v0 捆绑包格式是 schema 版本 v0,这意味着它可能会在以后有所变化。

例如,下面显示了 plain+v0 捆绑包中的文件树。它必须具有一个 manifests/ 目录,其中包含部署应用程序所需的 Kubernetes 资源。

plain+v0 捆绑包文件树示例

manifests
├── namespace.yaml
├── cluster_role.yaml
├── role.yaml
├── serviceaccount.yaml
├── cluster_role_binding.yaml
├── role_binding.yaml
└── deployment.yaml

静态清单必须位于 manifests/ 目录中,其中至少包含一个资源,以便捆绑包是置备程序可以解包的有效 plain+v0 捆绑包。manifests/ 目录还必须是扁平的;所有清单都必须位于顶层,且无子目录。

重要

不要在不是静态清单的普通捆绑包的 manifests/ 目录中包含任何内容。否则,从该捆绑包创建内容时会出现错误。任何不能使用 oc apply 命令应用的文件将导致错误。多对象 YAML 或 JSON 文件也有效。

2.2.3.1.3. registry 捆绑包规格

registry 捆绑包或 registry+v1 捆绑包包含一组以旧 Operator Lifecycle Manager (OLM) 捆绑包格式组织的静态 Kubernetes YAML 清单。

2.2.3.2. BundleDeployment

警告

BundleDeployment 对象通过安装和删除对象来更改 Kubernetes 集群的状态。务必要验证并信任正在安装和限制访问权限的内容,方法是使用 RBAC 到 BundleDeployment API 到需要这些权限的用户。

RukPak BundleDeployment API 指向 Bundle 对象,并表明它应当处于活动状态。这包括从活跃捆绑包的旧版本获取。BundleDeployment 对象可能还包括所需捆绑包的嵌入式 spec。

与 pod 生成容器镜像实例一样,捆绑包部署会生成捆绑包部署的版本。捆绑包部署可被视为 pod 概念的一般化。

捆绑包部署如何根据引用的捆绑包对集群进行更改,具体由配置为监视该捆绑包部署的置备程序定义。

配置为与普通置备程序一起工作的 BundleDeployment 对象示例

apiVersion: core.rukpak.io/v1alpha1
kind: BundleDeployment
metadata:
  name: my-bundle-deployment
spec:
  provisionerClassName: core-rukpak-io-plain
  template:
    metadata:
      labels:
        app: my-bundle
    spec:
      source:
        type: image
        image:
          ref: my-bundle@sha256:xyz123
      provisionerClassName: core-rukpak-io-plain

2.2.3.3. Provisioner

RukPak 置备程序是一个控制器,它了解 BundleDeploymentBundle API,可以采取行动。每个置备程序都会被分配一个唯一 ID,它负责协调与该特定 ID匹配的 spec.provisionerClassName 字段的 BundleBundleDeployment 对象。

例如,普通置备程序可以解包给定 plain+v0 捆绑包到集群中,然后实例化它,使捆绑包的内容在集群中可用。

Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.