使用存储版本迁移功能来迁移 Kubernetes 对象

特性状态: Kubernetes v1.35 (Beta; (默认禁用))
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the StorageVersionMigrator feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Kubernetes 依赖主动重写的 API 数据来支持与静态存储相关的一些维护活动。 两个著名的例子是已存储资源的版本化模式(即针对给定资源的首选存储模式从 v1 更改为 v2) 和静态加密(即基于数据加密方式的变化来重写过时的数据)。

运行存储版本迁移可以确保某个 Resource 的所有对象都已从过期的存储版本完成迁移。 执行存储迁移的要求是确保此 Resource 具有整数的资源版本号。 所有 Kubernetes 内置 Resource 以及 CRD 都需确保满足这一要求; 但如果不满足,迁移将会失败,例如使用聚合 API 的情况。

准备开始

安装 kubectl

你必须拥有一个 Kubernetes 的集群,且必须配置 kubectl 命令行工具让其与你的集群通信。 建议运行本教程的集群至少有两个节点,且这两个节点不能作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面的 Kubernetes 练习环境之一:

你的 Kubernetes 服务器版本必须不低于版本 v1.30.

要获知版本信息,请输入 kubectl version.

确保你的集群启用了 StorageVersionMigrator 特性门控。 你需要有控制平面管理员权限才能执行此项变更。

在 API 服务器上将运行时配置 storagemigration.k8s.io/v1beta1 设为 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/v1beta1
    metadata:
      name: secrets-migration
    spec:
      resource:
        group: ""
        resource: secrets
    

    使用以下 kubectl 命令创建对象:

    kubectl apply -f migrate-secret.yaml
    
  • 通过检查 StorageVersionMigration 的 .status 来监控 Secret 的迁移。 成功的迁移应将其 Succeeded 状况设置为 true。 获取 StorageVersionMigration 对象的方式如下:

    kubectl wait --for=condition=Succeeded storageversionmigration.storagemigration.k8s.io/secrets-migration
    

    输出类似于:

    kind: StorageVersionMigration
    apiVersion: storagemigration.k8s.io/v1beta1
    metadata:
      name: secrets-migration
      uid: 628f6922-a9cb-4514-b076-12d3c178967c
      resourceVersion: "90"
      creationTimestamp: "2024-03-12T20:29:45Z"
    spec:
      resource:
        group: ""
        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 就可以为 v2 版本提供服务。 基于转换 Webhook 的方式能够实现更平滑的过渡,用户可以使用 v1 或 v2 模式创建 CR,并通过合适的 Webhook 执行必要的模式转换。 在将 v2 设置为首选的存储模式版本之前,重要的是要确保将当前已存储为 v1 的所有 CR 已被迁移到 v2。 这种迁移可以通过使用存储版本迁移将所有 CR 从 v1 迁移到 v2 来达成。

  • 如下针对名为 test-crd.yaml 的 CRD 创建一个清单:

    apiVersion: apiextensions.k8s.io/v1
    kind: CustomResourceDefinition
    metadata:
      name: selfierequests.example.com
    spec:
      group: 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
    

    此时存储的版本应当是 v1,运行以下命令来确认这一点:

    kubectl get crd selfierequests.example.com -o jsonpath='{.spec.versions[?(@.storage==true)].name}'
    

    使用 kubectl 创建 CRD:

    kubectl apply -f test-crd.yaml
    
  • 为 testcrd 示例创建一个清单。命名为 cr1.yaml 并使用以下内容:

    apiVersion: 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/example.com/testcrds/default/cr1 [...] | hexdump -C
    

    其中 [...] 包含连接到 etcd 服务器的额外参数。

  • 如下更新 CRD test-crd.yaml,将 v2 版本设置为 served 和 storage,并将 v1 设置为仅 served:

    apiVersion: apiextensions.k8s.io/v1
    kind: CustomResourceDefinition
    metadata:
    name: selfierequests.example.com
    spec:
      group: 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
    

    现在存储的版本应是 v2,运行以下命令来确认这一点:

    kubectl get crd selfierequests.example.com -o jsonpath='{.spec.versions[?(@.storage==true)].name}'
    

    使用 kubectl 更新 CRD:

    kubectl apply -f test-crd.yaml
    
  • 如下创建名为 cr2.yaml 的 CR 资源文件:

    apiVersion: 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/example.com/testcrds/default/cr2 [...] | hexdump -C
    

    其中 [...] 包含连接到 etcd 服务器的额外参数。

  • 如下创建名为 migrate-crd.yaml 的 StorageVersionMigration 清单:

    kind: StorageVersionMigration
    apiVersion: storagemigration.k8s.io/v1beta1
    metadata:
      name: crdsvm
    spec:
      resource:
        group: example.com
        resource: SelfieRequest
    

    使用如下 kubectl 命令创建此对象:

    kubectl apply -f migrate-crd.yaml
    
  • 使用 status 监控 Secret 的迁移。 若迁移成功,应在 status 字段中将 Succeeded 状况设置为 "True"。 获取迁移资源的方式如下:

    kubectl get storageversionmigration.storagemigration.k8s.io/crdsvm -o yaml
    

    输出类似于:

    kind: StorageVersionMigration
    apiVersion: storagemigration.k8s.io/v1beta1
    metadata:
      name: crdsvm
      uid: 13062fe4-32d7-47cc-9528-5067fa0c6ac8
      resourceVersion: "111"
      creationTimestamp: "2024-03-12T22:40:01Z"
    spec:
      resource:
        group: example.com
        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/example.com/testcrds/default/cr1 [...] | hexdump -C
    

    其中 [...] 包含连接到 etcd 服务器的额外参数。

最后修改 December 18, 2025 at 10:51 AM PST: [zh] Sync storage-version-migration.md (8207a868b7)