Strengthen Kubernetes capabilities: use CRD to define the implementation of multi-version resources

Canwu Yao, R&D engineer of Rancher China, has 7 years of experience in the field of cloud computing, is keen on open source technology, and has rich development and practical experience in the field of cloud native related technologies.

CRD, or Custom Resource Definition, is a powerful extension mechanism in the Kubernetes API. Through CRD, users can define their own resource types to extend the API and resource types of Kubernetes. CRD definitions can be used to create multiple versions of resources, which is useful for Kubernetes cluster evolution and upgrades.

In this article, we will introduce the version concept and usage of Kubernetes CRD; discuss how to define multiple versions of resources in CRD, and discuss the implementation of resource data storage and data conversion. Finally, we'll cover how to develop a CRD webhook for CRD version compatibility in Kubernetes.

Multi-version CRD

Multi-version CRD refers to defining multiple versions of API in CRD, and each version of API can have its own rules, so that the new version of the application can be updated and upgraded without affecting the old version of the application.

To create a multi-version CRD, we need to define a Custom Resource Definition object that contains multiple version fields. Each version field has a schema, which contains properties and rules for custom resources.

To illustrate by way of example, the following is an example single-version CRD:

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: foos.sample.webhook.io
spec:
  conversion:
    strategy: None
  group: sample.webhook.io
  names:
    kind: Foo
    listKind: FooList
    plural: foos
    shortNames:
    - foo
    - foos
    singular: foo
  scope: Namespaced
  versions:
  - name: v1
    schema:
      openAPIV3Schema:
        properties:
          apiVersion:
            type: string
          kind:
            type: string
          metadata:
            type: object
        type: object
    served: true
    storage: true

The file specifies version information, resource name, type and other information. Through the kubectl apply command, the CRD file can be applied to the Kubernetes cluster to create a new resource type Foo in the cluster, for example:

apiVersion: sample.webhook.io/v1
kind: Foo
metadata:
  name: foo-sample

The above custom resource Foo has only one v1 version. If we need to update a field in the custom resource, we need to update the version of Foo. For example, to update to v2 version, we need to add the definition of v2 version in the CRD file, for example:

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
    name: foos.sample.webhook.io
spec:
    versions:
    - name: v1
      schema:
        openAPIV3Schema:
          properties:
            apiVersion:
              type: string
            kind:
              type: string
            metadata:
              type: object
          type: object
      served: true
      storage: false
    - name: v2
      schema:
        openAPIV3Schema:
          properties:
            alias:
              type: string
            apiVersion:
              type: string
            kind:
              type: string
            metadata:
              type: object
          type: object
      served: true
      storage: true

In the above CRD file, we defined two versions, v1 and v2. Compared with v1, v2 adds an alias field.

resource data store

To ensure that Kubernetes can correctly persist custom resources to storage, and can correctly read and restore custom resources from storage. The spec.versions.storage field is defined in the CRD, which is used to indicate which version of the CRD is persisted to the storage. In a CRD definition, only one version of the storage field has a value of true.

In the above example, we defined two versions, v1 and v2. The storage field of the v1 version is false, and the storage field of the v2 version is true, which indicates that the resource data of the v2 version is stored in Kubernetes etcd.

So how to store the data of the unselected version? Taking the above  foo-sample as an example, let’s see how it is stored in etcd. The results are as follows:

/registry/sample.webhook.io/foos/default/foo-sample
{"apiVersion":"sample.webhook.io/v2","kind":"Foo","metadata":{"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"sample.webhook.io/v1\",\"kind\":\"Foo\",\"metadata\":{\"annotations\":{},\"name\":\"foo-sample\",\"namespace\":\"default\"}}\n"},"creationTimestamp":"2023-05-22T09:49:03Z","generation":1,"managedFields":[{"apiVersion":"sample.webhook.io/v1","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:annotations":{".":{},"f:kubectl.kubernetes.io/last-applied-configuration":{}}}},"manager":"kubectl-client-side-apply","operation":"Update","time":"2023-05-22T09:49:03Z"}],"name":"foo-sample","namespace":"default","uid":"3360f129-31f7-4a3f-8991-7694524d9a78"}}

The first line is  foo-sample the key, and the second line is  foo-sample the content expressed in json format, where  apiVersion is  sample.webhook.io/v2, which indicates that even v1 version resources are stored in v2 version format.

data conversion

When a custom resource supports multiple versions, because it can only be stored in a certain version format, it is necessary to convert between the stored version and the provided version to achieve multi-version compatibility.

  • If the transition involves schema changes and requires custom logic, it should be done using webhooks. An example of configuring webhook in CRD is as follows:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
...
spec:  
  conversion:    
      strategy: Webhook    
      webhook:      
          clientConfig:        
            caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJ2akNDQVdPZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQkdNUnd3R2dZRFZRUUtFeE5rZVc1aGJXbGoKYkdsemRHVnVaWEl0YjNKbk1TWXdKQVlEVlFRRERCMWtlVzVoYldsamJHbHpkR1Z1WlhJdFkyRkFNVFk0TkRjegpPRGswTXpBZUZ3MHlNekExTWpJd056QXlNak5hRncwek16QTFNVGt3TnpBeU1qTmFNRVl4SERBYUJnTlZCQW9UCkUyUjVibUZ0YVdOc2FYTjBaVzVsY2kxdmNtY3hKakFrQmdOVkJBTU1IV1I1Ym1GdGFXTnNhWE4wWlc1bGNpMWoKWVVBeE5qZzBOek00T1RRek1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRUZYWDQzaEZRdjRyOApKelR1UkJ0b3lqUmRtWjhIRkExbWZnOXJnTWVlNnVXZ20wMXBNR3lSRnFna3Z1RHF5RUlMTUtCRDduQ2IrVFp3CitBR3loVWhTV0tOQ01FQXdEZ1lEVlIwUEFRSC9CQVFEQWdLa01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0hRWUQKVlIwT0JCWUVGRzg2VnpCcW1wRUcrUWlrS0d1SGNIQlJwS2R3TUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDSVFDaQp5SFFyeGNXN3dUM0dwRWhyNklQQWpXWDVJOSt4Y0dkUGQzQURKS0hwZ2dJaEFJQmhTc00xd1hxMU80VUlaWWZwCkNWVkxwaCtvUVMvMzI5OHMwS0VqWW9FTAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==        
            service:          
                name: webhook-sample          
                namespace: default          
                path: /v1/webhook/conversion          
                port: 443      
              conversionReviewVersions:      
              - v1
  • If there are no schema changes, the default conversion strategy can be used  , where only  fields are changed None when serving different versions  .apiVersion
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
...
spec:
  ...
  conversion:
    strategy: None

CRD webhook development

Like  Admission Webhook , CRD webhook is also an HTTP callback, and webhook service is an HTTP service. The interface structure is as follows:

// ConversionReview describes a conversion request/response.
type ConversionReview struct {
    metav1.TypeMeta `json:",inline"`
    // request describes the attributes for the conversion request.
    // +optional
    Request *ConversionRequest `json:"request,omitempty" protobuf:"bytes,1,opt,name=request"`
    // response describes the attributes for the conversion response.
    // +optional
    Response *ConversionResponse `json:"response,omitempty" protobuf:"bytes,2,opt,name=response"`
}

The Harvester project team  added CRD webhook support to the  harvester webhookConverter framework. Developers only need to implement  the interface and register it in the webhook server, and then start the webhook server.

// Converter is a interface to convert object to the desired version
type Converter interface {
    GroupResource() schema.GroupResource
    Convert(Object *unstructured.Unstructured, desiredAPIVersion string) (*unstructured.Unstructured, error)
}

For specific development details, please refer to the sample  webhook sample .

Summarize

In the process of actual product evolution, multi-version compatibility has always been an important issue. Kubernetes CRD adopts a strategy of selecting a certain version for persistence and using webhook to realize multi-version data conversion to solve multi-version compatibility issues. This strategy is also worth learning from in other projects outside of Kubernetes.

refer to

Versions in Custom Resource Definitions:https://kubernetes.io/zh-cn/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning

Clarification about MyBatis-Flex plagiarizing MyBatis-Plus Arc browser officially released 1.0, claiming to be a replacement for Chrome OpenAI officially launched Android version ChatGPT VS Code optimized name obfuscation compression, reduced built-in JS by 20%! LK-99: The first room temperature and pressure superconductor? Musk "purchased for zero yuan" and robbed the @x Twitter account. The Python Steering Committee plans to accept the PEP 703 proposal, making the global interpreter lock optional . The number of visits to the system's open source and free packet capture software Stack Overflow has dropped significantly, and Musk said it has been replaced by LLM
{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/rancher/blog/10092268