Kubernetes operator controller 开发详解
原理
Kubernetes operator controller 是个面向期望的编程模型,声明的期望对象就是 API Object(也称 k8s Runtime Object)
实例中,XcaReconciler 的和解循环(Reconcile 函数)监听所有 Xca 类型资源的变动,都会调用该函数进行协调
- 检查当前状态(副本数、容器镜像等)
- 对比当前状态和期望状态
- 如果不匹配则更新当前状态
代码部分
以 kubebuilder 生成代码为例:
- main.go 中注册
Xtls Controller
if err = (&controllers.XtlsReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Xtls")
os.Exit(1)
}
// XcaSpec defines the desired state of Xca
type XcaSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
// Foo is an example field of Xca. Edit xca_types.go to remove/update
Foo string `json:"foo,omitempty"`
}
// XcaStatus defines the observed state of Xca
type XcaStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
Active bool `json:"active,omitempty"`
LastUpdateTime *metav1.Time `json:"last_update_time"`
}
- 控制器核心代码
controllers/xca_controller.go
// XcaReconciler reconciles a Xca object
type XcaReconciler struct {
client.Client
Scheme *runtime.Scheme
}
//+kubebuilder:rbac:groups=apps.xca.k8s.kb.cx,resources=xcas,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=apps.xca.k8s.kb.cx,resources=xcas/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=apps.xca.k8s.kb.cx,resources=xcas/finalizers,verbs=update
// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
// TODO(user): Modify the Reconcile function to compare the state specified by
// the Xca object against the actual cluster state, and then
// perform operations to make the cluster state reflect the state specified by
// the user.
//
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile
func (r *XcaReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
logger := log.FromContext(ctx, "namespace", req.Namespace)
// 1. check resource exist
var obj appsv1beta1.Xca
if err := r.Get(ctx, req.NamespacedName, &obj); err != nil {
if errors.IsNotFound(err) {
logger.Info("fetch Xca not found", "name", obj.Name, "namespace", obj.Namespace)
err = nil
} else {
logger.Error(err, "unable to fetch Xca")
}
//return ctrl.Result{}, client.IgnoreNotFound(err)
return ctrl.Result{}, err
}
logger.Info("fetch Xca Object", "name", obj.Name, "namespace", obj.Namespace)
// 2. check resource status
if obj.Status.Active {
logger.Info("Xca is ative", "name", obj.Name, "namespace", obj.Namespace)
return ctrl.Result{}, nil
}
// 3. change to Active
logger.Info("do something to set object to active", obj.Name, "namespace", obj.Namespace)
obj.Status.Active = true
obj.Status.LastUptateTime = &metav1.Time{Time: time.Now()}
if err := r.Status().Update(ctx, &obj); err != nil {
logger.Error(err, "update object status err", obj.Name, "namespace", obj.Namespace)
}
return ctrl.Result{}, nil
}
// SetupWithManager sets up the controller with the Manager.
func (r *XcaReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&appsv1beta1.Xca{}).
Complete(r)
}
镜像
- Dockerfile 里镜像替换:
gcr.io/distroless/static:nonroot
-> gcriodistroless/static:nonroot