etcd
├── manifests
│ ├── etcdcluster.crd.yaml
│ └── etcdoperator.clusterserviceversion.yaml
│ └── secret.yaml
│ └── configmap.yaml
└── metadata
└── annotations.yaml
└── dependencies.yaml
运算符的Bundle 格式是由运算符框架引入的一种打包格式。为了提高可扩展性并更好地支持上游用户托管自己的目录,Bundle 格式规范简化了运算符元数据的分发。
一个运算符 Bundle 代表运算符的单个版本。磁盘上的Bundle 清单文件被容器化并作为Bundle 镜像交付,这是一个不可运行的容器镜像,用于存储 Kubernetes 清单文件和运算符元数据。然后,使用现有的容器工具(如podman
和docker
)和容器注册表(如 Quay)来管理 Bundle 镜像的存储和分发。
运算符元数据可以包括:
标识运算符的信息,例如其名称和版本。
驱动 UI 的附加信息,例如其图标和一些示例自定义资源 (CR)。
所需的和提供的 API。
相关的镜像。
将清单文件加载到运算符注册表数据库时,将验证以下要求:
Bundle 必须在注释中至少定义一个通道。
每个 Bundle 只有一个集群服务版本 (CSV)。
如果 CSV 拥有自定义资源定义 (CRD),则该 CRD 必须存在于 Bundle 中。
Bundle 清单文件指的是一组 Kubernetes 清单文件,这些文件定义了运算符的部署和 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 中时,运算符生命周期管理器 (OLM) 可以从 Bundle 中创建它们,并与 CSV 一起管理它们的生存周期。
删除 CSV 时,OLM 会删除可选对象。
升级 CSV 时:
如果可选对象的名称相同,OLM 会就地更新它。
如果可选对象的名称在不同版本之间发生了变化,OLM 会删除并重新创建它。
包还包含其/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 注册表时,包订阅的通道列表。 |
6 | 从注册表安装时,Operator 应订阅的默认通道。 |
如果出现不匹配, |
Operator 的依赖项列在包的metadata/
文件夹中的dependencies.yaml
文件中。此文件是可选的,目前仅用于指定显式的 Operator 版本依赖项。
依赖项列表为每个项目包含一个type
字段,用于指定这是什么类型的依赖项。支持以下类型的 Operator 依赖项:
olm.package
此类型表示特定 Operator 版本的依赖项。依赖信息必须包含包名和包的语义版本号格式的版本。例如,您可以指定确切的版本,例如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
Operator Framework 提供了opm
CLI 工具,用于 Operator 包格式。此工具允许您根据类似于软件存储库的 Operator 包列表创建和维护 Operator 目录。结果是一个容器镜像,可以存储在容器注册表中,然后安装到集群上。
目录包含指向 Operator 清单内容的指针数据库,可以通过运行容器镜像时提供的包含的 API 进行查询。在 OpenShift Dedicated 中,Operator 生命周期管理器 (OLM) 可以引用目录源中的镜像(由CatalogSource
对象定义),该对象定期轮询镜像以启用对集群上已安装的 Operator 的频繁更新。
有关安装opm
CLI 的步骤,请参见CLI 工具。
基于文件的目录是 Operator 生命周期管理器 (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 Dedicated 版本开发额外的官方工具,但其主要好处在于目录维护者也具备此能力。
从 OpenShift Dedicated 4.11 开始,默认的 Red Hat 提供的 Operator 目录使用基于文件的目录格式发布。OpenShift Dedicated 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 & !=""
}
使用 您可以通过同时使用 |
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
模式定义了目录中包、捆绑包和通道的弃用信息。Operator 作者可以使用此模式向从目录运行这些 Operator 的用户提供有关其 Operator 的相关消息,例如支持状态和推荐的升级路径。
定义此模式后,OpenShift Dedicated Web 控制台会在 Operator 的受影响元素(包括任何自定义弃用消息)上显示警告徽章,这些徽章位于 OperatorHub 的安装前和安装后页面上。
olm.deprecations
模式条目包含以下一个或多个 reference
类型,这表示弃用范围。安装 Operator 后,任何指定的邮件都可以作为相关 Subscription
对象上的状态条件查看。
类型 | 范围 | 状态条件 |
---|---|---|
|
表示整个包 |
|
|
表示一个通道 |
|
|
表示一个捆绑包版本 |
|
每个 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 字段都必须是非零长度的,并表示为不透明文本 Blob。 |
4 | olm.channel 模式的 name 字段是必需的。 |
5 | olm.bundle 模式的 name 字段是必需的。 |
弃用功能不考虑重叠弃用,例如包与通道与捆绑包。 |
Operator 作者可以将 olm.deprecations
模式条目保存为 deprecations.yaml
文件,该文件与包的 index.yaml
文件位于同一目录中。
my-catalog
└── my-operator
├── index.yaml
└── deprecations.yaml
属性是可以附加到基于文件的目录模式的任意元数据片段。type
字段是一个字符串,有效地指定了 value
字段的语义和语法含义。该值可以是任何任意 JSON 或 YAML。
OLM 定义了一些属性类型,再次使用保留的 olm.*
前缀。
olm.package
属性定义了包名称和版本。这是捆绑包上的必需属性,并且必须只有一个此类属性。packageName
字段必须与捆绑包的一级 package
字段匹配,version
字段必须是有效的语义版本。
olm.package
属性#PropertyPackage: {
type: "olm.package"
value: {
packageName: string & !=""
version: string & !=""
}
}
olm.gvk
属性定义了此捆绑包提供的 Kubernetes API 的组/版本/种类 (GVK)。OLM 使用此属性来解析具有此属性的捆绑包作为其他捆绑包的依赖项,这些捆绑包将相同的 GVK 列为必需的 API。GVK 必须符合 Kubernetes GVK 验证。
olm.gvk
属性#PropertyGVK: {
type: "olm.gvk"
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 生命周期管理器 (OLM) 的一般建议是,捆绑包镜像及其元数据应视为不可变的。
如果已将损坏的捆绑包推送到目录,则必须假设至少有一个用户已升级到该捆绑包。基于此假设,必须发布另一个捆绑包,其中包含从损坏的捆绑包升级的边缘,以确保安装了损坏的捆绑包的用户能够收到升级。如果目录中捆绑包的内容已更新,OLM 将不会重新安装已安装的捆绑包。
但是,在某些情况下,更改目录元数据是更好的选择。
频道升级:如果已发布捆绑包,后来决定将其添加到另一个频道,则可以在另一个olm.channel
blob 中添加捆绑包的条目。
新的升级边缘:例如,如果发布了新的1.2.z
捆绑包版本,例如1.2.4
,但1.3.0
已经发布,则可以更新1.3.0
的目录元数据以跳过1.2.4
。