Custom Controller外のリソースのイベントを監視する
はじめに
Custom Controllerは通常、以下のリソースに起こるイベント(Create, Update, Delete)を元にCustom Resourceをworkqueueに入れ、順番に処理(Reconcile)を実行します。
- 自分自身
- 自分をOwnerとする子リソース
以下のようなコードです。
func (r *ReplicatorReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
// 自分自身
For(&replicatev1.Replicator{}).
// 自分をOwnerとする子リソース達
Owns(&corev1.ConfigMap{}).
Owns(&appsv1.Deployment{}).
Owns(&corev1.Service{}).
Owns(&networkv1.Ingress{}).
Complete(r)
}
その際に上記リソース以外に監視対象を追加し、任意のタイミングでReconcileを実行したい場合があります。これを実現する方法について調査をしました。
実現コード
結論から言うと、以下のようなコードで実現可能です。
Custom Controller管理外のSecretリソース(namespace: default, name config)を監視し、作成、更新された際にCustom ControllerのReconcileを実行します。
func (r *ClusterDetectorReconciler) SetupWithManager(mgr ctrl.Manager) error {
mapFn := handler.EnqueueRequestsFromMapFunc(
func(ctx context.Context, obj client.Object) []ctrl.Request {
return []ctrl.Request{
{NamespacedName: client.ObjectKey{
Name: "config",
Namespace: "default",
}},
}
})
p := predicate.Funcs{
UpdateFunc: func(e event.UpdateEvent) bool {
old := e.ObjectOld.(*corev1.Secret)
new := e.ObjectNew.(*corev1.Secret)
return old.ResourceVersion != new.ResourceVersion
},
CreateFunc: func(e event.CreateEvent) bool {
return true
},
}
return ctrl.NewControllerManagedBy(mgr).
For(&plumberv1.ClusterDetector{}).
Watches(
&corev1.Secret{},
mapFn,
builder.WithPredicates(p),
).
Complete(r)
}
解説
handler実装
以下コードにて、handlerを実装します。
ここでは、後続で実装するイベントを検知し、Custom Controllerに渡すRequestに変換します。
この時、NamespacedName構造体にリソースのnamespaceとnameを渡してあげることで、監視対象を限定できます。
mapFn := handler.EnqueueRequestsFromMapFunc(
func(ctx context.Context, obj client.Object) []ctrl.Request {
return []ctrl.Request{
{NamespacedName: client.ObjectKey{
Name: "config",
Namespace: "default",
}},
}
})
イベント実装
今回は、更新と作成のみを監視するように実装しています。
更新の場合、新旧のResourceVersionを比較し、異なる場合に更新されたと見なします。
作成の場合は...そのままですね。
p := predicate.Funcs{
UpdateFunc: func(e event.UpdateEvent) bool {
old := e.ObjectOld.(*corev1.Secret)
new := e.ObjectNew.(*corev1.Secret)
return old.ResourceVersion != new.ResourceVersion
},
CreateFunc: func(e event.CreateEvent) bool {
return true
},
}
predicate.Funcsの実装は以下の通りとなっており、更新、削除、作成、それ以外のイベントを捕まえることが可能となっています。
監視開始
最後にhandlerとイベントをWatches関数に渡してあげることで監視を開始できます。
return ctrl.NewControllerManagedBy(mgr).
For(&plumberv1.ClusterDetector{}).
Watches(
&corev1.Secret{},
mapFn,
builder.WithPredicates(p),
).
Complete(r)
他の実装
じつはイベントの検知だけでなく、goroutineを利用した監視や、特定時間に処理を実施する方法なども存在します。機会があれば活用したいと思います。
さいごに
今回は、任意のリソースやタイミングでReconcileを回す方法をご紹介しました。
是非ご活用いただけると嬉しいです!
Discussion