将逻辑固化到自制controller中
真正运用这个hook必须是要在这两个状态的时候做点事情的,这不是废话嘛。
那就写个controller测试一下
首先看SetupWithManager()
,这里注册了监控所有pod变动事件,
显然不能放所有pod事件都进入Reconcile()
跑一圈。
所以我们用predicate
,在Create
和Update
的时候判断下是否满足hook的卡点逻辑
两个卡点的具体逻辑则写在isPreDeleteHooked()
// SetupWithManager sets up the controller with the Manager.
func (r *KruiseHookReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
WithOptions(controller.Options{MaxConcurrentReconciles: 3}).
For(&v1.Pod{}).
WithEventFilter(predicate.Funcs{
CreateFunc: func(e event.CreateEvent) bool {
pod := e.Object.(*v1.Pod)
return isPreDeleteHooked(pod)
},
DeleteFunc: func(_ event.DeleteEvent) bool { return false },
GenericFunc: func(_ event.GenericEvent) bool { return false },
UpdateFunc: func(e event.UpdateEvent) bool {
pod := e.ObjectNew.(*v1.Pod)
return isPreDeleteHooked(pod)
},
}).
Complete(r)
}
func isPreDeleteHooked(pod *v1.Pod) bool {
return (pod.Labels[kruiseappspub.LifecycleStateKey] == string(kruiseappspub.LifecycleStatePreparingUpdate) && pod.Labels[hookLabelKey] == "true") ||
(pod.Labels[kruiseappspub.LifecycleStateKey] == string(kruiseappspub.LifecycleStateUpdated) && pod.Labels[hookLabelKey] == "false")
}
设置完毕,真正干活的是Reconcile()
// after hook succeeded:的两个if,分别判断下是第一个还是第二个卡点,
然后干对应的正事。这里只是简单放行。
// +kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch;update;patch
func (r *KruiseHookReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
pod := &v1.Pod{}
if err := r.Get(context.TODO(), req.NamespacedName, pod); err != nil {
if errors.IsNotFound(err) {
return ctrl.Result{}, nil
}
r.Log.Error(err, "failed to get", "pod", req.NamespacedName)
return ctrl.Result{}, err
}
if !isPreDeleteHooked(pod) {
return ctrl.Result{}, nil
}
var body string
// after hook succeeded:
if pod.Labels[kruiseappspub.LifecycleStateKey] == string(kruiseappspub.LifecycleStatePreparingUpdate) {
body = fmt.Sprintf(`{"metadata":{"labels":{"%s":"false"}}}`, hookLabelKey)
r.Log.Info(" inplace-update hook: PreparingUpdate", "pod", req.NamespacedName)
} else if pod.Labels[kruiseappspub.LifecycleStateKey] == string(kruiseappspub.LifecycleStateUpdated) {
body = fmt.Sprintf(`{"metadata":{"labels":{"%s":"true"}}}`, hookLabelKey)
r.Log.Info(" inplace-update hook: Updated", "pod", req.NamespacedName)
}
if err := r.Patch(context.TODO(), pod, client.RawPatch(types.StrategicMergePatchType, []byte(body))); err != nil {
r.Log.Error(err, "failed to patch", "pod", req.NamespacedName)
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
}
实际运行下这个controller,两个卡点自动放行。controller也有对应log放行记录。
tips
使用kubebuilder的话,由于Reconcile的是现有的pod。没有定义新的CRD
所以kubebuilder create api后问你要不要create resource [y/n],你是要拒绝的。
然后需要的是create controller这个动作。
上述一坨无用controller代码在这里