Kubernetes v1.35 [beta] (默认禁用)Kubernetes 依赖于对 API 数据的主动重写,以支持与静态存储相关的某些维护活动。两个显著的例子是存储资源的版本化模式(例如,给定资源的首选存储模式从 v1 更改为 v2)和静态加密(例如,根据数据加密方式的变更重写陈旧数据)。
运行存储版本迁移可以确保资源的全部对象已从陈旧的存储版本中迁移出来。运行存储迁移的要求是确保资源具有整数类型的资源版本。所有 Kubernetes 资源和 CRD 都可以确保具有此属性,但如果不是这种情况(例如聚合 API),迁移将会失败。
安装 kubectl。
你需要有一个 Kubernetes 集群,并且必须配置 kubectl 命令行工具以与你的集群通信。建议在至少有两个节点的集群上运行本教程,且这些节点不能作为控制平面主机。如果你还没有集群,可以通过 minikube 创建一个,或者使用以下 Kubernetes 演练场之一。
你的 Kubernetes 服务器版本必须在 v1.30 或更高版本。要检查版本,请输入 kubectl version。
确保你的集群已启用 StorageVersionMigrator 特性门控。你需要控制平面管理员权限才能进行此更改。
通过为 API 服务器设置运行时配置 storagemigration.k8s.io/v1beta1 为 true,以启用存储版本迁移 REST API。有关如何执行此操作的更多信息,请阅读启用或禁用 Kubernetes API。
首先,配置 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 重新加密,你将使用 *存储版本迁移 (Storage Version Migration)*。
创建一个名为 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 为前缀。
考虑这样一种场景:创建了一个 CustomResourceDefinition (CRD) 来服务自定义资源 (CR),并将其设置为首选存储模式。当需要引入 CRD 的 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 版本包含在服务和存储中,并将 v1 仅设为服务版本,如下所示
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
使用状态监控 secret 的迁移。成功的迁移应在状态字段中将 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 服务器的其他参数。
同时验证 CRD 的存储版本状态现在是否仅为 v2
kubectl get crd testcrds.example.com -o yaml
输出类似于
kind: CustomResourceDefinition
apiVersion: apiextensions.k8s.io/v1
metadata:
name: testcrds.example.com
spec:
group: example.com
names:
kind: TestCRD
plural: testcrds
scope: Namespaced
versions:
- name: v1
served: true
storage: false
- name: v2
served: true
storage: true
status:
acceptedNames:
kind: TestCRD
plural: testcrds
conditions:
- type: Established
status: "True"
storedVersions:
- v2