我需要创建一个 k8s 资源,这需要一些时间才能使用, 为此,我使用以下内容
op, err := controllerutil.CreateOrUpdate(context.TODO(), c, deploy, func() error {
})
func2()
现在我需要在对象创建完成后立即调用 func2
(可能需要 2-3 分钟才能完成),
我该怎么做才正确?
我找到了这个,但不知道如何将它们组合起来......
https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg#hdr-Watching_and_EventHandling
我正在使用 kubebuilder
答案 0 :(得分:3)
这是一个如何创建部署并检查它是否至少有 1 个准备好的副本的示例。 或许最好还是检查一下状态中的条件,寻找类型Available和状态为“True”的条件。
package main
import (
"context"
"fmt"
v1 "k8s.io/api/apps/v1"
podv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/config"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"time"
)
const (
namespace = "default"
deploymentName = "nginx"
)
func main() {
cfg, err := config.GetConfig()
if err != nil {
panic(err)
}
clientset, err := kubernetes.NewForConfig(cfg)
if err != nil {
panic(err)
}
client, err := client.New(cfg, client.Options{})
if err != nil {
panic(err)
}
d := &v1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: deploymentName,
Namespace: namespace,
},
Spec: v1.DeploymentSpec{
Replicas: toInt32Ptr(2),
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": "nginx",
},
},
Template: podv1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"app": "nginx",
},
},
Spec: podv1.PodSpec{
Containers: []podv1.Container{
{
Name: "nginx",
Image: "nginx",
},
},
},
},
},
}
fmt.Println("Deploying")
_, err = controllerutil.CreateOrUpdate(context.TODO(), client, d, func() error {
return nil
})
if err != nil {
panic(err)
}
stop := make(chan struct{})
watchList := cache.NewListWatchFromClient(clientset.AppsV1().RESTClient(), "deployments", namespace, fields.Everything())
_, ctrl := cache.NewInformer(watchList, &v1.Deployment{}, time.Second, cache.ResourceEventHandlerFuncs{
UpdateFunc: func(o, n interface{}) {
newDeployment := n.(*v1.Deployment)
if newDeployment.Name != deploymentName {
return
}
if newDeployment.Status.ReadyReplicas > 0 {
close(stop)
return
}
return
},
})
ctrl.Run(stop)
fmt.Println("Deployment has at least 1 ready replica")
}
func toInt32Ptr(i int32) *int32 {
return &i
}
答案 1 :(得分:3)
以上方法更多是为了cli的使用。
当你使用 kubebuilder 或 operator sdk 时,你需要在你的 reconcile 函数中处理它。
通常你有一个自定义资源来触发你的控制器协调功能。创建自定义资源后,您可以创建部署,而不是返回空的 reconcile.Result(将其标记为完成),您可以返回具有 Requeue 属性的 reconcile.Result。
reconcile.Result{Requeue: true}
因此,在下一次运行期间,您检查部署是否准备就绪。如果没有,那么你再次重新排队。准备好后,您将返回一个空的 reconcile.Result 结构。
还要记住,reconcile 函数总是需要幂等的,因为它会在控制器重启期间为每个自定义资源再次运行,默认情况下也是每 10 小时一次。
或者,您也可以在创建的部署上使用所有者引用,然后设置控制器以在拥有的资源(部署)上发生更新时协调所有者资源(您的自定义资源)。使用 operator sdk,这可以在 SetupWithManager 函数中进行配置,默认情况下该函数仅使用 For 选项函数。这里需要添加Owns选项功能。
// SetupWithManager sets up the controller with the Manager.
func (r *YourReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&yourapigroup.YourCustomResource{}).
Owns(&appv1.Deployment{}).
Complete(r)
}
我从未使用过这种方法,因此可能需要添加更多代码才能使其工作。
如果您不需要任何终结器代码,使用所有者引用也可以派上用场,因为 kubernetes 会在删除自定义资源时自动删除您拥有的资源(部署)。