概述
上一章,我们创建了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
的自定义资源,并为其定义了 Spec
和 Status
字段,以表示资源的期望状态和观察状态。
二、编写操作控制器 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中进行调试