使用存储版本迁移 Kubernetes 对象
Kubernetes v1.30 [alpha]
(默认启用:false)Kubernetes 依赖于主动重写 API 数据,以支持一些与静态存储相关的维护活动。两个显著的例子是存储资源的版本化模式(即,给定资源的首选存储模式从 v1 变为 v2)和静态加密(即,根据数据应如何加密的更改重写旧数据)。
准备工作
安装 kubectl
。
你需要有一个 Kubernetes 集群,并且 kubectl 命令行工具必须配置为与你的集群通信。建议在至少有两个不作为控制平面主机的节点的集群上运行本教程。如果你还没有集群,可以使用 minikube 创建一个,或者使用以下 Kubernetes 演练场之一
你的 Kubernetes 服务器版本必须是 v1.30 或更高版本。要检查版本,请输入 kubectl version
。
确保你的集群已启用 StorageVersionMigrator
和 InformerResourceVersion
特性门控。你需要控制平面管理员权限才能进行此更改。
通过将 API 服务器的运行时配置 storagemigration.k8s.io/v1alpha1
设置为 true
来启用存储版本迁移 REST API。有关如何执行此操作的更多信息,请阅读 启用或禁用 Kubernetes API。
使用存储版本迁移重新加密 Kubernetes Secret
首先,配置 KMS 提供商,使用以下加密配置加密 etcd 中的静态数据。
kind: EncryptionConfiguration apiVersion: apiserver.config.k8s.io/v1 resources: - resources: - secrets providers: - aescbc: keys: - name: key1 secret: c2VjcmV0IGlzIHNlY3VyZQ==
请务必将
--encryption-provider-config-automatic-reload
设置为 true,以启用加密配置文件自动重新加载。使用 kubectl 创建一个 Secret。
kubectl create secret generic my-secret --from-literal=key1=supersecret
验证该 Secret 对象的序列化数据是否以
k8s:enc:aescbc:v1:key1
为前缀。更新加密配置文件以轮换加密密钥,如下所示。
kind: EncryptionConfiguration apiVersion: apiserver.config.k8s.io/v1 resources: - resources: - secrets providers: - aescbc: keys: - name: key2 secret: c2VjcmV0IGlzIHNlY3VyZSwgaXMgaXQ/ - aescbc: keys: - name: key1 secret: c2VjcmV0IGlzIHNlY3VyZQ==
为了确保之前创建的 Secret
my-secret
使用新密钥key2
重新加密,你将使用 **存储版本迁移**。创建一个名为
migrate-secret.yaml
的 StorageVersionMigration 清单,内容如下kind: StorageVersionMigration apiVersion: storagemigration.k8s.io/v1alpha1 metadata: name: secrets-migration spec: resource: group: "" version: v1 resource: secrets
使用 **kubectl** 创建对象,如下所示
kubectl apply -f migrate-secret.yaml
通过检查 StorageVersionMigration 的
.status
来监控 Secret 的迁移。成功的迁移应将其Succeeded
条件设置为 true。获取 StorageVersionMigration 对象,如下所示kubectl get storageversionmigration.storagemigration.k8s.io/secrets-migration -o yaml
输出类似于:
kind: StorageVersionMigration apiVersion: storagemigration.k8s.io/v1alpha1 metadata: name: secrets-migration uid: 628f6922-a9cb-4514-b076-12d3c178967c resourceVersion: "90" creationTimestamp: "2024-03-12T20:29:45Z" spec: resource: group: "" version: v1 resource: secrets status: conditions: - type: Running status: "False" lastUpdateTime: "2024-03-12T20:29:46Z" reason: StorageVersionMigrationInProgress - type: Succeeded status: "True" lastUpdateTime: "2024-03-12T20:29:46Z" reason: StorageVersionMigrationSucceeded resourceVersion: "84"
验证存储的 Secret 现在是否以
k8s:enc:aescbc:v1:key2
为前缀。
更新 CRD 的首选存储模式
考虑这样一种场景:创建了一个 CustomResourceDefinition (CRD) 来提供自定义资源 (CR),并将其设置为首选存储模式。当需要引入 CRD 的 v2 版本时,可以仅通过转换 Webhook 添加它以供服务。这使得过渡更加顺畅,用户可以使用 v1 或 v2 模式创建 CR,并通过 Webhook 在它们之间执行必要的模式转换。在将 v2 设置为首选存储模式版本之前,重要的是要确保所有存储为 v1 的现有 CR 都已迁移到 v2。这种迁移可以通过 **存储版本迁移** 来实现,将所有 CR 从 v1 迁移到 v2。
为 CRD 创建一个名为
test-crd.yaml
的清单,内容如下apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: selfierequests.stable.example.com spec: group: stable.example.com names: plural: SelfieRequests singular: SelfieRequest kind: SelfieRequest listKind: SelfieRequestList scope: Namespaced versions: - name: v1 served: true storage: true schema: openAPIV3Schema: type: object properties: hostPort: type: string conversion: strategy: Webhook webhook: clientConfig: url: "https://127.0.0.1:9443/crdconvert" caBundle: <CABundle info> conversionReviewVersions: - v1 - v2
使用 kubectl 创建 CRD
kubectl apply -f test-crd.yaml
为示例 testcrd 创建一个清单。将清单命名为
cr1.yaml
并使用以下内容apiVersion: stable.example.com/v1 kind: SelfieRequest metadata: name: cr1 namespace: default
使用 kubectl 创建 CR
kubectl apply -f cr1.yaml
通过从 etcd 获取对象来验证 CR 是否以 v1 写入和存储。
ETCDCTL_API=3 etcdctl get /kubernetes.io/stable.example.com/testcrds/default/cr1 [...] | hexdump -C
其中
[...]
包含连接到 etcd 服务器的附加参数。更新 CRD
test-crd.yaml
以包含 v2 版本用于服务和存储,以及 v1 仅用于服务,如下所示apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: selfierequests.stable.example.com spec: group: stable.example.com names: plural: SelfieRequests singular: SelfieRequest kind: SelfieRequest listKind: SelfieRequestList scope: Namespaced versions: - name: v2 served: true storage: true schema: openAPIV3Schema: type: object properties: host: type: string port: type: string - name: v1 served: true storage: false schema: openAPIV3Schema: type: object properties: hostPort: type: string conversion: strategy: Webhook webhook: clientConfig: url: "https://127.0.0.1:9443/crdconvert" caBundle: <CABundle info> conversionReviewVersions: - v1 - v2
使用 kubectl 更新 CRD
kubectl apply -f test-crd.yaml
创建名为
cr2.yaml
的 CR 资源文件,内容如下apiVersion: stable.example.com/v2 kind: SelfieRequest metadata: name: cr2 namespace: default
使用 kubectl 创建 CR
kubectl apply -f cr2.yaml
通过从 etcd 获取对象来验证 CR 是否以 v2 写入和存储。
ETCDCTL_API=3 etcdctl get /kubernetes.io/stable.example.com/testcrds/default/cr2 [...] | hexdump -C
其中
[...]
包含连接到 etcd 服务器的附加参数。创建一个名为
migrate-crd.yaml
的 StorageVersionMigration 清单,内容如下kind: StorageVersionMigration apiVersion: storagemigration.k8s.io/v1alpha1 metadata: name: crdsvm spec: resource: group: stable.example.com version: v1 resource: SelfieRequest
使用 **kubectl** 创建对象,如下所示
kubectl apply -f migrate-crd.yaml
使用状态监控 Secret 的迁移。成功的迁移应在状态字段中将
Succeeded
条件设置为 "True"。获取迁移资源,如下所示kubectl get storageversionmigration.storagemigration.k8s.io/crdsvm -o yaml
输出类似于:
kind: StorageVersionMigration apiVersion: storagemigration.k8s.io/v1alpha1 metadata: name: crdsvm uid: 13062fe4-32d7-47cc-9528-5067fa0c6ac8 resourceVersion: "111" creationTimestamp: "2024-03-12T22:40:01Z" spec: resource: group: stable.example.com version: v1 resource: testcrds status: conditions: - type: Running status: "False" lastUpdateTime: "2024-03-12T22:40:03Z" reason: StorageVersionMigrationInProgress - type: Succeeded status: "True" lastUpdateTime: "2024-03-12T22:40:03Z" reason: StorageVersionMigrationSucceeded resourceVersion: "106"
通过从 etcd 获取对象来验证之前创建的 cr1 现在是否以 v2 写入和存储。
ETCDCTL_API=3 etcdctl get /kubernetes.io/stable.example.com/testcrds/default/cr1 [...] | hexdump -C
其中
[...]
包含连接到 etcd 服务器的附加参数。