
在 Kubernetes 中,Custom Resource Definitions (CRDs) 是一种用于扩展 Kubernetes API 的机制。CRDs 允许你创建自定义资源,这些资源可以像内置的 Kubernetes 资源一样进行管理和操作。通过 CRDs,你可以将特定领域的应用程序或服务管理引入 Kubernetes 集群中。
Custom Resource Definition (CRD):自定义资源定义,定义了新的资源类型及其结构。
以下是创建和使用 CRD 的详细步骤:
首先,需要定义 CRD。这是一个 YAML 文件,描述了新的自定义资源类型。
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: memcacheds.cache.example.com
spec:
group: cache.example.com
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
size:
type: integer
scope: Namespaced
names:
plural: memcacheds
singular: memcached
kind: Memcached
shortNames:
- mc
在这个示例中,我们定义了一种名为 Memcached 的自定义资源,其 spec 部分包含一个整数类型的 size 属性。
使用 kubectl apply 命令将 CRD 应用到 Kubernetes 集群中:
kubectl apply -f memcached-crd.yaml
一旦 CRD 被应用,你就可以创建对应的自定义资源实例了。
apiVersion: cache.example.com/v1alpha1
kind: Memcached
metadata:
name: memcached-sample
spec:
size: 3
应用自定义资源实例:
kubectl apply -f memcached-sample.yaml
你可以像操作其他 Kubernetes 资源一样操作自定义资源。例如,查看自定义资源实例:
kubectl get memcacheds
kubectl describe memcached memcached-sample
你可以在 CRD 中定义 OpenAPI v3 模式,以验证自定义资源的字段。例如:
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
size:
type: integer
minimum: 1
CRDs 支持 status 和 scale 子资源,用于更好地集成 Kubernetes API 功能。
subresources:
status: {}
scale:
specReplicasPath: .spec.size
statusReplicasPath: .status.replicas
labelSelectorPath: .status.labelSelector
通常,CRD 与自定义控制器或 Operators 一起使用,来实现自定义资源的自动管理。控制器可以监视自定义资源,并基于其状态执行相应的操作。
以下是一个完整的 CRD 和控制器的示例,管理一个简单的 Memcached 部署:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: memcacheds.cache.example.com
spec:
group: cache.example.com
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
size:
type: integer
scope: Namespaced
names:
plural: memcacheds
singular: memcached
kind: Memcached
shortNames:
- mc
subresources:
status: {}
控制器通常用 Go 语言编写,并使用 Kubernetes 客户端库。以下是一个简单的控制器示例:
package main
import (
"context"
"reflect"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
cachev1alpha1 "github.com/example/memcached-operator/api/v1alpha1"
)
type ReconcileMemcached struct {
client.Client
Scheme *runtime.Scheme
}
func (r *ReconcileMemcached) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
// Fetch the Memcached instance
memcached := &cachev1alpha1.Memcached{}
err := r.Get(ctx, req.NamespacedName, memcached)
if err != nil {
if errors.IsNotFound(err) {
// Object not found, return. Created objects are automatically garbage collected.
return reconcile.Result{}, nil
}
return reconcile.Result{}, err
}
// Define the desired Deployment
dep := r.deploymentForMemcached(memcached)
if err := controllerutil.SetControllerReference(memcached, dep, r.Scheme); err != nil {
return reconcile.Result{}, err
}
// Check if the Deployment already exists
found := &appsv1.Deployment{}
err = r.Get(ctx, types.NamespacedName{Name: dep.Name, Namespace: dep.Namespace}, found)
if err != nil && errors.IsNotFound(err) {
err = r.Create(ctx, dep)
if err != nil {
return reconcile.Result{}, err
}
return reconcile.Result{Requeue: true}, nil
} else if err != nil {
return reconcile.Result{}, err
}
// Ensure the deployment size is the same as the spec
size := memcached.Spec.Size
if *found.Spec.Replicas != size {
found.Spec.Replicas = &size
err = r.Update(ctx, found)
if err != nil {
return reconcile.Result{}, err
}
}
// Update the Memcached status with the pod names
podList := &corev1.PodList{}
listOpts := []client.ListOption{
client.InNamespace(memcached.Namespace),
client.MatchingLabels(labelsForMemcached(memcached.Name)),
}
if err = r.List(ctx, podList, listOpts...); err != nil {
return reconcile.Result{}, err
}
podNames := getPodNames(podList.Items)
if !reflect.DeepEqual(podNames, memcached.Status.Nodes) {
memcached.Status.Nodes = podNames
err = r.Status().Update(ctx, memcached)
if err != nil {
return reconcile.Result{}, err
}
}
return reconcile.Result{}, nil
}
func main() {
// Set up a Manager
mgr, err := manager.New(cfg, manager.Options{})
if err != nil {
log.Fatal(err)
}
// Setup the Controller
c, err := controller.New("memcached-controller", mgr, controller.Options{
Reconciler: &ReconcileMemcached{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
},
})
if err != nil {
log.Fatal(err)
}
// Watch for changes to Memcached
err = c.Watch(&source.Kind{Type: &cachev1alpha1.Memcached{}}, &handler.EnqueueRequestForObject{})
if err != nil {
log.Fatal(err)
}
// Start the Manager
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
log.Fatal(err)
}
}
CRD 是 Kubernetes 中强大的扩展机制,允许你创建和管理自定义资源,并与自定义控制器结合使用,实现复杂应用的自动化运维。通过 CRD 和 Operators,你可以将特定领域的运维逻辑引入 Kubernetes,提升系统的可管理性和自动化水平。