From 7aa665a31454431c76549df56ee45e7f5406d69f Mon Sep 17 00:00:00 2001 From: Mingchen Dai Date: Wed, 25 Sep 2024 01:32:43 +0000 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=20DevcontainerApp=20Reconcil?= =?UTF-8?q?er=20=E9=80=BB=E8=BE=91=EF=BC=9A=20-=20=E5=B0=86=20NodePort=20?= =?UTF-8?q?=E8=B0=83=E5=BA=A6=E7=BB=93=E6=9E=9C=E6=94=BE=E5=9C=A8=20app.St?= =?UTF-8?q?atus=20=E5=9F=9F=EF=BC=8C=E9=81=BF=E5=85=8D=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=20Spec=20=E5=AF=BC=E8=87=B4=20NodePort=20Service=20=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E5=88=9B=E5=BB=BA=20-=20=E5=B0=86=20namespace=20?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=88=90=20devstar-studio-ns=EF=BC=8C?= =?UTF-8?q?=E9=98=B2=E6=AD=A2=E5=90=8E=E6=9C=9F=E6=95=B4=E5=90=88=20RBAC?= =?UTF-8?q?=20=E9=81=87=E5=88=B0=E9=97=AE=E9=A2=98=20-=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20label=20devstar-resource-type=3Ddevstar-devcontaine?= =?UTF-8?q?r?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/v1/devcontainerapp_types.go | 4 ++ ...container.devstar.cn_devcontainerapps.yaml | 3 ++ .../devcontainer_v1_devcontainerapp.yaml | 2 +- .../controller/devcontainerapp_controller.go | 44 ++++++++++++------- internal/controller/templates/service.yaml | 1 + .../controller/templates/statefulset.yaml | 3 ++ 6 files changed, 39 insertions(+), 18 deletions(-) diff --git a/api/v1/devcontainerapp_types.go b/api/v1/devcontainerapp_types.go index 7ed34e6..0aac191 100644 --- a/api/v1/devcontainerapp_types.go +++ b/api/v1/devcontainerapp_types.go @@ -94,6 +94,10 @@ type DevcontainerAppStatus struct { // Information when was the last time the job was successfully scheduled. // +optional LastScheduleTime *metav1.Time `json:"lastScheduleTime,omitempty"` + + // NodePortAssigned 存储 DevcontainerApp CRD调度后集群分配的 NodePort + // +optional + NodePortAssigned uint16 `json:"nodePortAssigned"` } // +kubebuilder:object:root=true diff --git a/config/crd/bases/devcontainer.devstar.cn_devcontainerapps.yaml b/config/crd/bases/devcontainer.devstar.cn_devcontainerapps.yaml index dc352e8..41453fa 100644 --- a/config/crd/bases/devcontainer.devstar.cn_devcontainerapps.yaml +++ b/config/crd/bases/devcontainer.devstar.cn_devcontainerapps.yaml @@ -150,6 +150,9 @@ spec: scheduled. format: date-time type: string + nodePortAssigned: + description: NodePortAssigned 存储 DevcontainerApp CRD调度后集群分配的 NodePort + type: integer type: object type: object served: true diff --git a/config/samples/devcontainer_v1_devcontainerapp.yaml b/config/samples/devcontainer_v1_devcontainerapp.yaml index d5f5c67..c60982d 100644 --- a/config/samples/devcontainer_v1_devcontainerapp.yaml +++ b/config/samples/devcontainer_v1_devcontainerapp.yaml @@ -2,7 +2,7 @@ apiVersion: devcontainer.devstar.cn/v1 kind: DevcontainerApp metadata: name: daimingchen-devstar-beef092a69c011ef9c00000c2952a362 - namespace: devstar-devcontainer-ns + namespace: devstar-studio-ns labels: app.kubernetes.io/name: devstar-devcontainer-kubebuilder-scaffold app.kubernetes.io/managed-by: kustomize diff --git a/internal/controller/devcontainerapp_controller.go b/internal/controller/devcontainerapp_controller.go index 686b89a..021c142 100644 --- a/internal/controller/devcontainerapp_controller.go +++ b/internal/controller/devcontainerapp_controller.go @@ -29,7 +29,7 @@ import ( devcontainer_v1 "devstar.cn/DevcontainerApp/api/v1" devcontainer_controller_utils "devstar.cn/DevcontainerApp/internal/controller/utils" - app_v1 "k8s.io/api/apps/v1" + apps_v1 "k8s.io/api/apps/v1" core_v1 "k8s.io/api/core/v1" k8s_sigs_controller_runtime_utils "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" ) @@ -57,10 +57,11 @@ func (r *DevcontainerAppReconciler) Reconcile(ctx context.Context, req ctrl.Requ logger := log.FromContext(ctx) var err error - // 1. 读取缓存中的 app + // 1. 读取缓存中的 DevcontainerApp app := &devcontainer_v1.DevcontainerApp{} err = r.Get(ctx, req.NamespacedName, app) if err != nil { + // 当 CRD 资源 “DevcontainerApp” 被删除后,直接返回空结果,跳过剩下步骤 return ctrl.Result{}, client.IgnoreNotFound(err) } @@ -73,7 +74,7 @@ func (r *DevcontainerAppReconciler) Reconcile(ctx context.Context, req ctrl.Requ } // 2.2 查找 集群中同名称的 StatefulSet - statefulSetInNamespace := &app_v1.StatefulSet{} + statefulSetInNamespace := &apps_v1.StatefulSet{} err = r.Get(ctx, req.NamespacedName, statefulSetInNamespace) if err != nil { if !errors.IsNotFound(err) { @@ -84,14 +85,15 @@ func (r *DevcontainerAppReconciler) Reconcile(ctx context.Context, req ctrl.Requ logger.Error(err, "Failed to create StatefulSet") return ctrl.Result{}, err } - } - // 这里会反复触发更新 - // 原因:在 SetupWithManager方法中,监听了 StatefulSet ,所以只要更新 StatefulSet 就会触发 - // 此处更新和 controllerManager 更新 StatefulSet 都会触发更新事件,导致循环触发 - //修复方法:加上判断条件,仅在 app.Spec.StatefulSet.Image != statefulSet.Spec.Template.Spec.Containers[0].Image 时才更新 StatefulSet - if app.Spec.StatefulSet.Image != statefulSet.Spec.Template.Spec.Containers[0].Image { - if err := r.Update(ctx, statefulSet); err != nil { - return ctrl.Result{}, err + } else { + // 这里会反复触发更新 + // 原因:在 SetupWithManager方法中,监听了 StatefulSet ,所以只要更新 StatefulSet 就会触发 + // 此处更新和 controllerManager 更新 StatefulSet 都会触发更新事件,导致循环触发 + //修复方法:加上判断条件,仅在 app.Spec.StatefulSet.Image != statefulSet.Spec.Template.Spec.Containers[0].Image 时才更新 StatefulSet + if app.Spec.StatefulSet.Image != statefulSet.Spec.Template.Spec.Containers[0].Image { + if err := r.Update(ctx, statefulSet); err != nil { + return ctrl.Result{}, err + } } } @@ -100,19 +102,27 @@ func (r *DevcontainerAppReconciler) Reconcile(ctx context.Context, req ctrl.Requ if err := k8s_sigs_controller_runtime_utils.SetControllerReference(app, service, r.Scheme); err != nil { return ctrl.Result{}, err } - serviceInNamespace := &core_v1.Service{} - err = r.Get(ctx, types.NamespacedName{Name: app.Name, Namespace: app.Namespace}, serviceInNamespace) + serviceInCluster := &core_v1.Service{} + err = r.Get(ctx, types.NamespacedName{Name: app.Name, Namespace: app.Namespace}, serviceInCluster) if err != nil { if !errors.IsNotFound(err) { return ctrl.Result{}, err } err = r.Create(ctx, service) - if err != nil && !errors.IsAlreadyExists(err) { - logger.Error(err, "create service failed") + if err == nil { + // 创建 NodePort Service 成功只执行一次 ==> 将NodePort 端口分配信息更新到 app.Status + logger.Info("[DevStar][DevContainer] NodePort Assigned", "nodePortAssigned", service.Spec.Ports[0].NodePort) + + app.Status.NodePortAssigned = uint16(service.Spec.Ports[0].NodePort) + if err := r.Status().Update(ctx, app); err != nil { + logger.Error(err, "Failed to update NodePort of DevcontainerApp", "nodePortAssigned", service.Spec.Ports[0].NodePort) + return ctrl.Result{}, err + } + } else if !errors.IsAlreadyExists(err) { + logger.Error(err, "Failed to create DevcontainerApp NodePort Service", "nodePortServiceName", service.Name) return ctrl.Result{}, err } } - return ctrl.Result{}, nil } @@ -120,7 +130,7 @@ func (r *DevcontainerAppReconciler) Reconcile(ctx context.Context, req ctrl.Requ func (r *DevcontainerAppReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&devcontainer_v1.DevcontainerApp{}). - Owns(&app_v1.StatefulSet{}). + Owns(&apps_v1.StatefulSet{}). Owns(&core_v1.Service{}). Complete(r) } diff --git a/internal/controller/templates/service.yaml b/internal/controller/templates/service.yaml index 046dabe..973ce89 100644 --- a/internal/controller/templates/service.yaml +++ b/internal/controller/templates/service.yaml @@ -6,6 +6,7 @@ metadata: spec: selector: app: {{.ObjectMeta.Name}} + devstar-resource-type: devstar-devcontainer sessionAffinity: None type: NodePort externalTrafficPolicy: Cluster diff --git a/internal/controller/templates/statefulset.yaml b/internal/controller/templates/statefulset.yaml index f4ee4b1..cd99347 100644 --- a/internal/controller/templates/statefulset.yaml +++ b/internal/controller/templates/statefulset.yaml @@ -5,16 +5,19 @@ metadata: namespace: {{.ObjectMeta.Namespace}} labels: app: {{.ObjectMeta.Name}} + devstar-resource-type: devstar-devcontainer spec: podManagementPolicy: OrderedReady replicas: 1 selector: matchLabels: app: {{.ObjectMeta.Name}} + devstar-resource-type: devstar-devcontainer template: metadata: labels: app: {{.ObjectMeta.Name}} + devstar-resource-type: devstar-devcontainer spec: containers: - name: {{.ObjectMeta.Name}}