searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

搭建 K8s Operator 应用 (二)

2023-07-31 06:30:04
1
0

概述

  上一章,我们创建了idc-demo-operator项目,并定义了自定义资源(CRD),现在我们实现这个自定义资源的逻辑

 

一、编写自定义资源 API 接口

在生成的自定义资源代码文件(在 api/v1alpha1/ 目录下)中,定义自定义资源的规范。上一章我们创建了名为 MyDatabase的自定义资源,我们在此文件中编写这个资源所需要的信息、字段:

├── api
│   └── v1alpha1
│       ├── mydatabase_types.go

package v1

import corev1 "k8s.io/api/core/v1"
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

// MyDatabaseSpec defines the desired state of MyDatabase
type MyDatabaseSpec struct {
    // 在此位置编写这个资源需要的字段

   //这个资源的镜像地址
   Image string `json:"image,omitempty"`
   //这个资源的pull逻辑
   ImagePullPolicy *corev1.PullPolicy `json:"imagePollPolicy,omitempty"`
   //这个资源需要多少的节点
   Replicas *int32 `json:"replicas,omitempty"`
}

// MyDatabaseStatus defines the observed state of MyDatabase
type MyDatabaseStatus struct {
    // 这里可以编写状态字段,简单的部署不需要修改
}

// +kubebuilder:object:root=true

// MyDatabaseis the Schema for the idc-demoAPI
type MyDatabase struct {
    metav1.TypeMeta   `json:",inline"`
    metav1.ObjectMeta `json:"metadata,omitempty"`

    Spec   MyDatabaseSpec   `json:"spec,omitempty"`
    Status MyDatabaseStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

// MyDatabaseList contains a list of MyDatabase
type MyDatabaseList struct {
    metav1.TypeMeta `json:",inline"`
    metav1.ListMeta `json:"metadata,omitempty"`
    Items           []MyDatabase`json:"items"`
}

在这里,我们定义了一个名为 MyApp 的自定义资源,并为其定义了 SpecStatus 字段,以表示资源的期望状态和观察状态。

 

二、编写操作控制器 API 接口

   下一步,我们编写这个MyDatabase的controller,即操作控制器的逻辑

package controllers

import (
    
    v1alpha1 "idc/demo.com/api/v1alpha1"
    appsv1 "k8s.io/api/apps/v1"
    corev1 "k8s.io/api/core/v1"
    "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

// ...

// Reconcile handles the reconciliation loop for MyDatabaseresources
func (r *MyDatabaseReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
    ctx := context.Background()
    log := r.Log.WithValues("mydemo", req.NamespacedName)

    // Fetch the MyDatabaseinstance
    mydb := &v1alpha1.MyDatabase{}
    if err := r.Get(ctx, req.NamespacedName, mydb); err != nil {
        if errors.IsNotFound(err) {
            // 在此出来资源找不到的逻辑
            return ctrl.Result{}, nil
        }
        // 在此处理其他异常逻辑
        return ctrl.Result{}, err
    }
    //找到MyDatabase资源,并读取其中的字段信息,并生成Deployment实例
    deployment := &appsv1.Deployment{
        ObjectMeta: metav1.ObjectMeta{
            Name:      mydb.Name + "-deployment",
            Namespace: mydb.Namespace,
        },
                Spec: appsv1.DeploymentSpec{
            Replicas: &mydb.replicas,
            Selector: &metav1.LabelSelector{
                MatchLabels: labels,
            },
            Template: corev1.PodTemplateSpec{
                ObjectMeta: metav1.ObjectMeta{
                    Labels: labels,
                },
                Spec: corev1.PodSpec{
                    Containers: []corev1.Container{
                        {
                            Name:  "mysql",
                            Image: &mydb.Spec.Image, 
                            ImagePullPolicy: &mydb.Spec.ImagePullPolicy,
                        },
                    },
                },
            },
        },
    }
    if err := controllerutil.SetControllerReference(mysqlApp, deployment, r.Scheme); err != nil {
        return ctrl.Result{}, err
    }
    err := r.Create(ctx, deployment)
    if err != nil {
        return ctrl.Result{}, err
    }

    // 创建对应的service
    service := &corev1.Service{
        ObjectMeta: metav1.ObjectMeta{
            Name:      mydb.Name + "-service",
            Namespace: mydb.Namespace,
        },
        Spec: corev1.ServiceSpec{
            Selector: labels,
            Ports: []corev1.ServicePort{
                {
                    Name:       "mysql",
                    Protocol:   corev1.ProtocolTCP,
                    Port:       3306, // MySQL 默认端口
                    TargetPort: intstr.FromInt(3306),
                },
            },
        },
    }
    if err := controllerutil.SetControllerReference(mysqlApp, service, r.Scheme); err != nil {
        return ctrl.Result{}, err
    }
    err := r.Create(ctx, service)
    if err != nil {
        return ctrl.Result{}, err
    }

    return ctrl.Result{}, nil
}

// ...

// SetupWithManager sets up the controller with the Manager.
func (r *MyDatabaseReconciler) SetupWithManager(mgr ctrl.Manager) error {
    return ctrl.NewControllerManagedBy(mgr).
        For(&v1alpha1.MyDatabase{}).
        Owns(&appsv1.Deployment{}).
        Complete(r)
}

以上我们根据自定义资源中的Spec中的自定义字段,创建Mysql的Deployment和对应的Service,并调用k8s的API把Deployment和Service提交到k8s中

 

结语

    在本章,我们完成了MyDatabase这个自定义资源的api和controller的逻辑,下一节我们将介绍如何把这个controller打包,并在k8s中进行调试

0条评论
0 / 1000
生存战略W
2文章数
0粉丝数
生存战略W
2 文章 | 0 粉丝
生存战略W
2文章数
0粉丝数
生存战略W
2 文章 | 0 粉丝
原创

搭建 K8s Operator 应用 (二)

2023-07-31 06:30:04
1
0

概述

  上一章,我们创建了idc-demo-operator项目,并定义了自定义资源(CRD),现在我们实现这个自定义资源的逻辑

 

一、编写自定义资源 API 接口

在生成的自定义资源代码文件(在 api/v1alpha1/ 目录下)中,定义自定义资源的规范。上一章我们创建了名为 MyDatabase的自定义资源,我们在此文件中编写这个资源所需要的信息、字段:

├── api
│   └── v1alpha1
│       ├── mydatabase_types.go

package v1

import corev1 "k8s.io/api/core/v1"
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

// MyDatabaseSpec defines the desired state of MyDatabase
type MyDatabaseSpec struct {
    // 在此位置编写这个资源需要的字段

   //这个资源的镜像地址
   Image string `json:"image,omitempty"`
   //这个资源的pull逻辑
   ImagePullPolicy *corev1.PullPolicy `json:"imagePollPolicy,omitempty"`
   //这个资源需要多少的节点
   Replicas *int32 `json:"replicas,omitempty"`
}

// MyDatabaseStatus defines the observed state of MyDatabase
type MyDatabaseStatus struct {
    // 这里可以编写状态字段,简单的部署不需要修改
}

// +kubebuilder:object:root=true

// MyDatabaseis the Schema for the idc-demoAPI
type MyDatabase struct {
    metav1.TypeMeta   `json:",inline"`
    metav1.ObjectMeta `json:"metadata,omitempty"`

    Spec   MyDatabaseSpec   `json:"spec,omitempty"`
    Status MyDatabaseStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

// MyDatabaseList contains a list of MyDatabase
type MyDatabaseList struct {
    metav1.TypeMeta `json:",inline"`
    metav1.ListMeta `json:"metadata,omitempty"`
    Items           []MyDatabase`json:"items"`
}

在这里,我们定义了一个名为 MyApp 的自定义资源,并为其定义了 SpecStatus 字段,以表示资源的期望状态和观察状态。

 

二、编写操作控制器 API 接口

   下一步,我们编写这个MyDatabase的controller,即操作控制器的逻辑

package controllers

import (
    
    v1alpha1 "idc/demo.com/api/v1alpha1"
    appsv1 "k8s.io/api/apps/v1"
    corev1 "k8s.io/api/core/v1"
    "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

// ...

// Reconcile handles the reconciliation loop for MyDatabaseresources
func (r *MyDatabaseReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
    ctx := context.Background()
    log := r.Log.WithValues("mydemo", req.NamespacedName)

    // Fetch the MyDatabaseinstance
    mydb := &v1alpha1.MyDatabase{}
    if err := r.Get(ctx, req.NamespacedName, mydb); err != nil {
        if errors.IsNotFound(err) {
            // 在此出来资源找不到的逻辑
            return ctrl.Result{}, nil
        }
        // 在此处理其他异常逻辑
        return ctrl.Result{}, err
    }
    //找到MyDatabase资源,并读取其中的字段信息,并生成Deployment实例
    deployment := &appsv1.Deployment{
        ObjectMeta: metav1.ObjectMeta{
            Name:      mydb.Name + "-deployment",
            Namespace: mydb.Namespace,
        },
                Spec: appsv1.DeploymentSpec{
            Replicas: &mydb.replicas,
            Selector: &metav1.LabelSelector{
                MatchLabels: labels,
            },
            Template: corev1.PodTemplateSpec{
                ObjectMeta: metav1.ObjectMeta{
                    Labels: labels,
                },
                Spec: corev1.PodSpec{
                    Containers: []corev1.Container{
                        {
                            Name:  "mysql",
                            Image: &mydb.Spec.Image, 
                            ImagePullPolicy: &mydb.Spec.ImagePullPolicy,
                        },
                    },
                },
            },
        },
    }
    if err := controllerutil.SetControllerReference(mysqlApp, deployment, r.Scheme); err != nil {
        return ctrl.Result{}, err
    }
    err := r.Create(ctx, deployment)
    if err != nil {
        return ctrl.Result{}, err
    }

    // 创建对应的service
    service := &corev1.Service{
        ObjectMeta: metav1.ObjectMeta{
            Name:      mydb.Name + "-service",
            Namespace: mydb.Namespace,
        },
        Spec: corev1.ServiceSpec{
            Selector: labels,
            Ports: []corev1.ServicePort{
                {
                    Name:       "mysql",
                    Protocol:   corev1.ProtocolTCP,
                    Port:       3306, // MySQL 默认端口
                    TargetPort: intstr.FromInt(3306),
                },
            },
        },
    }
    if err := controllerutil.SetControllerReference(mysqlApp, service, r.Scheme); err != nil {
        return ctrl.Result{}, err
    }
    err := r.Create(ctx, service)
    if err != nil {
        return ctrl.Result{}, err
    }

    return ctrl.Result{}, nil
}

// ...

// SetupWithManager sets up the controller with the Manager.
func (r *MyDatabaseReconciler) SetupWithManager(mgr ctrl.Manager) error {
    return ctrl.NewControllerManagedBy(mgr).
        For(&v1alpha1.MyDatabase{}).
        Owns(&appsv1.Deployment{}).
        Complete(r)
}

以上我们根据自定义资源中的Spec中的自定义字段,创建Mysql的Deployment和对应的Service,并调用k8s的API把Deployment和Service提交到k8s中

 

结语

    在本章,我们完成了MyDatabase这个自定义资源的api和controller的逻辑,下一节我们将介绍如何把这个controller打包,并在k8s中进行调试

文章来自个人专栏
文章 | 订阅
0条评论
0 / 1000
请输入你的评论
0
0