etcd
├── manifests
│ ├── etcdcluster.crd.yaml
│ └── etcdoperator.clusterserviceversion.yaml
│ └── secret.yaml
│ └── configmap.yaml
└── metadata
└── annotations.yaml
└── dependencies.yaml
Operator 的Bundle 格式是由 Operator Framework 引入的一种打包格式。为了提高可扩展性并更好地支持上游用户托管自己的目录,Bundle 格式规范简化了 Operator 元数据的分发。
一个 Operator Bundle 代表 Operator 的单个版本。磁盘上的Bundle 清单文件被容器化并作为Bundle 镜像交付,这是一种不可运行的容器镜像,用于存储 Kubernetes 清单文件和 Operator 元数据。然后,使用现有的容器工具(如podman
和docker
)和容器注册表(如 Quay)来管理 Bundle 镜像的存储和分发。
Operator 元数据可以包含:
标识 Operator 的信息,例如其名称和版本。
驱动 UI 的附加信息,例如其图标和一些示例自定义资源 (CR)。
必需和提供的 API。
相关的镜像。
将清单文件加载到 Operator 注册表数据库时,将验证以下要求:
Bundle 必须在注解中至少定义一个通道。
每个 Bundle 只有一个集群服务版本 (CSV)。
如果 CSV 拥有自定义资源定义 (CRD),则该 CRD 必须存在于 Bundle 中。
Bundle 清单文件指的是一组 Kubernetes 清单文件,这些文件定义了 Operator 的部署和 RBAC 模型。
一个 Bundle 在每个目录中包含一个 CSV,并且通常在其/manifests
目录中包含定义 CSV 所拥有 API 的 CRD。
etcd
├── manifests
│ ├── etcdcluster.crd.yaml
│ └── etcdoperator.clusterserviceversion.yaml
│ └── secret.yaml
│ └── configmap.yaml
└── metadata
└── annotations.yaml
└── dependencies.yaml
以下对象类型也可以选择包含在 Bundle 的/manifests
目录中:
ClusterRole
ClusterRoleBinding
ConfigMap
ConsoleCLIDownload
ConsoleLink
ConsoleQuickStart
ConsoleYamlSample
PodDisruptionBudget
PriorityClass
PrometheusRule
Role
RoleBinding
Secret
Service
ServiceAccount
ServiceMonitor
VerticalPodAutoscaler
当这些可选对象包含在 Bundle 中时,Operator Lifecycle Manager (OLM) 可以从 Bundle 中创建它们,并与 CSV 一起管理它们的生存周期。
删除 CSV 时,OLM 会删除可选对象。
升级 CSV 时:
如果可选对象的名称相同,OLM 会就地更新它。
如果可选对象的名称在不同版本之间发生了更改,OLM 会删除并重新创建它。
Bundle 还包含其/metadata
目录中的annotations.yaml
文件。此文件定义更高级别的聚合数据,有助于描述 Bundle 的格式和包信息,以及如何将 Bundle 添加到 Bundle 索引中。
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 Bundle 的媒体类型或格式。registry+v1 格式表示它包含 CSV 及其关联的 Kubernetes 对象。 |
2 | 镜像中包含 Operator 清单文件的目录的路径。此标签保留供将来使用,目前默认为manifests/ 。值manifests.v1 暗示 Bundle 包含 Operator 清单文件。 |
3 | 镜像中包含有关 Bundle 的元数据文件的目录的路径。此标签保留供将来使用,目前默认为metadata/ 。值metadata.v1 暗示此 Bundle 具有 Operator 元数据。 |
4 | Bundle 的包名。 |
5 | 添加到 Operator 注册表时,Bundle 订阅的通道列表。 |
6 | 从注册表安装时,Operator 应订阅的默认通道。 |
如果出现不匹配, |
Operator 的依赖项列在 Bundle 的metadata/
文件夹中的dependencies.yaml
文件中。此文件是可选的,目前仅用于指定显式 Operator 版本依赖项。
依赖项列表为每个项目包含一个type
字段,以指定这是什么类型的依赖项。支持以下类型的 Operator 依赖项:
olm.package
此类型指示特定 Operator 版本的依赖项。依赖项信息必须包含包名和包的semver格式版本。例如,您可以指定确切的版本,例如0.5.2
,或指定版本的范围,例如>0.5.1
。
olm.gvk
使用此类型,作者可以指定具有组/版本/种类 (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
opm
CLI 工具由 Operator Framework 提供,用于 Operator 包格式。此工具允许您从类似于软件存储库的 Operator 包列表创建和维护 Operator 目录。最终结果是一个容器镜像,可以存储在容器注册表中,然后安装到集群上。
目录包含指向 Operator 清单内容的指针数据库,可以通过运行容器镜像时提供的 API 进行查询。在 OpenShift Container Platform 上,Operator Lifecycle Manager (OLM) 可以引用目录源中的镜像(由CatalogSource
对象定义),该对象定期轮询镜像,以便频繁更新集群上已安装的 Operator。
有关安装opm
CLI 的步骤,请参见CLI 工具。
基于文件的目录是 Operator Lifecycle Manager (OLM) 中目录格式的最新迭代。它是早期 SQLite 数据库格式的基于纯文本(JSON 或 YAML)的声明式配置演变,并且完全向后兼容。此格式的目标是启用 Operator 目录编辑、组合和可扩展性。
使用基于文件的目录,与目录内容交互的用户能够直接更改格式并验证其更改是否有效。因为此格式是纯文本 JSON 或 YAML,所以目录维护者可以轻松地手动或使用广泛已知和支持的 JSON 或 YAML 工具(例如jq
CLI)来操作目录元数据。
这种可编辑性支持以下功能和用户定义的扩展
将现有包提升到新通道
更改包的默认通道
用于添加、更新和删除升级边的自定义算法
基于文件的目录存储在任意目录层次结构中,这使得目录组合成为可能。例如,考虑两个单独的基于文件的目录:catalogA
和 catalogB
。目录维护者可以通过创建一个新的目录catalogC
并将catalogA
和catalogB
复制到其中来创建一个新的组合目录。
这种组合性支持去中心化目录。此格式允许 Operator 作者维护特定于 Operator 的目录,并且允许维护者轻松构建由各个 Operator 目录组成的目录。可以通过组合多个其他目录、提取一个目录的子集或同时使用这两种方法来组合基于文件的目录。
不允许重复的包和包内的重复包。如果发现任何重复项, |
由于 Operator 作者最熟悉他们的 Operator、其依赖项及其升级兼容性,因此他们能够维护他们自己的 Operator 特定目录并直接控制其内容。使用基于文件的目录,Operator 作者负责在目录中构建和维护他们的包。但是,组合目录维护者只负责管理其目录中的包并将目录发布给用户。
基于文件的目录规范是目录的低级表示。虽然可以直接以其低级形式维护它,但目录维护者可以在其之上构建有趣的扩展,这些扩展可以被他们自己的自定义工具用于进行任意数量的更改。
例如,一个工具可以将高级 API(例如(mode=semver)
)转换为低级基于文件的目录格式以进行升级边。或者,目录维护者可能需要通过向符合特定条件的包添加新属性来自定义所有包元数据。
虽然这种可扩展性允许在低级 API 之上开发用于未来 OpenShift Container Platform 版本的其他官方工具,但主要好处是目录维护者也具有此功能。
从 OpenShift Container Platform 4.11 开始,默认的 Red Hat 提供的 Operator 目录以基于文件的目录格式发布。OpenShift Container Platform 4.6 到 4.10 的默认 Red Hat 提供的 Operator 目录以已弃用的 SQLite 数据库格式发布。 与 SQLite 数据库格式相关的 许多用于处理 SQLite 数据库格式的 |
基于文件的目录可以存储和加载自基于目录的文件系统。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 模式不应被认为是详尽无遗的。 |
Operator Lifecycle Manager (OLM) 目录当前使用三个模式(olm.package
、olm.channel
和olm.bundle
),它们对应于 OLM 现有的包和包的概念。
目录中的每个 Operator 包都需要一个olm.package
blob,至少一个olm.channel
blob 和一个或多个olm.bundle
blob。
所有 |
olm.package
模式定义了 Operator 的包级元数据。这包括其名称、描述、默认通道和图标。
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
blob 中表示一条边,则它每个通道只能出现一次。
条目的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` 和 `replaces` 字段增量更新 Operator,同时保留以前安装的版本供用户将来安装。请确保 `replaces` 字段指向该 Operator 版本的直接前一个版本。 |
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` 模式定义了目录中包、bundle 和 channel 的弃用信息。Operator 作者可以使用此模式向从目录运行这些 Operator 的用户提供有关其 Operator 的相关消息,例如支持状态和推荐的升级路径。
定义此模式后,OpenShift Container Platform Web 控制台会在 Operator 的受影响元素(包括任何自定义弃用消息)的 OperatorHub 预安装和安装后页面上显示警告徽章。
`olm.deprecations` 模式条目包含一个或多个以下 `reference` 类型,这指示弃用范围。安装 Operator 后,任何指定的都可以作为相关 `Subscription` 对象上的状态条件查看。
类型 | 范围 | 状态条件 |
---|---|---|
|
代表整个包 |
|
|
代表一个 channel |
|
|
代表一个 bundle 版本 |
|
每个 `reference` 类型都有其自身的要求,详见以下示例。
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` 字段是必需的。 |
弃用功能不考虑重叠弃用,例如包与 channel 与 bundle 之间的重叠。 |
Operator 作者可以将 `olm.deprecations` 模式条目保存为 `deprecations.yaml` 文件,该文件与包的 `index.yaml` 文件位于同一目录中。
my-catalog
└── my-operator
├── index.yaml
└── deprecations.yaml
属性是可以附加到基于文件的目录模式的任意元数据片段。`type` 字段是一个字符串,有效地指定了 `value` 字段的语义和句法含义。值可以是任何任意 JSON 或 YAML。
OLM 定义了一些属性类型,同样使用保留的 `olm.*` 前缀。
`olm.package` 属性定义了包名称和版本。这是 bundle 的必需属性,并且必须只有一个此类属性。`packageName` 字段必须与 bundle 的第一类 `package` 字段匹配,`version` 字段必须是有效的语义版本。
olm.package
属性#PropertyPackage: {
type: "olm.package"
value: {
packageName: string & !=""
version: string & !=""
}
}
`olm.gvk` 属性定义了此 bundle 提供的 Kubernetes API 的组/版本/种类 (GVK)。OLM 使用此属性来解析具有此属性的 bundle,作为列出相同 GVK 作为所需 API 的其他 bundle 的依赖项。GVK 必须符合 Kubernetes GVK 验证。
olm.gvk
属性#PropertyGVK: {
type: "olm.gvk"
value: {
group: string & !=""
version: string & !=""
kind: string & !=""
}
}
`olm.package.required` 属性定义了此 bundle 需要的另一个包的包名称和版本范围。对于 bundle 列出的每个所需包属性,OLM 都会确保集群上安装了列出的包的 Operator,并且版本在所需范围内。`versionRange` 字段必须是有效的语义版本 (semver) 范围。
olm.package.required
属性#PropertyPackageRequired: {
type: "olm.package.required"
value: {
packageName: string & !=""
versionRange: string & !=""
}
}
`olm.gvk.required` 属性定义了此 bundle 需要的 Kubernetes API 的组/版本/种类 (GVK)。对于 bundle 列出的每个所需 GVK 属性,OLM 都会确保集群上安装了提供它的 Operator。GVK 必须符合 Kubernetes GVK 验证。
olm.gvk.required
属性#PropertyGVKRequired: {
type: "olm.gvk.required"
value: {
group: string & !=""
version: string & !=""
kind: string & !=""
}
}
使用基于文件的目录,目录维护者可以专注于 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"
维护基于文件的目录时,请考虑以下指导原则。
Operator Lifecycle Manager (OLM) 的一般建议是 bundle 镜像及其元数据应视为不可变的。
如果已将损坏的 bundle 推送到目录,则必须假设至少有一个用户已升级到该 bundle。基于此假设,必须发布另一个 bundle,其中包含来自损坏 bundle 的升级边缘,以确保安装了损坏 bundle 的用户收到升级。如果目录中的 bundle 内容已更新,OLM 不会重新安装已安装的 bundle。
但是,在某些情况下,更改目录元数据是更好的选择。
Channel 升级:如果已发布 bundle,稍后决定将其添加到另一个 channel,则可以在另一个 `olm.channel` 块中添加 bundle 的条目。
新的升级边缘:例如,如果发布了新的 `1.2.z` bundle 版本 `1.2.4`,但 `1.3.0` 已经发布,则可以更新 `1.3.0` 的目录元数据以跳过 `1.2.4`。