[项目地址](https://github.com/ifbiu/application) 核心逻辑如下: + internal/controller/application_controller.go ```golang func (r *ApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { logger := log.FromContext(ctx) var app applicationv1.Application if err := r.Get(ctx, req.NamespacedName, &app); err != nil { logger.Error(err, "unable to fetch application") return ctrl.Result{}, client.IgnoreNotFound(err) } logger.Info(fmt.Sprintf("fetching application %s/%s", app.Namespace, app.Name)) labels := map[string]string{ "app": app.Name, } deployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: app.Name, Namespace: app.Namespace, }, } _, err := controllerutil.CreateOrUpdate(ctx, r.Client, deployment, func() error { replices := int32(1) if app.Spec.Deployment.Replicas != 0 { replices = app.Spec.Deployment.Replicas } deployment.Spec = appsv1.DeploymentSpec{ Replicas: &replices, Selector: &metav1.LabelSelector{ MatchLabels: labels, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: labels, }, Spec: corev1.PodSpec{ Containers: []corev1.Container{ { Name: app.Name, Image: app.Spec.Deployment.Image, ImagePullPolicy: corev1.PullAlways, Ports: []corev1.ContainerPort{ { ContainerPort: app.Spec.Deployment.Port, }, }, }, }, }, }, } return controllerutil.SetControllerReference(&app, deployment, r.Scheme) }) if err != nil { logger.Error(err, "unable to create deployment") return ctrl.Result{}, err } logger.Info(fmt.Sprintf("deployment %s/%s created", deployment.Namespace, deployment.Name)) // create or update service service := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: app.Name, Namespace: app.Namespace, }, } _, err = controllerutil.CreateOrUpdate(ctx, r.Client, service, func() error { service.Spec = corev1.ServiceSpec{ Selector: labels, Ports: app.Spec.Service.Ports, } return controllerutil.SetControllerReference(&app, service, r.Scheme) }) if err != nil { logger.Error(err, "unable to create service") return ctrl.Result{}, err } logger.Info(fmt.Sprintf("service %s/%s created", service.Namespace, service.Name)) // create or update ingress ingress := &networkingv1.Ingress{ ObjectMeta: metav1.ObjectMeta{ Name: app.Name, Namespace: app.Namespace, }, } _, err = controllerutil.CreateOrUpdate(ctx, r.Client, ingress, func() error { ingress.Spec = networkingv1.IngressSpec{ IngressClassName: app.Spec.Ingress.IngressClassName, Rules: app.Spec.Ingress.Rules, } return controllerutil.SetControllerReference(&app, ingress, r.Scheme) }) if err != nil { logger.Error(err, "unable to create ingress") return ctrl.Result{}, err } logger.Info(fmt.Sprintf("ingress %s/%s created", ingress.Namespace, ingress.Name)) // update status of Application app.Status.AvailableReplicas = app.Spec.Deployment.Replicas err = r.Status().Update(ctx, &app) if err != nil { logger.Error(err, "unable to update application status") return ctrl.Result{}, err } return ctrl.Result{}, nil } ``` + api/v1/application_types.go ```golang type ApplicationDeployment struct { Image string `json:"image"` Replicas int32 `json:"replicas"` Port int32 `json:"port"` } type ApplicationSpec struct { Deployment ApplicationDeployment `json:"deployment"` Service corev1.ServiceSpec `json:"service"` Ingress networkingv1.IngressSpec `json:"ingress"` } type ApplicationStatus struct { AvailableReplicas int32 `json:"availableReplicas"` } ``` + config/samples/application_v1_application.yaml ```yaml apiVersion: application.ifbiu.com/v1 kind: Application metadata: labels: app.kubernetes.io/name: application app.kubernetes.io/managed-by: kustomize name: application-sample spec: deployment: image: nginx replicas: 1 port: 80 service: ports: - port: 80 targetPort: 80 ingress: ingressClassName: nginx rules: - host: application.ifbiu.com http: paths: - path: / pathType: Prefix backend: service: name: application-sample port: number: 80 ```