--- title: 使用存储版本迁移功能来迁移 Kubernetes 对象 content_type: task min-kubernetes-server-version: v1.30 weight: 60 --- {{< feature-state feature_gate_name="StorageVersionMigrator" >}} Kubernetes 依赖主动重写的 API 数据来支持与静态存储相关的一些维护活动。 两个著名的例子是已存储资源的版本化模式(即针对给定资源的首选存储模式从 v1 更改为 v2) 和静态加密(即基于数据加密方式的变化来重写过时的数据)。 ## {{% heading "prerequisites" %}} 安装 [`kubectl`](/zh-cn/docs/tasks/tools/#kubectl)。 {{< include "task-tutorial-prereqs.md" >}} {{< version-check >}} 确保你的集群启用了 `StorageVersionMigrator` 和 `InformerResourceVersion` [特性门控](/zh-cn/docs/reference/command-line-tools-reference/feature-gates/)。 你需要有控制平面管理员权限才能执行此项变更。 在 API 服务器上将运行时配置 `storagemigration.k8s.io/v1alpha1` 设为 `true`,启用存储版本迁移 REST API。 有关如何执行此操作的更多信息,请阅读[启用或禁用 Kubernetes API](/zh-cn/docs/tasks/administer-cluster/enable-disable-api/)。 ## 使用存储版本迁移来重新加密 Kubernetes Secret {#reencrypt-kubernetes-secrets-using-storage-version-migration} - 首先[配置 KMS 驱动](/zh-cn/docs/tasks/administer-cluster/kms-provider/), 以便使用如下加密配置来加密 etcd 中的静态数据。 ```yaml 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。 ```shell kubectl create secret generic my-secret --from-literal=key1=supersecret ``` - [验证](/zh-cn/docs/tasks/administer-cluster/kms-provider/#verifying-that-the-data-is-encrypted)该 Secret 对象的序列化数据带有前缀 `k8s:enc:aescbc:v1:key1`。 - 按照以下方式更新加密配置文件,以轮换加密密钥。 ```yaml 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 清单: ```yaml kind: StorageVersionMigration apiVersion: storagemigration.k8s.io/v1alpha1 metadata: name: secrets-migration spec: resource: group: "" version: v1 resource: secrets ``` 使用以下 _kubectl_ 命令创建对象: ```shell kubectl apply -f migrate-secret.yaml ``` - 通过检查 StorageVersionMigration 的 `.status` 来监控 Secret 的迁移。 成功的迁移应将其 `Succeeded` 状况设置为 true。 获取 StorageVersionMigration 对象的方式如下: ```shell kubectl get storageversionmigration.storagemigration.k8s.io/secrets-migration -o yaml ``` 输出类似于: ```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" ``` - [验证](/zh-cn/docs/tasks/administer-cluster/kms-provider/#verifying-that-the-data-is-encrypted)存储的 Secret 现在带有前缀 `k8s:enc:aescbc:v1:key2`。 ## 更新 CRD 的首选存储模式 {#update-the-preferred-storage-schema-of-a-crd} 考虑这样一种情况: 用户创建了 {{< glossary_tooltip term_id="CustomResourceDefinition" text="CustomResourceDefinition" >}} (CRD) 来提供自定义资源 (CR),并将其设置为首选的存储模式。 当需要引入 CRD 的 v2 版本时,只需提供转换 Webhook 就可以为 v2 版本提供服务。 基于转换 Webhook 的方式能够实现更平滑的过渡,用户可以使用 v1 或 v2 模式创建 CR,并通过合适的 Webhook 执行必要的模式转换。 在将 v2 设置为首选的存储模式版本之前,重要的是要确保将当前已存储为 v1 的所有 CR 已被迁移到 v2。 这种迁移可以通过使用**存储版本迁移**将所有 CR 从 v1 迁移到 v2 来达成。 - 如下针对名为 `test-crd.yaml` 的 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: conversionReviewVersions: - v1 - v2 ``` 使用 kubectl 创建 CRD: ```shell kubectl apply -f test-crd.yaml ``` - 为 testcrd 示例创建一个清单。命名为 `cr1.yaml` 并使用以下内容: ```yaml apiVersion: stable.example.com/v1 kind: SelfieRequest metadata: name: cr1 namespace: default ``` 使用 kubectl 创建 CR: ```shell kubectl apply -f cr1.yaml ``` - 通过从 etcd 获取对象来验证 CR 是否以 v1 格式被写入和存储。 ```shell ETCDCTL_API=3 etcdctl get /kubernetes.io/stable.example.com/testcrds/default/cr1 [...] | hexdump -C ``` 其中 `[...]` 包含连接到 etcd 服务器的额外参数。 - 如下更新 CRD `test-crd.yaml`,将 v2 版本设置为 served 和 storage,并将 v1 设置为仅 served: ```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: 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: conversionReviewVersions: - v1 - v2 ``` 使用 kubectl 更新 CRD: ```shell kubectl apply -f test-crd.yaml ``` - 如下创建名为 `cr2.yaml` 的 CR 资源文件: ```yaml apiVersion: stable.example.com/v2 kind: SelfieRequest metadata: name: cr2 namespace: default ``` - 使用 kubectl 创建 CR: ```shell kubectl apply -f cr2.yaml ``` - 通过从 etcd 获取对象来验证 CR 是否以 v2 格式被写入和存储。 ```shell ETCDCTL_API=3 etcdctl get /kubernetes.io/stable.example.com/testcrds/default/cr2 [...] | hexdump -C ``` 其中 `[...]` 包含连接到 etcd 服务器的额外参数。 - 如下创建名为 `migrate-crd.yaml` 的 StorageVersionMigration 清单: ```yaml kind: StorageVersionMigration apiVersion: storagemigration.k8s.io/v1alpha1 metadata: name: crdsvm spec: resource: group: stable.example.com version: v1 resource: SelfieRequest ``` 使用如下 _kubectl_ 命令创建此对象: ```shell kubectl apply -f migrate-crd.yaml ``` - 使用 status 监控 Secret 的迁移。 若迁移成功,应在 status 字段中将 `Succeeded` 状况设置为 "True"。 获取迁移资源的方式如下: ```shell kubectl get storageversionmigration.storagemigration.k8s.io/crdsvm -o yaml ``` 输出类似于: ```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 格式被写入和存储。 ```shell ETCDCTL_API=3 etcdctl get /kubernetes.io/stable.example.com/testcrds/default/cr1 [...] | hexdump -C ``` 其中 `[...]` 包含连接到 etcd 服务器的额外参数。